Implementa recomendação formal com adopção e conferência independente

This commit is contained in:
2026-10-28 20:49:30 +02:00
parent 29cd859385
commit ee17ff7764
33 changed files with 2233 additions and 37 deletions
+6
View File
@@ -39,6 +39,7 @@ class PurchaseWorkflow
$quote = Quotation::query()->where('requisition_id', $requisition->id)->lockForUpdate()->findOrFail($data['quotation_id']);
$result = $this->checkComparison($user, $requisition, $quote);
$admission = app(FormalAdmission::class)->selection($requisition, $quote->id);
$recommendation = app(FormalRecommendation::class)->selection($requisition, $quote->id);
$investment = app(InvestmentWorkflow::class)->check($requisition, $quote);
app(BudgetWorkflow::class)->record($user, $requisition, 'award', $quote->total_minor, $quote->subtotal_minor);
$award = PurchaseAward::query()->create([
@@ -49,6 +50,7 @@ class PurchaseWorkflow
'approval_snapshot' => $rules, 'decision_matrix' => $result['rows'], 'comparison_hash' => $result['fingerprint'],
'investment_snapshot' => $investment,
'admission_snapshot' => $admission,
'recommendation_snapshot' => $recommendation,
]);
$roles = $this->roles($rules, $rules['approval_includes_tax'] ? $quote->total_minor : $quote->subtotal_minor, $requisition->items()->where('purchase_type', 'equipment')->exists());
foreach ($roles as $position => $role) {
@@ -152,6 +154,7 @@ class PurchaseWorkflow
'award' => [...$award->only(['id', 'justification', 'delivery_location']), 'delivery_date' => $deliveryDate],
'issuer' => $user->only(['id', 'name']), 'approval_rules' => $award->approval_snapshot,
'admission' => $award->admission_snapshot,
'recommendation' => $award->recommendation_snapshot,
'estimate_approvals' => $requisition->steps()->get()->toArray(),
'final_approvals' => $award->approvals()->get()->toArray(),
'decision_matrix' => $this->comparison->inspect($requisition)['rows'], 'items' => $lines,
@@ -186,6 +189,9 @@ class PurchaseWorkflow
if (app(FormalAdmission::class)->selection($requisition, $quote->id) !== $award->admission_snapshot) {
throw ValidationException::withMessages(['admission' => 'A base de admissão já não corresponde à adjudicação. Não se emite com outra base.']);
}
if (app(FormalRecommendation::class)->selection($requisition, $quote->id) !== $award->recommendation_snapshot) {
throw ValidationException::withMessages(['recommendation' => 'A recomendação já não corresponde à base da adjudicação. Prepare a revisão autorizada antes de emitir.']);
}
if ($result['fingerprint'] !== $award->comparison_hash || $award->approval_snapshot !== $rules ||
$quote->subtotal_minor !== $award->subtotal_minor || $quote->tax_minor !== $award->tax_minor || $quote->total_minor !== $award->total_minor) {
throw ValidationException::withMessages(['comparison' => 'A base da adjudicação mudou. As aprovações anteriores não autorizam a emissão com dados diferentes.']);