142 lines
5.5 KiB
PHP
142 lines
5.5 KiB
PHP
<?php
|
|
|
|
use App\Domain\Administration\Services\ReservationPolicy;
|
|
use App\Domain\Identity\Enums\RoleName;
|
|
use App\Domain\Identity\Models\Role;
|
|
use App\Domain\Inventory\Models\SnipeAsset;
|
|
use App\Domain\Reservations\Enums\ReservationItemStatus;
|
|
use App\Domain\Reservations\Enums\ReservationStatus;
|
|
use App\Domain\Reservations\Models\Reservation;
|
|
use App\Domain\Reservations\Services\AvailabilityService;
|
|
use App\Domain\Reservations\Services\ReservationService;
|
|
use App\Models\User;
|
|
use Carbon\CarbonImmutable;
|
|
|
|
function policyAdministrator(): User
|
|
{
|
|
$administrator = User::factory()->create();
|
|
$role = Role::firstOrCreate(['name' => RoleName::Administrator->value]);
|
|
$administrator->roles()->attach($role);
|
|
|
|
return $administrator;
|
|
}
|
|
|
|
/** @return array<string, int> */
|
|
function policyValues(array $overrides = []): array
|
|
{
|
|
return array_replace([
|
|
'reservation.min_notice_hours' => 0,
|
|
'reservation.max_duration_hours' => 168,
|
|
'reservation.turnaround_minutes' => 0,
|
|
'reservation.approval_deadline_hours' => 48,
|
|
'reservation.max_assets' => 10,
|
|
], $overrides);
|
|
}
|
|
|
|
it('permite ao administrador alterar políticas com auditoria', function () {
|
|
$administrator = policyAdministrator();
|
|
$values = policyValues([
|
|
'reservation.min_notice_hours' => 24,
|
|
'reservation.turnaround_minutes' => 30,
|
|
]);
|
|
|
|
$this->actingAs($administrator)
|
|
->put('/administracao/regras', $values)
|
|
->assertRedirect()
|
|
->assertSessionHas('success');
|
|
|
|
expect(app(ReservationPolicy::class)->integer('reservation.min_notice_hours'))->toBe(24)
|
|
->and(app(ReservationPolicy::class)->integer('reservation.turnaround_minutes'))->toBe(30);
|
|
$this->assertDatabaseHas('portal_settings', [
|
|
'key' => 'reservation.min_notice_hours',
|
|
'updated_by' => $administrator->id,
|
|
]);
|
|
$this->assertDatabaseHas('audit_logs', ['event' => 'settings.reservation_policy_updated']);
|
|
});
|
|
|
|
it('rejeita períodos fora da antecedência e duração configuradas', function () {
|
|
$administrator = policyAdministrator();
|
|
app(ReservationPolicy::class)->update(policyValues([
|
|
'reservation.min_notice_hours' => 24,
|
|
'reservation.max_duration_hours' => 4,
|
|
]), $administrator);
|
|
$requester = User::factory()->create();
|
|
$asset = SnipeAsset::factory()->create();
|
|
|
|
$this->actingAs($requester)
|
|
->from('/requisicoes/nova')
|
|
->post('/requisicoes', [
|
|
'purpose' => 'Atividade audiovisual com duração demasiado longa.',
|
|
'usage_location' => 'Auditório',
|
|
'starts_at' => now()->addHours(2)->toDateTimeString(),
|
|
'ends_at' => now()->addHours(8)->toDateTimeString(),
|
|
'asset_ids' => [$asset->id],
|
|
'terms_accepted' => true,
|
|
])
|
|
->assertRedirect('/requisicoes/nova')
|
|
->assertSessionHasErrors(['starts_at', 'ends_at']);
|
|
|
|
$this->assertDatabaseCount('reservations', 0);
|
|
});
|
|
|
|
it('aplica margem temporal na consulta e na garantia de conflito', function () {
|
|
$administrator = policyAdministrator();
|
|
app(ReservationPolicy::class)->update(policyValues([
|
|
'reservation.turnaround_minutes' => 60,
|
|
]), $administrator);
|
|
$requester = User::factory()->create();
|
|
$asset = SnipeAsset::factory()->create();
|
|
$reservation = Reservation::create([
|
|
'reference' => 'REQ-POLICY-MARGIN',
|
|
'requester_id' => $requester->id,
|
|
'purpose' => 'Reserva existente para validar a margem.',
|
|
'usage_location' => 'Estúdio',
|
|
'starts_at' => '2026-09-10 09:00:00',
|
|
'ends_at' => '2026-09-10 11:00:00',
|
|
'status' => ReservationStatus::Approved,
|
|
]);
|
|
$reservation->items()->create([
|
|
'snipe_asset_id' => $asset->id,
|
|
'starts_at' => '2026-09-10 09:00:00',
|
|
'ends_at' => '2026-09-10 11:00:00',
|
|
'buffer_starts_at' => '2026-09-10 09:00:00',
|
|
'buffer_ends_at' => '2026-09-10 11:00:00',
|
|
'status' => ReservationItemStatus::Reserved,
|
|
]);
|
|
|
|
$availability = app(AvailabilityService::class);
|
|
expect($availability->isAvailable(
|
|
$asset,
|
|
new DateTimeImmutable('2026-09-10 11:30:00'),
|
|
new DateTimeImmutable('2026-09-10 12:30:00'),
|
|
))->toBeFalse()
|
|
->and($availability->isAvailable(
|
|
$asset,
|
|
new DateTimeImmutable('2026-09-10 12:00:00'),
|
|
new DateTimeImmutable('2026-09-10 13:00:00'),
|
|
))->toBeTrue();
|
|
});
|
|
|
|
it('grava buffers e prazo de aprovação definidos pela política', function () {
|
|
$administrator = policyAdministrator();
|
|
app(ReservationPolicy::class)->update(policyValues([
|
|
'reservation.turnaround_minutes' => 30,
|
|
'reservation.approval_deadline_hours' => 12,
|
|
]), $administrator);
|
|
$startsAt = CarbonImmutable::now()->addDays(5)->setTime(10, 0, 0);
|
|
$endsAt = $startsAt->addHours(2);
|
|
|
|
$reservation = app(ReservationService::class)->createPending(User::factory()->create(), [
|
|
'purpose' => 'Atividade para validar políticas configuráveis.',
|
|
'usage_location' => 'Sala multimédia',
|
|
'starts_at' => $startsAt->toDateTimeString(),
|
|
'ends_at' => $endsAt->toDateTimeString(),
|
|
'asset_ids' => [SnipeAsset::factory()->create()->id],
|
|
]);
|
|
$item = $reservation->items()->firstOrFail();
|
|
|
|
expect($item->buffer_starts_at->equalTo($startsAt->subMinutes(30)))->toBeTrue()
|
|
->and($item->buffer_ends_at->equalTo($endsAt->addMinutes(30)))->toBeTrue()
|
|
->and($reservation->created_at->diffInHours($reservation->approval_deadline))->toBe(12.0);
|
|
});
|