import assert from 'node:assert/strict'; import test from 'node:test'; import { fiscalQaRows } from '../../resources/js/lib/fiscal-qa-preview.ts'; import { exportCompletedArithmeticCsv, readArithmeticSnapshot, } from '../../resources/js/lib/simulation-form.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; function fixture() { const snapshot = { contract_version: 1, scenario_kind: 'fiscal_rule_qa_preview', base: '0.03', currency: 'MZN', indicative_total: '0.0048', legal_interpretation: false, formula_version: 'investmoz.tax.v1', context: { reference_date: '2026-10-21', currency: 'MZN', currency_fraction_digits: 2, scenario_id: '61000100-0000-4000-8000-000000000099', scenario_version: 1, engine_version: 'fiscal-draft-preview-v1', ruleset_version: 'IVA-GERAL-BASE-LIQUIDA:1', }, result: { status: 'calculated', value: '0.0048', unit: 'MZN', explanation: 'Cálculo exacto QA; enquadramento declarado; não é saldo a pagar.', missing_inputs: [], source_ids: ['source-fixture'], }, intermediate: { result: '48/10000' }, fiscal_provenance: { rule: { rule_code: 'IVA-GERAL-BASE-LIQUIDA', rule_version: 1, valid_from: '2023-01-01', valid_until: null, source_sha256: 'a'.repeat(64), source: { diploma: 'Lei 22/2022', article: 'Artigo 17(1)' }, }, }, }; return { id: '61000100-0000-4000-8000-000000000088', status: 'completed', version_no: 2, result_snapshot: snapshot, reports: [ { id: '61000100-0000-4000-8000-000000000077', version_no: 1, status: 'ready', report_snapshot: structuredClone(snapshot), report_sha256: 'b'.repeat(64), }, ], }; } void test('screen rows preserve sub-cent IVA as a string and distinguish calculation from payment', () => { const simulation = fixture(); const before = JSON.stringify(simulation); const rows = fiscalQaRows(simulation.result_snapshot); assert.equal( rows.find(([label]) => label.startsWith('IVA calculado'))[1], '0.0048', ); assert.match( rows.find(([label]) => label === 'Arredondamento')[1], /Não aplicado/, ); assert.match( rows.find(([label]) => label === 'Enquadramento')[1], /não validado juridicamente/, ); assert.equal(JSON.stringify(simulation), before); }); void test('CSV preserves the exact amount and refuses a mismatched immutable report', () => { const simulation = fixture(); const csv = exportCompletedArithmeticCsv( simulation, '2026-10-21T09:00:00Z', ); assert.match(csv, /0\.0048/); assert.doesNotMatch(csv, /Resultado fiscal final,Indeterminado/); simulation.reports[0].report_snapshot.result.value = '0.00'; assert.throws( () => exportCompletedArithmeticCsv(simulation), /relatório preservado/, ); }); void test('dossier report uses the same exact snapshot and preserves genuine indetermination', () => { const simulation = fixture(); function report() { return createProjectDossierReport( { project_title: 'QA fiscal', currency: 'MZN' }, { selectedSections: new Set(['finance']), currentCalculation: { status: 'completed', version: 2, snapshot: simulation.result_snapshot, }, }, ); } const rows = report().sections.find( (section) => section.id === 'finance', ).rows; assert.equal( rows.find((row) => row.field.startsWith('IVA calculado')).value, '0.0048', ); assert.equal( rows.find((row) => row.field === 'Fonte da taxa').value, 'Lei 22/2022 — Artigo 17(1)', ); simulation.result_snapshot.result.status = 'indeterminate'; simulation.result_snapshot.result.value = null; simulation.result_snapshot.indicative_total = null; simulation.result_snapshot.result.missing_inputs = ['eligible_parameter']; assert.equal( report() .sections.find((section) => section.id === 'finance') .rows.find((row) => row.field.startsWith('IVA calculado')).value, 'Indeterminado', ); }); void test('published consumer routes the frozen snapshot through screen CSV and dossier without QA labels', () => { const simulation = fixture(); const snapshot = simulation.result_snapshot; snapshot.scenario_kind = 'fiscal_rule_published'; snapshot.context.engine_version = 'fiscal-published-v1'; snapshot.presentation = { value: snapshot.result.value, rounding_applied: false, }; snapshot.result.explanation = 'IVA pela versão publicada; enquadramento declarado.'; snapshot.fiscal_provenance.rule.status = 'published'; snapshot.fiscal_provenance.scope_status = 'user_declared'; snapshot.fiscal_provenance.mode = 'published_version'; simulation.reports[0].report_snapshot = structuredClone(snapshot); const before = JSON.stringify(simulation); const rows = fiscalQaRows(snapshot); assert.equal(readArithmeticSnapshot(snapshot).integrity, 'versioned'); assert.match(rows[0][1], /publicada/); assert.doesNotMatch(JSON.stringify(rows), /rascunho|não publicada|QA/); const csv = exportCompletedArithmeticCsv( simulation, '2026-10-21T12:00:00Z', ); for (const [label, value] of rows) { assert.ok(csv.includes(label)); assert.ok(csv.includes(value.replaceAll('"', '""'))); } const report = createProjectDossierReport( { project_title: 'Published IVA QA', currency: 'MZN' }, { selectedSections: new Set(['finance']), currentCalculation: { status: 'completed', version: 2, snapshot }, }, ); const finance = report.sections.find((section) => section.id === 'finance'); for (const [field, value] of rows) assert.ok( finance.rows.some( (row) => row.field === field && row.value === value, ), ); assert.doesNotMatch(JSON.stringify(finance), /rascunho|proveniência QA/); assert.equal(JSON.stringify(simulation), before); }); void test('published consumer indeterminate snapshot is valid and a mismatched presentation is refused', () => { const snapshot = fixture().result_snapshot; snapshot.scenario_kind = 'fiscal_rule_published'; snapshot.result.status = 'indeterminate'; snapshot.result.value = null; snapshot.result.missing_inputs = ['operation_scope']; snapshot.indicative_total = null; snapshot.presentation = { value: null, rounding_applied: false }; assert.equal(readArithmeticSnapshot(snapshot).integrity, 'versioned'); snapshot.presentation.value = '0'; assert.equal(readArithmeticSnapshot(snapshot).integrity, 'invalid'); });