Valida concorrencia e aplica orcamento com recuperacao verificada

This commit is contained in:
2026-10-28 14:13:00 +02:00
parent c05dc12aea
commit f86ecef44d
12 changed files with 483 additions and 17 deletions
+14
View File
@@ -16,6 +16,20 @@ class Budget extends Model
protected $guarded = ['id'];
protected static function booted(): void
{
static::updating(function (Budget $budget) {
if ($budget->getRawOriginal('approved_by') !== null) {
throw new \LogicException('Uma dotação aprovada não pode ser reescrita.');
}
});
static::deleting(function (Budget $budget) {
if ($budget->approved_by !== null) {
throw new \LogicException('Preservar a dotação aprovada e os seus movimentos.');
}
});
}
protected function casts(): array
{
return ['includes_tax' => 'boolean'];
+6
View File
@@ -6,6 +6,7 @@ use App\Models\Budget;
use App\Models\BudgetEntry;
use App\Models\Requisition;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class BudgetWorkflow
@@ -15,6 +16,11 @@ class BudgetWorkflow
*/
public function record(User $user, Requisition $request, string $kind, int $amount = 0, ?int $subtotal = null): ?array
{
abort_unless(auth()->id() === $user->id && $user->tenant_id !== null && $request->tenant_id === $user->tenant_id, 403);
if (DB::connection()->transactionLevel() === 0) {
throw new \LogicException('Movimentos de orçamento exigem transacção.');
}
app(ConflictGuard::class)->lockCompany($user);
$existing = BudgetEntry::query()->where('requisition_id', $request->id)->orderBy('id')->first();
$budget = $existing
? Budget::query()->lockForUpdate()->findOrFail($existing->budget_id)