Valida concorrencia e aplica orcamento com recuperacao verificada
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Services\ConflictGuard;
|
||||
use App\Services\RequisitionWorkflow;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
require_once __DIR__.'/../Support/ReceiptFixture.php';
|
||||
|
||||
@@ -76,6 +77,13 @@ test('company chooses its own tax basis', function () {
|
||||
expect((int) BudgetEntry::query()->sum('reserved_minor'))->toBe(10000);
|
||||
});
|
||||
|
||||
test('approved company allocation and tax basis cannot be rewritten', function () {
|
||||
$this->budget->update(['approved_by' => $this->approver->id]);
|
||||
expect(fn () => $this->budget->update(['amount_minor' => 999999]))->toThrow(LogicException::class);
|
||||
expect(fn () => $this->budget->refresh()->update(['includes_tax' => false]))->toThrow(LogicException::class);
|
||||
expect(fn () => $this->budget->refresh()->delete())->toThrow(LogicException::class);
|
||||
});
|
||||
|
||||
test('foreign company cannot read or approve allocation', function () {
|
||||
$other = receiptFixture();
|
||||
$user = User::factory()->create(['tenant_id' => $other['tenant']->id, 'purchasing_role' => PurchasingRole::Finance]);
|
||||
@@ -103,3 +111,41 @@ test('failed audit rolls back budget reservation', function () {
|
||||
expect(fn () => budgetRecord($this, 'reserve', 10000))->toThrow(RuntimeException::class);
|
||||
expect(BudgetEntry::query()->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('submission with insufficient approved budget leaves draft and approvals unchanged', function () {
|
||||
$this->budget->update(['approved_by' => $this->approver->id, 'amount_minor' => 9999]);
|
||||
$request = $this->f['r'];
|
||||
$request->update(['status' => 'draft']);
|
||||
$this->actingAs($this->f['issuer']);
|
||||
expect(fn () => app(RequisitionWorkflow::class)->submit($this->f['issuer'], $request))->toThrow(ValidationException::class);
|
||||
expect($request->refresh()->status)->toBe('draft')
|
||||
->and($request->steps()->count())->toBe(0)
|
||||
->and(BudgetEntry::query()->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('submission reserves approved allocation and rejection releases it', function () {
|
||||
$this->budget->update(['approved_by' => $this->approver->id]);
|
||||
$request = $this->f['r'];
|
||||
$request->update(['status' => 'draft']);
|
||||
$this->actingAs($this->f['issuer']);
|
||||
app(RequisitionWorkflow::class)->submit($this->f['issuer'], $request);
|
||||
expect($request->refresh()->status)->toBe('pending')
|
||||
->and((int) BudgetEntry::query()->sum('reserved_minor'))->toBe(10000);
|
||||
$head = User::factory()->create(['tenant_id' => $this->f['tenant']->id, 'department_id' => $this->f['department']->id, 'purchasing_role' => PurchasingRole::DepartmentHead]);
|
||||
$this->actingAs($head);
|
||||
app(RequisitionWorkflow::class)->decide($head, $request, 'rejected', 'Necessidade não confirmada.');
|
||||
expect($request->refresh()->status)->toBe('rejected')
|
||||
->and((int) BudgetEntry::query()->sum('reserved_minor'))->toBe(0);
|
||||
});
|
||||
|
||||
test('budget service refuses a requisition belonging to another company', function () {
|
||||
$other = receiptFixture();
|
||||
$this->actingAs($this->author);
|
||||
try {
|
||||
DB::transaction(fn () => app(BudgetWorkflow::class)->record($this->author, $other['r'], 'reserve', 10000));
|
||||
$this->fail('A foreign requisition must be rejected.');
|
||||
} catch (HttpException $exception) {
|
||||
expect($exception->getStatusCode())->toBe(403);
|
||||
}
|
||||
expect(BudgetEntry::query()->count())->toBe(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user