From dd2b570db5846c94ea00dfb0bb89a7fd9e39b40a Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 23 Feb 2025 14:11:39 +0000 Subject: [PATCH] Added tighter constraints on deleting components Signed-off-by: snipe --- .../Controllers/Api/ComponentsController.php | 8 ++++- .../Components/ComponentsController.php | 4 +++ .../Transformers/ComponentsTransformer.php | 2 +- app/Models/Component.php | 29 +++++++++++++++---- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 0f594f5e7..200951886 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -48,7 +48,8 @@ class ComponentsController extends Controller ]; $components = Component::select('components.*') - ->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer'); + ->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets') + ->withSum('uncontrainedAssets', 'components_assets.assigned_qty'); if ($request->filled('search')) { $components = $components->TextSearch($request->input('search')); @@ -197,6 +198,11 @@ class ComponentsController extends Controller $this->authorize('delete', Component::class); $component = Component::findOrFail($id); $this->authorize('delete', $component); + + if ($component->numCheckedOut() > 0) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.delete.error_qty'))); + } + $component->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.delete.success'))); diff --git a/app/Http/Controllers/Components/ComponentsController.php b/app/Http/Controllers/Components/ComponentsController.php index d5883c05f..74594d312 100644 --- a/app/Http/Controllers/Components/ComponentsController.php +++ b/app/Http/Controllers/Components/ComponentsController.php @@ -196,6 +196,10 @@ class ComponentsController extends Controller } } + if ($component->numCheckedOut() > 0) { + return redirect()->route('components.index')->with('error', trans('admin/components/message.delete.error_qty')); + } + $component->delete(); return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success')); diff --git a/app/Http/Transformers/ComponentsTransformer.php b/app/Http/Transformers/ComponentsTransformer.php index f98edd6e3..90d10ba9a 100644 --- a/app/Http/Transformers/ComponentsTransformer.php +++ b/app/Http/Transformers/ComponentsTransformer.php @@ -62,7 +62,7 @@ class ComponentsTransformer 'checkout' => Gate::allows('checkout', Component::class), 'checkin' => Gate::allows('checkin', Component::class), 'update' => Gate::allows('update', Component::class), - 'delete' => Gate::allows('delete', Component::class), + 'delete' => $component->isDeletable(), ]; $array += $permissions_array; diff --git a/app/Models/Component.php b/app/Models/Component.php index fb77bf082..d9277d7da 100644 --- a/app/Models/Component.php +++ b/app/Models/Component.php @@ -6,6 +6,7 @@ use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Facades\Gate; use Watson\Validating\ValidatingTrait; /** @@ -104,6 +105,13 @@ class Component extends SnipeModel ]; + public function isDeletable() + { + return Gate::allows('delete', $this) + && ($this->numCheckedOut() === 0) + && ($this->deleted_at == ''); + } + /** * Establishes the components -> action logs -> uploads relationship * @@ -234,13 +242,24 @@ class Component extends SnipeModel // In case there are elements checked out to assets that belong to a different company // than this asset and full multiple company support is on we'll remove the global scope, // so they are included in the count. - foreach ($this->assets()->withoutGlobalScope(new CompanyableScope)->get() as $checkout) { - $checkedout += $checkout->pivot->assigned_qty; - } - - return $checkedout; + return $this->uncontrainedAssets->sum('pivot.assigned_qty'); } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + * + * This allows us to get the assets with assigned components without the company restriction + */ + public function uncontrainedAssets() { + + return $this->belongsToMany(\App\Models\Asset::class, 'components_assets') + ->withPivot('id', 'assigned_qty', 'created_at', 'created_by', 'note') + ->withoutGlobalScope(new CompanyableScope); + + } + + /** * Check how many items within a component are remaining *