import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { normalBook, normalCurrent, calculateNormal, recordNormal, saveNormalBook, normalHtml, normalReportRows, } from '../../resources/js/lib/irpc-normal.ts'; import { newNormalAssessmentInput, calculateNormalAssessment, } from '../../resources/js/lib/irpc-normal-assessment.ts'; import { fraction } from '../../resources/js/lib/fiscal-rational.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const seed = () => JSON.parse( fs.readFileSync( new URL('./fixtures/irpc-base-preserved.json', import.meta.url), 'utf8', ), ); const input = () => ({ ...newNormalAssessmentInput(), treatment: 'general_61_1', reference: 'QA sujeito residente,actividade ordinária,sem taxa reduzida/benefício ou tributação autónoma neste recorte', }); const context = () => ({ year: '2026', scope: 'resident_general', currency: 'MZN', }); void test('current base4400 times statutory general32percent yields1408 colecta with explicit2026 period and L8 unknown balance', () => { const d = seed(), b = normalBook(d); b.assessment = input(); const m = calculateNormal(d, b); assert.equal(m.taxableProfit.numerator, '6700'); assert.equal(m.taxableBase.numerator, '4400'); assert.equal(m.colecta.numerator, '1408'); assert.equal(m.tax, null); assert.equal(m.assessment.rate.numerator, '32'); assert.deepEqual(m.assessment.period, { year: '2026', from: '2026-01-01', to: '2026-12-31', }); assert.match(m.assessment.classification, /artigo61\(1\)/); assert.equal(m.assessment.finalBalance.payable, null); assert.equal(m.assessment.finalBalance.recoverable, null); assert.equal(m.assessment.finalBalance.scope, 'L8'); }); void test('missing classification and special cases do not silently inherit32percent;known upstream base remains', () => { for (const patch of [ { treatment: '' }, { treatment: 'other' }, { reference: '' }, ]) { const m = calculateNormalAssessment( { ...input(), ...patch }, fraction(4400n), context(), ); assert.equal(m.colecta, null); assert.equal(m.taxableBase.numerator, '4400'); assert.ok(m.pending.length > 0); if (patch.treatment === 'other') assert.equal(m.rate, null); } }); void test('rate is scoped by period,residence regime and currency,not carried across years or contexts', () => { for (const patch of [ { year: '2025' }, { year: '2027' }, { scope: 'other' }, { currency: 'USD' }, ]) { const m = calculateNormalAssessment(input(), fraction(4400n), { ...context(), ...patch, }); assert.equal(m.colecta, null); if (patch.year) assert.equal(m.rate, null); } }); void test('unknown base is not replaced with6700profit;known zero stays zero and fractional cents remain exact', () => { assert.equal( calculateNormalAssessment(input(), null, context()).colecta, null, ); assert.equal( calculateNormalAssessment(input(), fraction(0n), context()).colecta .numerator, '0', ); const m = calculateNormalAssessment(input(), fraction(1n, 100n), context()); assert.deepEqual(m.colecta, { numerator: '2', denominator: '625' }); assert.equal(m.centExact, false); assert.equal( calculateNormalAssessment(input(), fraction(-1n), context()).colecta, null, ); }); void test('an incomplete base calculation only blocks colecta;profit and valid source amounts remain visible', () => { const d = seed(), b = normalBook(d); b.assessment = input(); b.base.benefits = { state: '', amount: '', reference: '' }; const m = calculateNormal(d, b); assert.equal(m.taxableProfit.numerator, '6700'); assert.equal(m.taxableBase, null); assert.equal(m.colecta, null); assert.equal(m.assessment.rate.numerator, '32'); }); void test('retentions,payments and annual credits are not subtracted or resolved by this L6 scope', () => { const d = seed(), b = normalBook(d); b.assessment = input(); const m = calculateNormal(d, b); d.annual_withholdings = '999999'; d.annual_payments = '999999'; d.annual_credits = '999999'; const s = JSON.parse(d.modelo_a_snapshot); for (const w of Object.values(s.irpcWithholdings ?? {})) { w.payments = []; if (w.mrfta) w.mrfta.codes = []; } d.modelo_a_snapshot = JSON.stringify(s); const changed = calculateNormal(d, b); assert.deepEqual(changed.colecta, m.colecta); assert.deepEqual( changed.assessment.finalBalance, m.assessment.finalBalance, ); assert.equal(changed.tax, null); }); void test('legacy3 remains current without recalculation;version4 roundtrip/history/report/dossier preserve prior books and stale guards', () => { const d = seed(), old = normalBook(d); assert.equal(normalCurrent(d, old), true); assert.equal(old.result.model.version, 'IRPC-normal-adjustments/3'); const originalStore = JSON.parse(d.modelo_a_snapshot); const b = recordNormal( d, { ...old, assessment: input() }, '2026-10-25T23:30:00Z', ); assert.deepEqual(b.history.at(-1), old.result); assert.equal(b.result.model.version, 'IRPC-normal-adjustments/4'); d.modelo_a_snapshot = saveNormalBook(d, b); assert.deepEqual( JSON.parse(d.modelo_a_snapshot).irpcWithholdings, originalStore.irpcWithholdings, ); const back = JSON.parse(JSON.stringify(d)); assert.equal(normalCurrent(back, normalBook(back)), true); const html = normalHtml(back); assert.match(html, /colecta simulada:1408/); assert.match(html, /saldo final a pagar ou recuperar:Indeterminado \(L8\)/); assert.match(html, /taxa:32%/); assert.match( JSON.stringify( createProjectDossierReport(back, { selectedSections: new Set(['finance']), }), ), /1408/, ); assert.match( JSON.stringify(normalReportRows(back)), /Saldo final — âmbito L8/, ); const changed = normalBook(back); changed.assessment.reference = ''; back.modelo_a_snapshot = saveNormalBook(back, changed); assert.equal(normalCurrent(back, normalBook(back)), false); assert.throws(() => normalHtml(back)); const again = recordNormal(back, normalBook(back)); assert.equal(again.result.model.colecta, null); assert.deepEqual(again.history.at(-1), b.result); fs.mkdirSync('outputs/irpc-l6-colecta', { recursive: true }); fs.writeFileSync( 'outputs/irpc-l6-colecta/calculated.json', JSON.stringify(d), ); fs.writeFileSync('outputs/irpc-l6-colecta/preparation.html', normalHtml(d)); const md = structuredClone(d), missing = normalBook(md); missing.assessment.treatment = ''; md.modelo_a_snapshot = saveNormalBook(md, recordNormal(md, missing)); fs.writeFileSync( 'outputs/irpc-l6-colecta/missing.json', JSON.stringify(md), ); }); void test('unsupported input versions and malformed classification fail without replacing originals', () => { const d = seed(), b = normalBook(d); b.assessment = input(); b.assessment.version = 2; assert.throws(() => saveNormalBook(d, b)); b.assessment.version = 1; b.assessment.treatment = 'general20'; assert.throws(() => saveNormalBook(d, b)); });