Added tighter constraints on deleting components

Signed-off-by: snipe <snipe@snipe.net>
This commit is contained in:
snipe 2025-02-23 14:11:39 +00:00
parent 2bee4532ec
commit dd2b570db5
4 changed files with 36 additions and 7 deletions

View file

@ -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')));

View file

@ -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'));

View file

@ -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;

View file

@ -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
*