fix: complete InvesteMoz validation and error corrections

This commit is contained in:
2026-10-29 21:47:33 +02:00
parent 63147312e2
commit daf8623441
718 changed files with 127308 additions and 20959 deletions
+19 -3
View File
@@ -6,7 +6,9 @@ namespace App\Services;
use App\Models\InvestmentLegalSource;
use App\Models\SimulationTaxRuleVersion;
use App\Support\StructuredData;
use Brick\Math\BigRational;
use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
@@ -14,6 +16,9 @@ use Illuminate\Support\Str;
/** Admission freezes eligibility without granting the public consumer governance write access. */
final class SimulationPublishedFiscal
{
/**
* @return array<array-key, mixed>
*/
public function availability(): array
{
$enabled = (bool) config('simulation-fiscal-consumer.enabled');
@@ -24,6 +29,9 @@ final class SimulationPublishedFiscal
: 'O cálculo de IVA geral sobre base líquida está indisponível para novas execuções. Os históricos mantêm-se acessíveis.'];
}
/**
* @return Builder<SimulationTaxRuleVersion>
*/
private function boundRule(): Builder
{
if (! Str::isUuid((string) config('simulation-fiscal-consumer.rule_id')) || config('simulation-fiscal-consumer.rule_version') < 1) {
@@ -36,6 +44,10 @@ final class SimulationPublishedFiscal
->where('scope_key', 'mz.internal-general-net.mzn');
}
/**
* @param array<array-key, mixed> $input
* @return array<array-key, mixed>
*/
public function admit(array $input, bool $missingBase = false): array
{
if (isset($input['monthly_sales'])) {
@@ -51,7 +63,7 @@ final class SimulationPublishedFiscal
'A versão autorizada de IVA não está disponível para novas execuções. Os históricos foram preservados.');
abort_if($input['reference_date'] < '2026-01-01' || $input['reference_date'] > '2026-12-31', 422,
'Este cálculo abrange apenas exigibilidade em 2026. As entradas foram preservadas.');
abort_if(collect($rule->rule_definition['nodes'] ?? [])->contains(fn (array $node): bool => ($node['op'] ?? null) === 'round'), 422,
abort_if(collect(StructuredData::collectionItems($rule->rule_definition['nodes'] ?? []))->contains(fn (array $node): bool => ($node['op'] ?? null) === 'round'), 422,
'A versão seleccionada não é compatível com o cálculo exacto deste consumidor.');
DB::select('select pg_advisory_xact_lock_shared(261022, hashtext(?))', [(string) $rule->legal_source_id]);
$source = InvestmentLegalSource::whereKey($rule->legal_source_id)->firstOrFail();
@@ -87,6 +99,10 @@ final class SimulationPublishedFiscal
return app(SimulationFiscalSnapshot::class)->build($version, $input, $resolution, $evaluation, $missing, true);
}
/**
* @param array<array-key, mixed> $input
* @return array<array-key, mixed>
*/
private function admitMonthly(array $input): array
{
$rows = [];
@@ -95,7 +111,7 @@ final class SimulationPublishedFiscal
$complete = true;
$previous = null;
foreach ($input['monthly_sales'] as $sale) {
abort_unless($previous === null || $sale['date'] === date('Y-m-d', strtotime($previous.' +1 month')), 422, 'A projecção deve conter meses consecutivos, sem duplicações.');
abort_unless($previous === null || $sale['date'] === CarbonImmutable::parse($previous)->addMonth()->format('Y-m-d'), 422, 'A projecção deve conter meses consecutivos, sem duplicações.');
$previous = $sale['date'];
$known = $sale['amount'] !== null && $sale['amount'] !== '';
$net = $input['sales_vat_basis'] === 'net';
@@ -103,7 +119,7 @@ final class SimulationPublishedFiscal
'currency' => $input['currency'], 'reference_date' => $sale['date'],
'operation' => 'internal_general_net', 'scope_declared' => $input['scope_declared']], ! $known || ! $net);
$snapshot ??= $month;
$rate = collect($month['fiscal_provenance']['resolution'])->firstWhere('parameter_code', 'IVA_GENERAL_RATE');
$rate = collect(StructuredData::collectionItems($month['fiscal_provenance']['resolution']))->firstWhere('parameter_code', 'IVA_GENERAL_RATE');
$vat = $month['result']['value'];
$status = ! $known ? 'missing_sales' : (! $net ? 'unsupported_basis' : ($vat === null ? 'indeterminate' : 'calculated'));
$rows[] = ['date' => $sale['date'], 'sales_declared' => $sale['amount'],