$reference, 'requester_id' => $requester->id, 'purpose' => 'Produção audiovisual para uma atividade pedagógica.', 'usage_location' => 'Auditório', 'starts_at' => now()->addDays(3), 'ends_at' => now()->addDays(3)->addHours(2), 'status' => ReservationStatus::PendingApproval, 'approval_deadline' => now()->addDay(), ]); $reservation->items()->create([ 'snipe_asset_id' => $asset->id, 'starts_at' => $reservation->starts_at, 'ends_at' => $reservation->ends_at, 'status' => ReservationItemStatus::Held, ]); return $reservation; } function approverUser(): User { $user = User::factory()->create(); $role = Role::create(['name' => RoleName::Approver->value]); $user->roles()->attach($role); return $user; } it('aprova uma requisição após revalidar disponibilidade', function () { $approver = approverUser(); $reservation = pendingApprovalReservation( User::factory()->create(), SnipeAsset::factory()->create(), 'REQ-APPROVE-001', ); $this->actingAs($approver) ->post("/aprovacoes/{$reservation->uuid}/aprovar", ['comment' => 'Pedido adequado.']) ->assertRedirect() ->assertSessionHas('success'); expect($reservation->fresh()->status)->toBe(ReservationStatus::Approved) ->and($reservation->items()->first()->status)->toBe(ReservationItemStatus::Reserved); $this->assertDatabaseHas('approval_actions', [ 'reservation_id' => $reservation->id, 'actor_id' => $approver->id, 'action' => 'approved', ]); $this->assertDatabaseHas('audit_logs', ['event' => 'reservation.approved']); }); it('rejeita uma requisição e liberta a pré-reserva', function () { $approver = approverUser(); $reservation = pendingApprovalReservation( User::factory()->create(), SnipeAsset::factory()->create(), 'REQ-APPROVE-002', ); $this->actingAs($approver) ->post("/aprovacoes/{$reservation->uuid}/rejeitar", ['comment' => 'O equipamento não pode sair da escola.']) ->assertRedirect(); expect($reservation->fresh()->status)->toBe(ReservationStatus::Rejected) ->and($reservation->items()->first()->status)->toBe(ReservationItemStatus::Cancelled); }); it('regista um pedido de esclarecimentos e renova o prazo', function () { $approver = approverUser(); $reservation = pendingApprovalReservation( User::factory()->create(), SnipeAsset::factory()->create(), 'REQ-APPROVE-003', ); $oldDeadline = $reservation->approval_deadline; $this->actingAs($approver) ->post("/aprovacoes/{$reservation->uuid}/pedir-esclarecimentos", [ 'comment' => 'Indique quem ficará responsável pelo transporte.', ]) ->assertRedirect(); expect($reservation->fresh()->status)->toBe(ReservationStatus::AwaitingInformation) ->and($reservation->fresh()->approval_deadline->isAfter($oldDeadline))->toBeTrue(); $this->assertDatabaseHas('approval_actions', ['action' => 'information_requested']); }); it('impede requisitantes de aceder à área de aprovação', function () { $this->actingAs(User::factory()->create())->get('/aprovacoes')->assertForbidden(); }); it('recusa aprovação se o estado operacional do ativo mudou', function () { $approver = approverUser(); $asset = SnipeAsset::factory()->create(); $reservation = pendingApprovalReservation(User::factory()->create(), $asset, 'REQ-APPROVE-004'); $asset->update(['assigned_id' => 99]); $this->actingAs($approver) ->from('/aprovacoes') ->post("/aprovacoes/{$reservation->uuid}/aprovar") ->assertRedirect('/aprovacoes') ->assertSessionHasErrors('decision'); expect($reservation->fresh()->status)->toBe(ReservationStatus::PendingApproval); });