Files
reservas/tests/Feature/PhaseSixReportingTest.php

121 lines
4.3 KiB
PHP

<?php
use App\Domain\Audit\Models\AuditLog;
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\Models\User;
use Inertia\Testing\AssertableInertia as Assert;
function phaseSixUser(RoleName $role): User
{
$user = User::factory()->create();
$user->roles()->attach(Role::firstOrCreate(['name' => $role->value]));
return $user;
}
function completedReportedReservation(User $requester): Reservation
{
$asset = SnipeAsset::factory()->create([
'asset_tag' => 'REPORT-001',
'name' => 'Câmara de relatório',
'category_name' => 'Fotografia',
]);
$reservation = Reservation::create([
'reference' => 'REQ-REPORT-001',
'requester_id' => $requester->id,
'purpose' => 'Produção de conteúdos para relatório.',
'usage_location' => 'Estúdio',
'starts_at' => now()->subDays(2),
'ends_at' => now()->subDays(2)->addHours(3),
'status' => ReservationStatus::Completed,
]);
$reservation->items()->create([
'snipe_asset_id' => $asset->id,
'starts_at' => $reservation->starts_at,
'ends_at' => $reservation->ends_at,
'buffer_starts_at' => $reservation->starts_at,
'buffer_ends_at' => $reservation->ends_at,
'status' => ReservationItemStatus::Returned,
'delivered_at' => $reservation->starts_at,
'returned_at' => $reservation->ends_at,
]);
return $reservation;
}
it('apresenta o calendário global apenas a perfis autorizados', function () {
$requester = phaseSixUser(RoleName::Requester);
$reservation = completedReportedReservation($requester);
$month = $reservation->starts_at->format('Y-m');
$this->actingAs($requester)->get("/calendario-global?month={$month}")->assertForbidden();
$this->actingAs(phaseSixUser(RoleName::Approver))
->get("/calendario-global?month={$month}")
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('reservations/calendar')
->where('scope', 'global')
->has('reservations', 1)
->where('reservations.0.reference', 'REQ-REPORT-001')
->where('reservations.0.requester.id', $requester->id));
});
it('calcula indicadores e exporta detalhe em CSV', function () {
$requester = User::factory()->create([
'name' => '=HYPERLINK("https://invalid.test")',
'department' => 'Comunicação',
]);
completedReportedReservation($requester);
$auditor = phaseSixUser(RoleName::Auditor);
$query = http_build_query([
'date_from' => now()->subDays(7)->toDateString(),
'date_to' => now()->toDateString(),
]);
$this->actingAs($auditor)
->get("/relatorios?{$query}")
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('reports/index')
->where('summary.total', 1)
->where('summary.completed', 1)
->where('summary.utilizationHours', 3)
->where('byCategory.Fotografia', 1)
->where('byDepartment.Comunicação', 1));
$response = $this->actingAs($auditor)->get("/relatorios/exportar?{$query}");
$response->assertOk()->assertDownload();
expect($response->streamedContent())->toContain(
'REQ-REPORT-001',
'REPORT-001',
'Comunicação',
"'=HYPERLINK",
);
});
it('disponibiliza auditoria imutável a auditores e administradores', function () {
$actor = User::factory()->create();
AuditLog::create([
'actor_id' => $actor->id,
'event' => 'reservation.test_audit',
'metadata' => ['reference' => 'REQ-AUDIT-001'],
]);
$this->actingAs(User::factory()->create())->get('/auditoria')->assertForbidden();
$this->actingAs(phaseSixUser(RoleName::Auditor))
->get('/auditoria?event=test_audit')
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('audit/index')
->has('logs.data', 1)
->where('logs.data.0.event', 'reservation.test_audit')
->where('logs.data.0.actor.name', $actor->name));
});