commit14
This commit is contained in:
@@ -19,7 +19,28 @@ class InvoiceWorkflow
|
||||
{
|
||||
private function access(User $user): void
|
||||
{
|
||||
abort_unless(auth()->id() === $user->id && $user->tenant_id !== null && $user->hasFunctions([PurchasingRole::Finance]), 403);
|
||||
abort_unless(auth()->id() === $user->id && $user->tenant_id !== null && $user->hasFunctions([PurchasingRole::Finance]) && ! app(OrganizationAccess::class)->maintenanceOnly($user), 403);
|
||||
}
|
||||
|
||||
private function reviewerBaseEligible(User $user, Invoice $invoice): bool
|
||||
{
|
||||
return $user->tenant_id === $invoice->tenant_id && $invoice->created_by !== $user->id
|
||||
&& $user->hasFunctions([PurchasingRole::Finance]) && ! app(OrganizationAccess::class)->maintenanceOnly($user);
|
||||
}
|
||||
|
||||
/** Pending intervention, not a promise of a matching invoice or budget availability. */
|
||||
public function reviewerEligible(User $user, Invoice $invoice): bool
|
||||
{
|
||||
if ($invoice->status !== 'pending' || ! $this->reviewerBaseEligible($user, $invoice)) {
|
||||
return false;
|
||||
}
|
||||
$order = PurchaseOrder::query()->whereKey($invoice->purchase_order_id)->first();
|
||||
if ($order === null) {
|
||||
return false;
|
||||
}
|
||||
$request = Requisition::query()->visibleTo($user)->whereKey($order->requisition_id)->first();
|
||||
|
||||
return $request !== null && ! app(ConflictGuard::class)->processBlocked($request, $order->supplier_id, $user);
|
||||
}
|
||||
|
||||
private function invalid(string $message): never
|
||||
@@ -49,7 +70,10 @@ class InvoiceWorkflow
|
||||
if ($quantity <= 0 || (int) $previous + $quantity > (int) $accepted || (int) $previous + $quantity > ReceiptWorkflow::milli($source->quantity)) {
|
||||
$this->invalid('Quantidade superior à recepção aceite ainda não facturada. Serviços também exigem aceitação.');
|
||||
}
|
||||
if (BigDecimal::of((string) $input['unit_price'])->multipliedBy(100)->compareTo($source->unit_price_minor) !== 0 || BigDecimal::of((string) $input['tax_rate'])->compareTo((string) $source->tax_rate) !== 0 || trim((string) $input['unit']) !== $source->unit) {
|
||||
$unit = array_key_exists('unit', $input) ? $input['unit'] : $source->unit;
|
||||
$unitPrice = array_key_exists('unit_price', $input) ? $input['unit_price'] : (string) BigDecimal::of($source->unit_price_minor)->dividedBy(100, 2);
|
||||
$taxRate = array_key_exists('tax_rate', $input) ? $input['tax_rate'] : $source->tax_rate;
|
||||
if (BigDecimal::of((string) $unitPrice)->multipliedBy(100)->compareTo($source->unit_price_minor) !== 0 || BigDecimal::of((string) $taxRate)->compareTo((string) $source->tax_rate) !== 0 || trim((string) $unit) !== $source->unit) {
|
||||
$this->invalid('Preço, unidade e IVA devem coincidir exactamente com a ordem. Não há tolerância ou excepção configurada.');
|
||||
}
|
||||
// Cumulative rounding ensures partial invoices sum exactly to the frozen order.
|
||||
@@ -75,6 +99,7 @@ class InvoiceWorkflow
|
||||
return DB::transaction(function () use ($user, $order, $data) {
|
||||
app(ConflictGuard::class)->lockCompany($user);
|
||||
$user = app(CurrentActor::class)->lock($user, [PurchasingRole::Finance]);
|
||||
$this->access($user);
|
||||
$order = PurchaseOrder::query()->lockForUpdate()->findOrFail($order->id);
|
||||
$request = Requisition::query()->findOrFail($order->requisition_id);
|
||||
app(ConflictGuard::class)->assertProcess($request, $order->supplier_id, $user);
|
||||
@@ -104,10 +129,11 @@ class InvoiceWorkflow
|
||||
public function validate(User $user, Invoice $invoice): void
|
||||
{
|
||||
$this->access($user);
|
||||
abort_unless($invoice->tenant_id === $user->tenant_id && $invoice->created_by !== $user->id, 403);
|
||||
abort_unless($this->reviewerBaseEligible($user, $invoice), 403);
|
||||
DB::transaction(function () use ($user, $invoice) {
|
||||
app(ConflictGuard::class)->lockCompany($user);
|
||||
$user = app(CurrentActor::class)->lock($user, [PurchasingRole::Finance]);
|
||||
$this->access($user);
|
||||
$invoice = Invoice::query()->lockForUpdate()->findOrFail($invoice->id);
|
||||
if ($invoice->status === 'validated') {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user