feat: protect production Snipe-IT operations

This commit is contained in:
2026-08-05 12:37:12 +01:00
parent 26330b75f7
commit 8c69331118
13 changed files with 289 additions and 26 deletions

View File

@@ -144,7 +144,7 @@ final class HandoverService
$this->authorizeOperator($operator);
$this->assertOperationalConfiguration();
$reservation = Reservation::query()->with('items.asset')->findOrFail($reservation->id);
$reservation = Reservation::query()->with(['requester', 'items.asset'])->findOrFail($reservation->id);
if (! in_array($reservation->status, [
ReservationStatus::Delivered,
ReservationStatus::InUse,
@@ -166,10 +166,23 @@ final class HandoverService
if ($asset->status_id === null) {
throw ValidationException::withMessages(['operation' => "O equipamento {$asset->asset_tag} não tem estado Snipe-IT sincronizado."]);
}
if ($reservation->requester->snipe_user_id === null) {
throw ValidationException::withMessages(['operation' => 'O destinatário não tem associação Snipe-IT confirmada.']);
}
$hasPortalCheckout = $item->handoverRecords()
->where('type', HandoverType::Checkout->value)
->where('recipient_id', $reservation->requester_id)
->exists();
if (! $hasPortalCheckout) {
throw ValidationException::withMessages([
'operation' => "O equipamento {$asset->asset_tag} não tem um checkout confirmado pelo portal; o check-in foi bloqueado.",
]);
}
$response = $this->snipeIt->checkinHardware(
(int) $asset->snipe_asset_id,
(int) $asset->status_id,
(int) $reservation->requester->snipe_user_id,
$asset->location_id === null ? null : (int) $asset->location_id,
$this->externalNote($reservation, $notes),
);