diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index 4e4793dcfa..6c8716e54e 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -8,6 +8,7 @@ use App\Helpers\Helper; use App\Models\Accessory; use App\Http\Transformers\AccessoriesTransformer; use App\Models\Company; +use App\Http\Transformers\SelectlistTransformer; class AccessoriesController extends Controller @@ -201,4 +202,30 @@ class AccessoriesController extends Controller return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.delete.success'))); } + + /** + * Gets a paginated collection for the select2 menus + * + * @author [A. Gianotto] [] + * @since [v4.0.16] + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $accessories = Accessory::select([ + 'accessories.id', + 'accessories.name' + ]); + + if ($request->filled('search')) { + $accessories = $accessories->where('accessories.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $accessories = $accessories->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($accessories); + } } diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 85b5201729..a97f92771c 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -8,6 +8,7 @@ use App\Models\Company; use App\Models\Consumable; use App\Http\Transformers\ConsumablesTransformer; use App\Helpers\Helper; +use App\Http\Transformers\SelectlistTransformer; class ConsumablesController extends Controller { @@ -187,4 +188,30 @@ class ConsumablesController extends Controller $data = array('total' => $consumableCount, 'rows' => $rows); return $data; } + + /** + * Gets a paginated collection for the select2 menus + * + * @author [A. Gianotto] [] + * @since [v4.0.16] + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $consumables = Consumable::select([ + 'consumables.id', + 'consumables.name' + ]); + + if ($request->filled('search')) { + $consumables = $consumables->where('consumables.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $consumables = $consumables->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($consumables); + } } diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index 5df6c52d3e..9defee8cd6 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -11,6 +11,7 @@ use App\Models\License; use App\Models\LicenseSeat; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +use App\Http\Transformers\SelectlistTransformer; class LicensesController extends Controller { @@ -244,5 +245,32 @@ class LicensesController extends Controller } + + /** + * Gets a paginated collection for the select2 menus + * + * @author [A. Gianotto] [] + * @since [v4.0.16] + * @see \App\Http\Transformers\SelectlistTransformer + * + */ + public function selectlist(Request $request) + { + + $licenses = License::select([ + 'licenses.id', + 'licenses.name' + ]); + + if ($request->filled('search')) { + $licenses = $licenses->where('licenses.name', 'LIKE', '%'.$request->get('search').'%'); + } + + $licenses = $licenses->orderBy('name', 'ASC')->paginate(50); + + + return (new SelectlistTransformer)->transformSelectlist($licenses); + } + } diff --git a/app/Http/Controllers/Api/PredefinedKitsController.php b/app/Http/Controllers/Api/PredefinedKitsController.php index e72966ec82..70d5c17a7c 100644 --- a/app/Http/Controllers/Api/PredefinedKitsController.php +++ b/app/Http/Controllers/Api/PredefinedKitsController.php @@ -113,6 +113,12 @@ class PredefinedKitsController extends Controller $this->authorize('delete', PredefinedKit::class); $kit = PredefinedKit::findOrFail($id); + // Delete childs + $kit->models()->detach(); + $kit->licenses()->detach(); + $kit->consumables()->detach(); + $kit->accessories()->detach(); + $kit->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, 'Delete was successfull')); // TODO: trans @@ -178,8 +184,14 @@ class PredefinedKitsController extends Controller if( $quantity < 1) { $quantity = 1; } - $kit->licenses()->attach( $request->get('license'), ['quantity' => $quantity]); - + + $license_id = $request->get('license'); + $relation = $kit->licenses(); + if( $relation->find($license_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['license' => 'License already attached to kit'])); + } + + $relation->attach( $license_id, ['quantity' => $quantity]); return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License added successfull')); // TODO: trans } @@ -200,7 +212,7 @@ class PredefinedKitsController extends Controller if( $quantity < 1) { $quantity = 1; } - $kit->licenses()->sync([$license_id => ['quantity' => $quantity]]); + $kit->licenses()->syncWithoutDetaching([$license_id => ['quantity' => $quantity]]); return response()->json(Helper::formatStandardApiResponse('success', $kit, 'License updated')); // TODO: trans } @@ -258,10 +270,10 @@ class PredefinedKitsController extends Controller if( $quantity < 1) { $quantity = 1; } - //echo $request->get('model'); + $relation = $kit->models(); if( $relation->find($model_id) ) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'Model already exists')); + return response()->json(Helper::formatStandardApiResponse('error', null, ['model' => 'Model already attached to kit'])); } $relation->attach($model_id, ['quantity' => $quantity]); @@ -306,4 +318,173 @@ class PredefinedKitsController extends Controller $kit->models()->detach($model_id); return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans } + + + + /** + * Display the specified resource. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $id + * @return \Illuminate\Http\Response + */ + public function indexConsumables($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $consumables = $kit->consumables; + return (new PredefinedKitsTransformer)->transformElements($consumables, $consumables->count()); + } + + + /** + * Display the specified resource. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $id + * @return \Illuminate\Http\Response + */ + public function storeConsumable(Request $request, $kit_id) + { + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $consumable_id = $request->get('consumable'); + $relation = $kit->consumables(); + if( $relation->find($consumable_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['consumable' => 'Consumable already attached to kit'])); + } + + $relation->attach( $consumable_id, ['quantity' => $quantity]); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable added successfull')); // TODO: trans + } + + /** + * Update the specified resource in storage. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function updateConsumable(Request $request, $kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->consumables()->syncWithoutDetaching([$consumable_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Consumable updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachConsumable($kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + + $kit->consumables()->detach($consumable_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans + } + + + /** + * Display the specified resource. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $id + * @return \Illuminate\Http\Response + */ + public function indexAccessories($kit_id) { + $this->authorize('view', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($kit_id); + $accessories = $kit->accessories; + return (new PredefinedKitsTransformer)->transformElements($accessories, $accessories->count()); + } + + + /** + * Display the specified resource. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $id + * @return \Illuminate\Http\Response + */ + public function storeAccessory(Request $request, $kit_id) + { + $this->authorize('update', PredefinedKit::class); + + $kit = PredefinedKit::findOrFail($kit_id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + + $accessory_id = $request->get('accessory'); + $relation = $kit->accessories(); + if( $relation->find($accessory_id) ) { + return response()->json(Helper::formatStandardApiResponse('error', null, ['accessory' => 'Accessory already attached to kit'])); + } + + $relation->attach( $accessory_id, ['quantity' => $quantity]); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory added successfull')); // TODO: trans + } + + /** + * Update the specified resource in storage. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function updateAccessory(Request $request, $kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + $quantity = $request->input('quantity', 1); + if( $quantity < 1) { + $quantity = 1; + } + $kit->accessories()->syncWithoutDetaching([$accessory_id => ['quantity' => $quantity]]); + + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Accessory updated')); // TODO: trans + } + + /** + * Remove the specified resource from storage. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @param int $kit_id + * @return \Illuminate\Http\Response + */ + public function detachAccessory($kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + $kit = PredefinedKit::findOrFail($id); + + $kit->accessories()->detach($accessory_id); + return response()->json(Helper::formatStandardApiResponse('success', $kit, 'Delete was successfull')); // TODO: trans + } } diff --git a/app/Http/Controllers/Kits/CheckoutKitController.php b/app/Http/Controllers/Kits/CheckoutKitController.php index 260826d6c0..36f0b6bda3 100644 --- a/app/Http/Controllers/Kits/CheckoutKitController.php +++ b/app/Http/Controllers/Kits/CheckoutKitController.php @@ -13,7 +13,7 @@ use App\Models\Accessory; use App\Models\SnipeItPivot; use Illuminate\Http\Request; use App\Http\Controllers\CheckInOutRequest; -use App\Services\PredefinedKitService; +use App\Services\PredefinedKitCheckoutService; use App\Models\User; @@ -32,7 +32,7 @@ class CheckoutKitController extends Controller use CheckInOutRequest; - public function __construct(PredefinedKitService $kitService) + public function __construct(PredefinedKitCheckoutService $kitService) { $this->kitService = $kitService; } @@ -70,9 +70,9 @@ class CheckoutKitController extends Controller $errors = $this->kitService->checkout($request, $kit, $user); if( count($errors) > 0 ) { - return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error'))->with('error_messages', $errors); + return redirect()->back()->with('error', 'Checkout error')->with('error_messages', $errors); // TODO: trans } - return redirect()->back()->with('success', trans('admin/hardware/message.checkout.success')); + return redirect()->back()->with('success', 'Checkout was successfully'); // TODO: trans } } diff --git a/app/Http/Controllers/Kits/PredefinedKitsController.php b/app/Http/Controllers/Kits/PredefinedKitsController.php index b13ef7d27a..d71d99a602 100644 --- a/app/Http/Controllers/Kits/PredefinedKitsController.php +++ b/app/Http/Controllers/Kits/PredefinedKitsController.php @@ -155,6 +155,8 @@ class PredefinedKitsController extends Controller // Delete childs $kit->models()->detach(); $kit->licenses()->detach(); + $kit->consumables()->detach(); + $kit->accessories()->detach(); // Delete the kit $kit->delete(); @@ -246,7 +248,7 @@ class PredefinedKitsController extends Controller } /** - * Get the kit information to present to the kit view page + * Remove the model from set * * @author [A. Gianotto] [] * @since [v1.0] @@ -267,6 +269,246 @@ class PredefinedKitsController extends Controller return redirect()->route('kits.edit', $kit_id)->with('success', 'Model was successfully detached'); // TODO: trans } + /** + * Returns a view containing attached license edit form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $licenseId + * @return View + */ + public function editLicense($kit_id, $license_id) + { + $this->authorize('update', PredefinedKit::class); + if( !($kit = PredefinedKit::find($kit_id)) ) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if( !($license = $kit->licenses()->find($license_id)) ) { + return redirect()->route('kits.index')->with('error', 'License does not exist'); // TODO: trans + } + + return view('kits/license-edit', [ + 'kit' => $kit, + 'license' => $license, + 'item' => $license->pivot + ]); + } + + /** + * Update attached licese + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $licenseId + * @return View + */ + public function updateLicense(Request $request, $kit_id, $license_id) { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeLicenseRules($license_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->licenses()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->license_id = $request->input('license_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'License updated successfully.'); // TODO: trans + } + + /** + * + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $licenseId + * @return View + */ + public function detachLicense($kit_id, $license_id) { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->licenses()->detach($license_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'License was successfully detached'); // TODO: trans + } + + + /** + * Returns a view containing attached accessory edit form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $accessoryId + * @return View + */ + public function editAccessory($kit_id, $accessory_id) + { + $this->authorize('update', PredefinedKit::class); + if( !($kit = PredefinedKit::find($kit_id)) ) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if( !($accessory = $kit->accessories()->find($accessory_id)) ) { + return redirect()->route('kits.index')->with('error', 'Accessory does not exist'); // TODO: trans + } + + return view('kits/accessory-edit', [ + 'kit' => $kit, + 'accessory' => $accessory, + 'item' => $accessory->pivot + ]); + } + + /** + * Update attached accessory + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $accessoryId + * @return View + */ + public function updateAccessory(Request $request, $kit_id, $accessory_id) { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeAccessoryRules($accessory_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->accessories()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->accessory_id = $request->input('accessory_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'Accessory updated successfully.'); // TODO: trans + } + + /** + * + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $accessoryId + * @return View + */ + public function detachAccessory($kit_id, $accessory_id) { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->accessories()->detach($accessory_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'Accessory was successfully detached'); // TODO: trans + } + + /** + * Returns a view containing attached consumable edit form. + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $consumableId + * @return View + */ + public function editConsumable($kit_id, $consumable_id) + { + $this->authorize('update', PredefinedKit::class); + if( !($kit = PredefinedKit::find($kit_id)) ) { + return redirect()->route('kits.index')->with('error', 'Kit does not exist'); // TODO: trans + } + if( !($consumable = $kit->consumables()->find($consumable_id)) ) { + return redirect()->route('kits.index')->with('error', 'Consumable does not exist'); // TODO: trans + } + + return view('kits/consumable-edit', [ + 'kit' => $kit, + 'consumable' => $consumable, + 'item' => $consumable->pivot + ]); + } + + /** + * Update attached consumable + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $kit_id + * @param int $consumableId + * @return View + */ + public function updateConsumable(Request $request, $kit_id, $consumable_id) { + + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + $validator = \Validator::make($request->all(), $kit->makeConsumableRules($consumable_id)); + + if ($validator->fails()) { + return redirect()->back()->withInput()->withErrors($validator); + } + + $pivot = $kit->consumables()->wherePivot('id', $request->input('pivot_id'))->first()->pivot; + + $pivot->consumable_id = $request->input('consumable_id'); + $pivot->quantity = $request->input('quantity'); + $pivot->save(); + + return redirect()->route('kits.edit', $kit_id)->with('success', 'Consumable updated successfully.'); // TODO: trans + } + + /** + * + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @param int $consumableId + * @return View + */ + public function detachConsumable($kit_id, $consumable_id) { + $this->authorize('update', PredefinedKit::class); + if (is_null($kit = PredefinedKit::find($kit_id))) { + // Redirect to the kits management page + return redirect()->route('kits.index')->with('error','Kit does not exist'); // TODO: trans + } + + // Delete childs + $kit->consumables()->detach($consumable_id); + + // Redirect to the kit management page + return redirect()->route('kits.edit', $kit_id)->with('success', 'Consumable was successfully detached'); // TODO: trans + } /** * Returns true if a fieldset is set, 'add default values' is ticked and if @@ -283,7 +525,7 @@ class PredefinedKitsController extends Controller } /** - * Adds default values to a model (as long as they are truthy) + * Adds default values to a accessory (as long as they are truthy) * * @param AssetModel $model * @param array $defaultValues diff --git a/app/Http/Controllers/ModalController.php b/app/Http/Controllers/ModalController.php index 791d342a8f..168a46e5bb 100644 --- a/app/Http/Controllers/ModalController.php +++ b/app/Http/Controllers/ModalController.php @@ -43,4 +43,12 @@ class ModalController extends Controller function kitLicense() { return view('modals.kit-license'); } + + function kitConsumable() { + return view('modals.kit-consumable'); + } + + function kitAccessory() { + return view('modals.kit-accessory'); + } } diff --git a/app/Models/PredefinedKit.php b/app/Models/PredefinedKit.php index ea6f478fa9..9044945ecb 100644 --- a/app/Models/PredefinedKit.php +++ b/app/Models/PredefinedKit.php @@ -44,24 +44,62 @@ class PredefinedKit extends SnipeModel 'pivot_id' => 'integer|exists:kits_models,id' ]; - public function makeModelRules($model_id) { - return [ - // 'model_id' => 'required|exists:models,id', - 'model_id' => [ - 'required', - 'exists:models,id', - Rule::unique('kits_models')->whereNot('model_id', $model_id)->where('kit_id', $this->id) - ], - 'quantity' => 'required|integer|min:1', - 'pivot_id' => 'integer|exists:kits_models,id' - ]; + public function makeModelRules($model_id, $new = false) { + // return [ + // // 'model_id' => 'required|exists:models,id', + // 'model_id' => [ + // 'required', + // 'exists:models,id', + // Rule::unique('kits_models')->whereNot('model_id', $model_id)->where('kit_id', $this->id) + // ], + // 'quantity' => 'required|integer|min:1', + // 'pivot_id' => 'integer|exists:kits_models,id' + // ]; + return $this->_makeRuleHelper('licenses', 'kits_licenses', 'license_id', $license_id, $new); } - public $licenseRules = [ - 'license_id' => 'required|exists:licenses,id', - 'quantity' => 'required|integer|min:1', - 'pivot_id' => 'integer|exists:kits_licenses,id' - ]; + public function makeLicenseRules($license_id, $new = false) { + return $this->_makeRuleHelper('licenses', 'kits_licenses', 'license_id', $license_id, $new); + } + + public function makeAccessoriesRules($accessoriy_id, $new = false) { + return $this->_makeRuleHelper('accessories', 'kits_accessories', 'accessoriy_id', $accessoriy_id, $new); + } + + public function makeConsumablesRules($consumable_id, $new = false) { + return $this->_makeRuleHelper('consumables', 'kits_consumables', 'consumable_id', $consumable_id, $new); + } + + protected function _makeRuleHelper($table, $pivot_table, $pivot_elem_key, $element_id, $new) { + // return [ + // $pivot_elem_key => [ + // 'required', + // "exists:$table,id", + // Rule::unique($pivot_table)->whereNot($pivot_elem_key, $element_id)->where('kit_id', $this->id) + // ], + // 'quantity' => 'required|integer|min:1', + // 'pivot_id' => "integer|exists:$pivot_table,id" + // ]; + $rule = [ + $pivot_elem_key => [ + 'required', + "exists:$table,id", + Rule::unique($pivot_table)->whereNot($pivot_elem_key, $element_id)->where('kit_id', $this->id) + ], + 'quantity' => 'required|integer|min:1' + ]; + if(!$new) { + $rule['pivot_id'] = "integer|exists:$pivot_table,id"; + + } + return $rule; + } + + // public $licenseRules = [ + // 'license_id' => 'required|exists:licenses,id', + // 'quantity' => 'required|integer|min:1', + // 'pivot_id' => 'integer|exists:kits_licenses,id' + // ]; /** @@ -119,6 +157,29 @@ class PredefinedKit extends SnipeModel return $this->belongsToMany('\App\Models\License', 'kits_licenses', 'kit_id', 'license_id')->withPivot('id', 'quantity'); } + /** + * Establishes the kits -> licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function consumables() + { + return $this->belongsToMany('\App\Models\Consumable', 'kits_consumables', 'kit_id', 'consumable_id')->withPivot('id', 'quantity'); + } + + /** + * Establishes the kits -> licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function accessories() + { + return $this->belongsToMany('\App\Models\Accessory', 'kits_accessories', 'kit_id', 'accessory_id')->withPivot('id', 'quantity'); + } /** * ----------------------------------------------- diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 4e17c798c2..02bf3dc072 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -64,7 +64,6 @@ class RouteServiceProvider extends ServiceProvider require base_path('routes/web/components.php'); require base_path('routes/web/users.php'); require base_path('routes/web/kits.php'); - //require base_path('routes/web/dbtest.php'); require base_path('routes/web.php'); }); } diff --git a/app/Services/PredefinedKitCheckoutService.php b/app/Services/PredefinedKitCheckoutService.php new file mode 100644 index 0000000000..decdb1db1c --- /dev/null +++ b/app/Services/PredefinedKitCheckoutService.php @@ -0,0 +1,174 @@ +getAssetsToAdd($kit, $user, $errors); + $license_seats_to_add = $this->getLicenseSeatsToAdd($kit, $user, $errors); + $consumables_to_add = $this->getConsumablesToAdd($kit, $user, $errors); + $accessories_to_add = $this->getAccessoriesToAdd($kit, $user, $errors); + + if( count($errors) > 0 ) { + return $errors; + } + + $checkout_at = date("Y-m-d H:i:s"); + if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) { + $checkout_at = $request->get('checkout_at'); + } + + $expected_checkin = ''; + if ($request->filled('expected_checkin')) { + $expected_checkin = $request->get('expected_checkin'); + } + + $admin = Auth::user(); + + $note = e($request->get('note')); + + $errors = DB::transaction( + function () use ($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $license_seats_to_add, $consumables_to_add, $accessories_to_add, $note) { + // assets + foreach ($assets_to_add as $asset) { + $asset->location_id = $user->location_id; + $error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, $note, null); + if ($error) { + array_merge_recursive($errors, $asset->getErrors()->toArray()); + } + } + // licenses + foreach ($license_seats_to_add as $licenseSeat) { + $licenseSeat->user_id = $admin->id; + $licenseSeat->assigned_to = $user->id; + if ($licenseSeat->save()) { + event(new CheckoutableCheckedOut($licenseSeat, $user, $admin, $note)); + } + else { + $errors []= 'Something went wrong saving a license seat'; + } + } + // consumables + foreach($consumables_to_add as $consumable) { + $consumable->assigned_to = $user->id; + $consumable->users()->attach($consumable->id, [ + 'consumable_id' => $consumable->id, + 'user_id' => $admin->id, + 'assigned_to' => $user->id + ]); + event(new CheckoutableCheckedOut($consumable, $user, $admin, $note)); + } + //accessories + foreach($accessories_to_add as $accessory) { + $accessory->assigned_to = $user->id; + $accessory->users()->attach($accessory->id, [ + 'accessory_id' => $accessory->id, + 'user_id' => $admin->id, + 'assigned_to' => $user->id + ]); + event(new CheckoutableCheckedOut($accessory, $user, $admin, $note)); + } + return $errors; + }); + + return $errors; + + } catch (ModelNotFoundException $e) { + return [$e->getMessage()]; + } catch (CheckoutNotAllowed $e) { + return [$e->getMessage()]; + } + } + + protected function getAssetsToAdd($kit, $user, &$errors) { + $models = $kit->models() + ->with( ['assets' => function($hasMany) { $hasMany->RTD(); }] ) + ->get(); + $assets_to_add = []; + foreach($models as $model) { + $assets = $model->assets; + $quantity = $model->pivot->quantity; + foreach($assets as $asset) { + + if ($asset->availableForCheckout() + && !$asset->is($user)) { + + $this->authorize('checkout', $asset); + $quantity -= 1; + $assets_to_add []= $asset; + if($quantity <= 0) { + break; + } + } + } + if($quantity > 0) { + $errors []= "Don't have available assets for model " . $model->name . '. Need ' . $model->pivot->quantity . ' assets.'; // TODO: trans + } + } + + return $assets_to_add; + } + + protected function getLicenseSeatsToAdd($kit, $user, &$errors) { + $seats_to_add = []; + $licenses = $kit->licenses() + ->with('freeSeats') + ->get(); + foreach($licenses as $license) { + $quantity = $license->pivot->quantity; + if( $quantity > count($license->freeSeats) ) { + $errors []= "Don't have free seats for license " . $license->name . '. Need ' . $quantity . ' seats.'; // TODO: trans + } + for($i=0; $i < $quantity; $i++) { + $seats_to_add []= $license->freeSeats[$i]; + } + } + return $seats_to_add; + } + + protected function getConsumablesToAdd($kit, $user, &$errors) { + // $consumables = $kit->consumables()->withCount('consumableAssignments as consumable_assignments_count')->get(); + $consumables = $kit->consumables()->with('users')->get(); + foreach($consumables as $consumable) { + if( $consumable->numRemaining() < $consumable->pivot->quantity ) { + $errors []= "Don't have available consumable " . $consumable->name . '. Need ' . $consumable->pivot->quantity; // TODO: trans + } + } + return $consumables; + } + + protected function getAccessoriesToAdd($kit, $user, &$errors) { + $accessories = $kit->accessories()->with('users')->get(); + foreach($accessories as $accossory) { + if( $accossory->numRemaining() < $accossory->pivot->quantity ) { + $errors []= "Don't have available accossory " . $accossory->name . '. Need ' . $accossory->pivot->quantity; // TODO: trans + } + } + return $accessories; + } +} diff --git a/app/Services/PredefinedKitService.php b/app/Services/PredefinedKitService.php deleted file mode 100644 index d07f826107..0000000000 --- a/app/Services/PredefinedKitService.php +++ /dev/null @@ -1,99 +0,0 @@ -models() - ->with( ['assets' => function($hasMany) { $hasMany->RTD(); }] ) - ->get(); - //$licenses = $kit->licenses()->with(['assets' => function($hasMany) { $hasMany->RTD(); }])->get(); - - // Check if the user exists - if (is_null($user) ) { - return [trans('admin/users/message.user_not_found')]; - } - - $assets_to_add = []; - $errors = []; - foreach($models as $model) { - $assets = $model->assets; - $quantity = $model->pivot->quantity; - foreach($assets as $asset) { - - if ($asset->availableForCheckout() - && !$asset->is($user)) { - - $this->authorize('checkout', $asset); - $quantity -= 1; - $assets_to_add []= $asset; - if($quantity <= 0) { - break; - } - } - } - if($quantity > 0) { - $errors []= "Don't have available assets for model " . $model->name . '. Need ' . $model->pivot->quantity . ' assets.'; // TODO: trans - } - } - - if( count($errors) > 0 ) { - return $errors; - } - - $checkout_at = date("Y-m-d H:i:s"); - if (($request->filled('checkout_at')) && ($request->get('checkout_at')!= date("Y-m-d"))) { - $checkout_at = $request->get('checkout_at'); - } - - $expected_checkin = ''; - if ($request->filled('expected_checkin')) { - $expected_checkin = $request->get('expected_checkin'); - } - - $admin = Auth::user(); - - $note = e($request->get('note')); - - $errors = DB::transaction(function () use ($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $note) { - - foreach ($assets_to_add as $asset) { - - $asset->location_id = $user->location_id; - - $error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, $note, null); - - if ($error) { - array_merge_recursive($errors, $asset->getErrors()->toArray()); - } - } - return $errors; - }); - - return $errors; - - } catch (ModelNotFoundException $e) { - return [$e->getMessage()]; - } catch (CheckoutNotAllowed $e) { - return [$e->getMessage()]; - } - } - -} diff --git a/database/migrations/2018_10_19_154013_add_kits_models_table.php b/database/migrations/2018_10_19_154013_add_kits_models_table.php index 6f80df2da6..a0abeeef7b 100644 --- a/database/migrations/2018_10_19_154013_add_kits_models_table.php +++ b/database/migrations/2018_10_19_154013_add_kits_models_table.php @@ -20,8 +20,6 @@ class AddKitsModelsTable extends Migration { $table->integer('quantity')->default(1); $table->timestamps(); }); - - } /** diff --git a/database/migrations/2019_02_07_185953_add_kits_consumables_table.php b/database/migrations/2019_02_07_185953_add_kits_consumables_table.php new file mode 100644 index 0000000000..b6d14e4285 --- /dev/null +++ b/database/migrations/2019_02_07_185953_add_kits_consumables_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('consumable_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_consumables'); + } +} diff --git a/database/migrations/2019_02_07_190030_add_kits_accessories_table.php b/database/migrations/2019_02_07_190030_add_kits_accessories_table.php new file mode 100644 index 0000000000..f0e80249db --- /dev/null +++ b/database/migrations/2019_02_07_190030_add_kits_accessories_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->integer('kit_id')->nullable()->default(NULL); + $table->integer('accessory_id')->nullable()->default(NULL); + $table->integer('quantity')->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + Schema::drop('kits_accessories'); + } +} diff --git a/resources/views/kits/accessory-edit.blade.php b/resources/views/kits/accessory-edit.blade.php new file mode 100644 index 0000000000..807cd7fa76 --- /dev/null +++ b/resources/views/kits/accessory-edit.blade.php @@ -0,0 +1,58 @@ +@extends('layouts/edit-form', [ + 'createText' => 'Append accessory', // TODO: trans + 'updateText' => 'Update appended accessory', // TODO: trans + 'formAction' => ($item) ? route('kits.accessories.update', ['kit_id' => $kit->id, 'accessory_id' => $item->accessory_id]) : route('kits.accessories.store', ['kit_id' => $kit->id]), +]) + +{{-- Page content --}} +@section('inputFields') +{{--
+ +
+ + @if ($accessory_id = Input::old('accessory_id', (isset($item)) ? $item->accessory_id : '')) + + @else + + @endif + + +
+
+ @can('create', \App\Accessories\Accessory::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + New + + @endif + @endcan +
+ + {!! $errors->first('accessory_id', '
:message
') !!} +
--}} +
+ +
+
+ +
+ {!! $errors->first('quantity', ' :message') !!} +
+
+ + +{{-- --}} + +@stop diff --git a/resources/views/kits/consumable-edit.blade.php b/resources/views/kits/consumable-edit.blade.php new file mode 100644 index 0000000000..857850e8b7 --- /dev/null +++ b/resources/views/kits/consumable-edit.blade.php @@ -0,0 +1,58 @@ +@extends('layouts/edit-form', [ + 'createText' => 'Append consumable', // TODO: trans + 'updateText' => 'Update appended consumable', // TODO: trans + 'formAction' => ($item) ? route('kits.consumables.update', ['kit_id' => $kit->id, 'consumable_id' => $item->consumable_id]) : route('kits.consumables.store', ['kit_id' => $kit->id]), +]) + +{{-- Page content --}} +@section('inputFields') +{{--
+ +
+ + @if ($consumable_id = Input::old('consumable_id', (isset($item)) ? $item->consumable_id : '')) + + @else + + @endif + + +
+
+ @can('create', \App\Consumables\Consumable::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + New + + @endif + @endcan +
+ + {!! $errors->first('consumable_id', '
:message
') !!} +
--}} +
+ +
+
+ +
+ {!! $errors->first('quantity', ' :message') !!} +
+
+ + +{{-- --}} + +@stop diff --git a/resources/views/kits/edit.blade.php b/resources/views/kits/edit.blade.php index db16d9dd79..7d26142d02 100644 --- a/resources/views/kits/edit.blade.php +++ b/resources/views/kits/edit.blade.php @@ -80,6 +80,74 @@ +{{-- Consumables --}} +
+
+
+
+

Consumables{{-- TODO: trans --}}

+
+ +
+
+
+{{-- Accessories --}} +
+
+
+
+

Accessories{{-- TODO: trans --}}

+
+ +
+
+
@stop @section('moar_scripts') diff --git a/resources/views/kits/license-edit.blade.php b/resources/views/kits/license-edit.blade.php new file mode 100644 index 0000000000..5a5e6858dc --- /dev/null +++ b/resources/views/kits/license-edit.blade.php @@ -0,0 +1,58 @@ +@extends('layouts/edit-form', [ + 'createText' => 'Append license', // TODO: trans + 'updateText' => 'Update appended license', // TODO: trans + 'formAction' => ($item) ? route('kits.licenses.update', ['kit_id' => $kit->id, 'license_id' => $item->license_id]) : route('kits.licenses.store', ['kit_id' => $kit->id]), +]) + +{{-- Page content --}} +@section('inputFields') +{{--
+ +
+ + @if ($license_id = Input::old('license_id', (isset($item)) ? $item->license_id : '')) + + @else + + @endif + + +
+
+ @can('create', \App\Licenses\License::class) + @if ((!isset($hide_new)) || ($hide_new!='true')) + New + + @endif + @endcan +
+ + {!! $errors->first('license_id', '
:message
') !!} +
--}} +
+ +
+
+ +
+ {!! $errors->first('quantity', ' :message') !!} +
+
+ + +{{-- --}} + +@stop diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 169033ed73..74bde6cf86 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -662,6 +662,13 @@ @endcan + + + + + Predefined kits{{-- TODO: trans --}} + + diff --git a/resources/views/partials/forms/edit/accessory-select.blade.php b/resources/views/partials/forms/edit/accessory-select.blade.php new file mode 100644 index 0000000000..d8c919c0fd --- /dev/null +++ b/resources/views/partials/forms/edit/accessory-select.blade.php @@ -0,0 +1,20 @@ + +
+ {{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }} +
+ +
+ {!! $errors->first($fieldname, '
:message
') !!} + +
diff --git a/resources/views/partials/forms/edit/consumable-select.blade.php b/resources/views/partials/forms/edit/consumable-select.blade.php new file mode 100644 index 0000000000..82fb54f537 --- /dev/null +++ b/resources/views/partials/forms/edit/consumable-select.blade.php @@ -0,0 +1,20 @@ + +
+ {{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }} +
+ +
+ {!! $errors->first($fieldname, '
:message
') !!} + +
diff --git a/resources/views/partials/forms/edit/license-select.blade.php b/resources/views/partials/forms/edit/license-select.blade.php new file mode 100644 index 0000000000..ecb07e0740 --- /dev/null +++ b/resources/views/partials/forms/edit/license-select.blade.php @@ -0,0 +1,20 @@ + +
+ {{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }} +
+ +
+ {!! $errors->first($fieldname, '
:message
') !!} + +
diff --git a/routes/api.php b/routes/api.php index ab038aa812..1178e62f0c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -33,7 +33,23 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { }); - /*--- Accessories API ---*/ + /*--- Accessories API ---*/ + Route::group(['prefix' => 'accessories'], function () { + + Route::get('{accessory}/checkedout', + [ + 'as' => 'api.accessories.checkedout', + 'uses' => 'AccessoriesController@checkedout' + ] + ); + + Route::get('selectlist', + [ + 'as' => 'api.accessories.selectlist', + 'uses'=> 'AccessoriesController@selectlist' + ] + ); + }); // Accessories group Route::resource('accessories', 'AccessoriesController', ['names' => [ @@ -48,15 +64,7 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { ] ); // Accessories resource - Route::group(['prefix' => 'accessories'], function () { - Route::get('{accessory}/checkedout', - [ - 'as' => 'api.accessories.checkedout', - 'uses' => 'AccessoriesController@checkedout' - ] - ); - }); // Accessories group /*--- Categories API ---*/ @@ -174,7 +182,12 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { /*--- Consumables API ---*/ - + Route::get('consumables/selectlist', + [ + 'as' => 'api.consumables.selectlist', + 'uses'=> 'ConsumablesController@selectlist' + ] + ); Route::resource('consumables', 'ConsumablesController', [ 'names' => @@ -414,6 +427,14 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { 'as' => 'api.license.seats', 'uses' => 'LicensesController@seats' ]); + + Route::get('selectlist', + [ + 'as' => 'api.licenses.selectlist', + 'uses'=> 'LicensesController@selectlist' + ] + ); + }); // Licenses group Route::resource('licenses', 'LicensesController', diff --git a/routes/web.php b/routes/web.php index 827088ed8c..7ecc4b1fe8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -89,6 +89,8 @@ Route::group(['middleware' => 'auth','prefix' => 'modals'], function () { Route::get('user',['as' => 'modal.user','uses' => 'ModalController@user']); Route::get('kit-model',['as' => 'modal.kit.model','uses' => 'ModalController@kitModel']); Route::get('kit-license',['as' => 'modal.kit.license','uses' => 'ModalController@kitLicense']); + Route::get('kit-consumable',['as' => 'modal.kit.consumable','uses' => 'ModalController@kitConsumable']); + Route::get('kit-accessory',['as' => 'modal.kit.accessory','uses' => 'ModalController@kitAccessory']); }); /* diff --git a/routes/web/kits.php b/routes/web/kits.php index ca1ff534ab..50712aba43 100644 --- a/routes/web/kits.php +++ b/routes/web/kits.php @@ -48,13 +48,6 @@ Route::group([ 'prefix' => 'kits/{kit_id}', 'middleware' => ['auth'] ], function // Models - - Route::post('models', - [ - 'as' => 'kits.models.store', - 'uses' => 'Kits\PredefinedKitsController@storeModel', - ] - ); Route::put('models/{model_id}', [ @@ -81,14 +74,6 @@ Route::group([ 'prefix' => 'kits/{kit_id}', 'middleware' => ['auth'] ], function // Consumables - - Route::post('consumables', - [ - 'as' => 'kits.consumables.store', - 'uses' => 'Kits\PredefinedKitsController@storeConsumable', - ] - ); - Route::put('consumables/{consumable_id}', [ 'as' => 'kits.consumables.update', @@ -114,14 +99,6 @@ Route::group([ 'prefix' => 'kits/{kit_id}', 'middleware' => ['auth'] ], function // Accessories - - Route::post('accessories', - [ - 'as' => 'kits.accessories.store', - 'uses' => 'Kits\PredefinedKitsController@storeAccessory', - ] - ); - Route::put('accessories/{accessory_id}', [ 'as' => 'kits.accessories.update',