This commit is contained in:
2026-11-02 08:06:45 +02:00
parent e4f520092e
commit 2a4169162b
108 changed files with 3793 additions and 88 deletions
@@ -17,6 +17,7 @@ final class InternalConfirmation
public function show(int $draft, int $actor): ?array
{
$scope = $this->workflow->scope('billing_drafts', $actor, 'view');
abort_unless(\App\Shared\Context\ModuleRecords::query('a_billing_drafts')->where($scope)->where('id',$draft)->exists(),403,'Registo fora do módulo ou do âmbito autorizado.');
$row = DB::table('b_internal_confirmations')->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->where('unit_id', $scope['unit_id'])->where('billing_draft_id', $draft)->first();
if (! $row) { return null; }
$history = DB::table('a_history')->where('area', 'internal_confirmations')->where('record_id', $row->id)->value('id');
@@ -43,7 +44,7 @@ final class InternalConfirmation
abort_unless((int) $old->actor_id === $actor && hash_equals($old->request_hash, $hash), 409, 'Chave repetida com conteúdo ou autor diferente.');
return json_decode($old->result, true, 32, JSON_THROW_ON_ERROR) + ['replayed' => true];
}
$billing = DB::table('a_billing_drafts')->where('id', $draft)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->where('unit_id', $scope['unit_id'])->lockForUpdate()->first();
$billing = \App\Shared\Context\ModuleRecords::query('a_billing_drafts')->where('id', $draft)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->where('unit_id', $scope['unit_id'])->lockForUpdate()->first();
abort_unless($billing, 403, 'Rascunho fora do âmbito autorizado.');
abort_unless((int) $billing->version === $version, 409, 'A versão mudou; reabra o rascunho.');
$existing = DB::table('b_internal_confirmations')->where('billing_draft_id', $draft)->first();
@@ -53,16 +54,16 @@ final class InternalConfirmation
$result = ['id' => $existing->id, 'billing_draft_id' => $draft, 'version' => $version, 'internal_reference' => 'INT-B1-'.$existing->id, 'event_id' => $event];
} else {
$data = json_decode($billing->data, true, 32, JSON_THROW_ON_ERROR);
$source = DB::table('a_service_drafts')->where('id', $billing->source_id)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->where('unit_id', $scope['unit_id'])->first();
$source = \App\Shared\Context\ModuleRecords::query('a_service_drafts')->where('id', $billing->source_id)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->where('unit_id', $scope['unit_id'])->first();
abort_unless($source && (int) $source->version === (int) $data['source_version'], 409, 'A prestação mudou; reveja e actualize explicitamente o rascunho antes de confirmar.');
$client = DB::table('a_clients')->where('id', $billing->client_id)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->first();
$client = \App\Shared\Context\ModuleRecords::query('a_clients')->where('id', $billing->client_id)->where('tenant_id', $scope['tenant_id'])->where('company_id', $scope['company_id'])->first();
abort_unless($client && trim($client->name) !== '' && trim($billing->name) !== '', 422, 'Complete o cliente e a designação do percurso.');
abort_unless((int) $source->client_id === (int) $billing->client_id, 422, 'O cliente diverge da prestação de origem.');
$data['lines'] = DraftValues::lines($data['lines'], $scope);
foreach ($data['lines'] as $line) { abort_if($line['quantity'] === null || $line['unit_price'] === null || trim($line['service_name']) === '', 422, 'Complete quantidade, preço e serviço de todas as linhas.'); }
$pending = DraftValues::pending($data) + ['accounts_pending' => 'Contas e classificação por validar; contabilização bloqueada.', 'recognition_pending' => 'Momento e regras de reconhecimento por validar; contabilização bloqueada.'];
$catalogue = [];
foreach (array_unique(array_column($data['lines'], 'service_id')) as $id) { $service = DB::table('a_services')->where('id', $id)->first(); $catalogue[] = $this->record($service); }
foreach (array_unique(array_column($data['lines'], 'service_id')) as $id) { $service = \App\Shared\Context\ModuleRecords::query('a_services')->where('id', $id)->first(); $catalogue[] = $this->record($service); }
$data['client_name'] = $client->name;
$snapshot = ['label' => self::LABEL, 'scope' => $scope, 'billing_draft' => $this->record($billing), 'service_draft' => $this->record($source),
'client' => $this->record($client), 'services' => $catalogue, 'data' => $data, 'base_amount' => DraftValues::base($data),