Files
compras/tests/Feature/PurchaseProcessTest.php
T

69 lines
4.1 KiB
PHP

<?php
use App\Enums\PurchasingRole;
use App\Models\AuditLog;
use App\Models\Department;
use App\Models\Tenant;
use App\Models\User;
use App\Services\InvoiceWorkflow;
use Inertia\Testing\AssertableInertia as Assert;
require_once __DIR__.'/../Support/InvoiceFixture.php';
test('process overview links records without declaring partial execution complete', function () {
$f = invoiceFixture();
$this->actingAs($f['author'])->get('/requisicoes/'.$f['r']->id.'/processo')
->assertOk()->assertHeader('Cache-Control', 'max-age=0, no-store, private')
->assertInertia(fn (Assert $page) => $page->component('purchases/process')
->where('process.number', $f['r']->number)
->where('stages.5.state', 'issued')
->where('stages.6.state', 'recorded')
->where('stages.7.state', 'recorded')
->where('stages.7.detail', '1 registadas; 0 validadas. O registo não equivale a validação.')
->where('stages.8.state', 'not_started')
->has('future', 2)
->where('documents', fn ($documents) => collect($documents)->contains('label', $f['invoice']->number)));
});
test('requester process view conceals purchase and finance details', function () {
$f = invoiceFixture();
$f['issuer']->forceFill(['purchasing_role' => PurchasingRole::Requester])->save();
$this->actingAs($f['issuer'])->get('/requisicoes/'.$f['r']->id.'/processo')->assertOk()
->assertInertia(fn (Assert $page) => $page->component('purchases/process')
->where('stages.2.state', 'restricted')->where('stages.3.state', 'restricted')
->where('stages.4.state', 'restricted')->where('stages.5.state', 'restricted')
->where('stages.7.state', 'restricted')->has('documents', 1)
->where('history', fn ($history) => collect($history)->every(fn ($event) => ! str_starts_with($event['action'], 'invoice.') && ! str_starts_with($event['action'], 'budget.')))
->missing('invoices')->missing('payments')->missing('bank_snapshot'));
});
test('process view does not expand request ownership or department access', function () {
$f = invoiceFixture();
$this->actingAs($f['receiver'])->get('/requisicoes/'.$f['r']->id.'/processo')->assertNotFound();
$department = Department::query()->create(['tenant_id' => $f['tenant']->id, 'name' => 'Outro departamento']);
$head = User::factory()->create(['tenant_id' => $f['tenant']->id, 'department_id' => $department->id, 'purchasing_role' => PurchasingRole::DepartmentHead]);
$this->actingAs($head)->get('/requisicoes/'.$f['r']->id.'/processo')->assertNotFound();
$head->forceFill(['department_id' => $f['r']->department_id])->save();
$this->actingAs($head)->get('/requisicoes/'.$f['r']->id.'/processo')->assertOk()
->assertInertia(fn (Assert $page) => $page->where('stages.3.state', 'recorded')->where('stages.7.state', 'restricted')->where('documents', fn ($documents) => ! collect($documents)->contains('kind', 'Factura')));
});
test('process view is protected across companies and for guests', function () {
$f = invoiceFixture();
$otherCompany = Tenant::query()->create(['name' => 'Outra empresa fictícia']);
$this->actingAs(User::factory()->create(['tenant_id' => $otherCompany->id, 'purchasing_role' => PurchasingRole::Admin]))->get('/requisicoes/'.$f['r']->id.'/processo')->assertNotFound();
auth()->logout();
$this->get('/requisicoes/'.$f['r']->id.'/processo')->assertRedirect('/login');
});
test('process overview reads current invoice state and never exposes audit snapshots', function () {
$f = invoiceFixture();
$this->actingAs($f['validator']);
app(InvoiceWorkflow::class)->validate($f['validator'], $f['invoice']);
$before = AuditLog::query()->count();
$this->get('/requisicoes/'.$f['r']->id.'/processo')->assertOk()
->assertInertia(fn (Assert $page) => $page->where('stages.7.detail', '1 registadas; 1 validadas. O registo não equivale a validação.')
->where('history', fn ($history) => collect($history)->every(fn ($event) => array_keys($event) === ['id', 'action', 'created_at'])));
expect(AuditLog::query()->count())->toBe($before);
});