Preserve shared budget adapter and limited technical acceptance
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\PurchasingRole;
|
||||
use App\Models\Requisition;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tempo\Finance\Budget\BudgetContext;
|
||||
use Tempo\Finance\Budget\BudgetControl;
|
||||
use Tempo\Finance\Budget\BudgetFailure;
|
||||
|
||||
/** Local host adapter: auth, tenant lock and audit; no budget arithmetic. */
|
||||
final class CommonBudget
|
||||
{
|
||||
public function for(User $user): BudgetControl
|
||||
{
|
||||
abort_unless(auth()->id() === $user->id && $user->tenant_id !== null, 403);
|
||||
abort_unless(DB::table('tenants')->where('id', $user->tenant_id)->value('currency') === 'MZN', 422, 'Controlo comum desta entrega suporta apenas MZN; câmbio permanece pendente.');
|
||||
$context = new BudgetContext($user->id, ['tenant_id' => (int) $user->tenant_id], (int) now()->year, 'MZN');
|
||||
|
||||
return new BudgetControl(DB::connection(), $context, '',
|
||||
function (string $action) use ($user): void {
|
||||
app(ConflictGuard::class)->lockCompany($user);
|
||||
abort_unless(DB::table('tenants')->where('id', $user->tenant_id)->value('currency') === 'MZN', 422, 'Moeda da organização incompatível com esta entrega.');
|
||||
$roles = in_array($action, ['create', 'approve', 'reinforcement.propose', 'reinforcement.review', 'view'], true)
|
||||
? [PurchasingRole::Admin, PurchasingRole::Finance]
|
||||
: ($action === 'consume' ? [PurchasingRole::Finance] : null);
|
||||
app(CurrentActor::class)->lock($user, $roles);
|
||||
},
|
||||
function (string $action, array $data, ?int $origin) use ($user): void {
|
||||
// InvoiceWorkflow retains invoice.validated in the enclosing transaction.
|
||||
if ($action !== 'budget.consumed') {
|
||||
$request = $origin ? Requisition::query()->findOrFail($origin) : null;
|
||||
app(RequisitionWorkflow::class)->audit($user, $action, $request, null, $data);
|
||||
}
|
||||
},
|
||||
fn (int $id): bool => User::query()->where('tenant_id', $user->tenant_id)->whereKey($id)->lockForUpdate()->whereIn('purchasing_role', [PurchasingRole::Admin->value, PurchasingRole::Finance->value])->exists(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*
|
||||
* @param callable(): T $command
|
||||
* @return T
|
||||
*/
|
||||
public function execute(callable $command): mixed
|
||||
{
|
||||
try {
|
||||
return $command();
|
||||
} catch (BudgetFailure $e) {
|
||||
abort_if($e->status !== 422, $e->status, $e->getMessage());
|
||||
throw ValidationException::withMessages([$e->field => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user