Files
compras/tests/Feature/SupplierPayableIntegrationTest.php
2026-11-03 11:51:44 +02:00

90 lines
5.3 KiB
PHP

<?php
use App\Models\User;
use App\Services\ExternalPaymentWorkflow;
use App\Services\SupplierPayables;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Tempo\Finance\Payables\PayablesSchema;
require_once __DIR__.'/../Support/PaymentFixture.php';
beforeEach(function () {
$this->f = paymentFixture();
config(['common-payables.enabled' => true, 'common-payables.source_instance' => 'integration-fixture-instance']);
foreach ([$this->f['author'], $this->f['validator']] as $user) {
foreach (['view', 'prepare', 'validate'] as $action) {
DB::table('pa_access')->insert(['tenant_id' => $user->tenant_id, 'company_id' => 0, 'unit_id' => 0,
'user_id' => $user->id, 'person' => 'fixture-person-'.$user->id, 'action' => $action]);
}
}
$this->actingAs($this->f['author']);
});
test('explicit activation recognises a confirmed invoice once on the normal application schema', function () {
expect(SupplierPayables::enabled())->toBeTrue();
$service = app(SupplierPayables::class);
$prepared = $service->engine($this->f['author'])->command('prepare', $this->f['invoice']->id, 'Conferência de integração sintética', (string) Str::uuid());
expect($prepared['state'])->toBe('prepared');
$this->actingAs($this->f['validator']);
$recognised = $service->engine($this->f['validator'])->command('validate', $prepared['proposal_id'], 'Validação independente de teste', (string) Str::uuid());
expect($recognised['state'])->toBe('recognised');
$service->engine($this->f['validator'])->command('validate', $prepared['proposal_id'], 'Validação repetida de teste', (string) Str::uuid());
expect(DB::table('pa_obligations')->count())->toBe(1)
->and(DB::table('pa_obligations')->value('principal_minor'))->toBe(6000)
->and(DB::table('pa_obligations')->value('due_on'))->toBeNull()
->and(app(ExternalPaymentWorkflow::class)->outstanding($this->f['invoice']))->toBe(6000);
$this->getJson('/api/supplier-payables?invoice='.$this->f['invoice']->id)->assertOk()->assertJsonCount(1, 'obligations');
config(['common-payables.source_instance' => 'different-installation']);
expect(fn () => $service->principal($this->f['invoice']))->toThrow(HttpException::class);
});
test('legacy payments keep their balance and prevent automatic import of a second debt', function () {
$payments = app(ExternalPaymentWorkflow::class);
$payment = $payments->register($this->f['author'], $this->f['invoice'], $this->f['payment_data']);
$this->actingAs($this->f['validator']);
$payments->review($this->f['validator'], $payment, 'confirmed', 'Conferência sintética do histórico');
expect($payments->outstanding($this->f['invoice']))->toBe(2000);
$this->actingAs($this->f['author']);
$prepared = app(SupplierPayables::class)->engine($this->f['author'])->command('prepare', $this->f['invoice']->id, 'Tentativa com pagamento anterior', (string) Str::uuid());
expect($prepared['state'])->toBe('pending_source');
$this->actingAs($this->f['validator']);
$result = app(SupplierPayables::class)->engine($this->f['validator'])->command('validate', $prepared['proposal_id'], 'Rever histórico sem nova dívida', (string) Str::uuid());
expect($result['state'])->toBe('conflict')->and(DB::table('pa_obligations')->count())->toBe(0)
->and($payments->outstanding($this->f['invoice']))->toBe(2000);
});
test('activation does not grant permissions and source queries remain tenant scoped', function () {
DB::table('pa_access')->where('user_id', $this->f['author']->id)->delete();
$this->getJson('/api/supplier-payables')->assertForbidden();
$foreign = User::factory()->create(['tenant_id' => null]);
$this->actingAs($foreign);
expect(fn () => app(SupplierPayables::class)->principal($this->f['invoice']))->toThrow(HttpException::class);
config(['common-payables.enabled' => false]);
// Owned PostgreSQL QA fixtures have an explicit environment override; normal
// installations still require the configured activation flag.
$environment = app()->environment();
app()->detectEnvironment(fn () => 'local');
try {
expect(SupplierPayables::enabled())->toBeFalse();
} finally {
app()->detectEnvironment(fn () => $environment);
}
});
test('the shared schema preserves histories and refuses repeated or partial installation', function () {
expect(fn () => PayablesSchema::install())->toThrow(LogicException::class);
$service = app(SupplierPayables::class);
$service->engine($this->f['author'])->command('prepare', $this->f['invoice']->id, 'Criar histórico imutável de teste', (string) Str::uuid());
expect(fn () => DB::table('pa_events')->delete())->toThrow(QueryException::class);
});
test('navigation exposes the workspace only while the current actor has explicit view access', function () {
$this->get('/dashboard')->assertOk()->assertInertia(fn ($page) => $page->where('payablesAvailable', true));
DB::table('pa_access')->where('user_id', $this->f['author']->id)->where('action', 'view')->delete();
$this->get('/dashboard')->assertOk()->assertInertia(fn ($page) => $page->where('payablesAvailable', false));
$this->get('/obrigacoes-fornecedores')->assertForbidden();
});