import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { normalBook, normalCurrent, saveNormalBook, } from '../../resources/js/lib/irpc-normal.ts'; import { irpcBook, newIrpcRow, saveIrpcBook, recordIrpc, } from '../../resources/js/lib/irpc-withholdings.ts'; import { annualBook, newAnnualBook, newAnnualPpc, saveAnnualBook, reuseAnnualAssessment, annualAssessment, annualWithholdingOptions, reuseAnnualWithholding, calculateAnnual, recordAnnual, annualCurrent, annualReportRows, annualHtml, } from '../../resources/js/lib/irpc-annual-settlement.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const read = (n) => JSON.parse( fs.readFileSync(new URL('./fixtures/' + n, import.meta.url), 'utf8'), ); const val = (v) => (v ? Number(v.numerator) / Number(v.denominator) : null); const now = '2026-10-26T18:00:00+02:00'; const original = () => read('irpc-assessment-preserved.json'); function acceptedL7(expense = false) { const d = read('irpc-l7-preserved.json')[ expense ? 'expense' : 'acceleration' ]; if (!expense) { const f = read('irpc-l7-continuation-preserved.json'); d.business_plan_snapshot = f.plan; d.modelo_a_snapshot = saveNormalBook(d, f.book); } return d; } function setup(rf = '300', ppc = '500') { const d = original(), l5 = irpcBook(d); if (rf !== null) { const row = { ...newIrpcRow('L8-received'), direction: 'received', origin: 'effective', counterparty: 'QA pagador A', documentRef: 'QA rendimento próprio 2026', base: String(Number(rf) * 5), currency: 'MZN', kind: 'royalty', recipientIrpc: 'yes', payerIrpc: 'yes', residence: 'resident', mozambique: 'yes', qualificationRef: 'QA royalties próprios incluídos no resultado anual', specialRelief: 'none', eventsComplete: 'yes', events: [ { kind: 'payment', date: '2026-10-02', reference: 'QA rendimento e primeiro evento 2026', }, ], settlement: 'complete', settlementRef: 'QA retenção efectivamente sofrida e reconciliada', allocations: [{ paymentId: 'RF-L8', amount: rf }], ordinary: { nonDigital: 'yes', capitalType: '', rentOwnPropertyManagement: '', specialFacts: 'no', capitalSeatAndManagement: '', reference: 'QA royalties não digitais de residente', }, }; l5.rows.push(row); l5.payments.push({ id: 'RF-L8', kind: 'withholding_proof', reference: 'QA-RF-2026-1', date: '2026-10-02', amount: rf, currency: 'MZN', }); d.modelo_a_snapshot = saveIrpcBook(d, recordIrpc(d, l5, now)); } let b = reuseAnnualAssessment(d, newAnnualBook()); b.reference = 'QA entidade123456789,exercício2026,declaração integral dos abatimentos'; b.assessmentReference = 'QA colecta válida já demonstrada1408'; b.withholdings = { state: rf === null ? 'absent' : 'known', reference: 'QA inventário completo das retenções efectivamente sofridas por este sujeito no exercício', rows: [], }; b.ppc = { state: ppc === null ? 'absent' : 'known', reference: 'QA inventário completo dos PPC efectuados no exercício', rows: [], }; b.pec = { state: 'absent', amount: '', reference: 'QA ausência de PEC' }; b.credits = { state: 'known', amount: '0', reference: 'QA créditos com regras próprias conhecidos zero', }; if (rf !== null) { b = reuseAnnualWithholding(d, b, 'L8-received', 'RF-L8', 'claim-rf'); Object.assign(b.withholdings.rows[0], { incomeIncluded: 'yes', reference: 'QA próprio beneficiário NUIT123456789;rendimento incluído na base anual2026', }); } if (ppc !== null) b.ppc.rows.push({ ...newAnnualPpc('claim-ppc'), document: 'QA-PPC-2026-1', issuer: 'QA AT', date: '2026-06-30', subjectNuit: b.subjectNuit, year: b.year, proofAmount: ppc, amount: ppc, effective: 'yes', reference: 'QA recibo de PPC efectivo e afectação ao sujeito/exercício', }); return { d, b }; } const model = (d, b) => calculateAnnual(d, b); const pending = (d, b) => { const m = model(d, b); assert.equal(m.status, 'indeterminate', m.pending.join(' | ')); assert.equal(m.arithmeticBalance, null); assert.equal(m.payable, null); assert.equal(m.recoverable, null); return m; }; void test('optional L8 leaves accepted assessment, other books and report rows untouched', () => { const d = original(), before = JSON.stringify(d), b = normalBook(d); assert.equal(normalCurrent(d, b), true); assert.equal(val(annualAssessment(d).colecta), 1408); assert.equal(annualBook(d), undefined); assert.deepEqual(annualReportRows(d), []); assert.equal(JSON.stringify(d), before); const old = acceptedL7(); assert.deepEqual(annualReportRows(old), []); assert.equal( normalBook(old).result.model.version, 'IRPC-normal-adjustments/13', ); }); void test('1408 minus actual received300 and provenPPC500 yields608 payable without consuming official balances', () => { const { d, b } = setup(), before = d.modelo_a_snapshot, m = model(d, b); assert.deepEqual(m.pending, []); assert.equal(m.status, 'payable'); assert.equal(val(m.knownWithholdings), 300); assert.equal(val(m.knownPpc), 500); assert.equal(val(m.payable), 608); assert.equal(val(m.recoverable), 0); assert.equal(m.officialBalancesConsumed, false); assert.equal(m.submitted, false); assert.equal(d.modelo_a_snapshot, before); }); void test('1408 minus1000 and600 yields192 recoverable;408 and1000 balances exactly', () => { for (const [rf, ppc, status, balance] of [ ['1000', '600', 'recoverable', -192], ['408', '1000', 'balanced', 0], ]) { const { d, b } = setup(rf, ppc), m = model(d, b); assert.deepEqual(m.pending, []); assert.equal(m.status, status); assert.equal(val(m.arithmeticBalance), balance); if (typeof balance !== 'number') throw new Error('Invalid balance fixture'); assert.equal(val(m.recoverable), balance < 0 ? -balance : 0); } }); void test('declared absence yields1408;known zero has its own proof and missing never becomes zero', () => { const { d, b } = setup(null, null); assert.equal(val(model(d, b).payable), 1408); b.credits.state = ''; assert.match(pending(d, b).pending.join(' '), /Créditos/); b.credits = { state: 'absent', amount: '', reference: 'QA ausência' }; b.ppc.state = ''; assert.match(pending(d, b).pending.join(' '), /PPC/); const zero = setup('0', '0'); assert.equal(val(model(zero.d, zero.b).payable), 1408); assert.equal(model(zero.d, zero.b).input.withholdings.state, 'known'); }); void test('effective received L5 proof is required, not a projection,remittance or definitive withholding', () => { for (const patch of [ { origin: 'projected' }, { direction: 'paid' }, { residence: 'nonresident', permanentEstablishment: 'no' }, ]) { const { d, b } = setup(), l5 = irpcBook(d); Object.assign( l5.rows.find((r) => r.id === 'L8-received'), patch, ); d.modelo_a_snapshot = saveIrpcBook(d, recordIrpc(d, l5, now)); const option = annualWithholdingOptions(d).find( (o) => o.rowId === 'L8-received', ); assert.equal(option.ready, false); pending(d, b); } const { d, b } = setup(), l5 = irpcBook(d); l5.payments.find((p) => p.id === 'RF-L8').kind = 'remittance'; d.modelo_a_snapshot = saveIrpcBook(d, recordIrpc(d, l5, now)); pending(d, b); }); void test('beneficiary,income inclusion,proof date,entity,exercise and actualPPC are mandatory', () => { for (const change of [ (b) => (b.withholdings.rows[0].incomeIncluded = ''), (b) => (b.withholdings.rows[0].reference = ''), (b) => (b.withholdings.rows[0].subjectNuit = '999999999'), (b) => (b.year = '2025'), (b) => (b.ppc.rows[0].subjectNuit = '999999999'), (b) => (b.ppc.rows[0].year = '2025'), (b) => (b.ppc.rows[0].currency = 'USD'), (b) => (b.ppc.rows[0].date = '2026-02-30'), (b) => (b.ppc.rows[0].date = '2027-01-01'), (b) => (b.ppc.rows[0].effective = 'no'), (b) => (b.ppc.rows[0].reference = ''), (b) => (b.reference = ''), ]) { const { d, b } = setup(); change(b); pending(d, b); } }); void test('selected current source and reusing collection never overwrite deliberate entity/year edits', () => { const { d, b } = setup(); b.subjectNuit = '999999999'; b.year = '2025'; const next = reuseAnnualAssessment(d, b); assert.equal(next.subjectNuit, '999999999'); assert.equal(next.year, '2025'); pending(d, next); const other = setup(); other.b.assessmentKey = 'old-source'; pending(other.d, other.b); }); void test('absence contradiction and incomplete group inventories are indeterminate,not assumed totals', () => { for (const change of [ (b) => { b.withholdings = { state: 'absent', reference: 'QA ausência contraditória', rows: [], }; }, (b) => (b.ppc.rows = []), (b) => (b.ppc.state = 'absent'), (b) => (b.withholdings.reference = ''), ]) { const { d, b } = setup(); change(b); pending(d, b); } }); void test('duplicate pair,duplicatePPC,overclaim and cross-kind physical proof cannot be deducted twice', () => { for (const change of [ (b) => b.withholdings.rows.push({ ...b.withholdings.rows[0], id: 'duplicate', }), (b) => b.ppc.rows.push({ ...b.ppc.rows[0], id: 'duplicate' }), (b) => (b.withholdings.rows[0].amount = '301'), (b) => (b.ppc.rows[0].amount = '501'), (b) => Object.assign(b.ppc.rows[0], { document: ' QA-RF-2026-1 ', issuer: 'QA pagador A', date: '2026-10-02', amount: '100', proofAmount: '300', }), ]) { const { d, b } = setup(); change(b); pending(d, b); } const { d, b } = setup(); assert.throws( () => reuseAnnualWithholding(d, b, 'L8-received', 'RF-L8', 'again'), /já seleccionada/, ); }); void test('partial proof allocations allowed only within its available amount across context maps', () => { const { d, b } = setup(null, '500'); b.ppc.rows[0].amount = '300'; const other = structuredClone(b); other.ppc.rows[0].id = 'other'; other.ppc.rows[0].amount = '200'; const s = JSON.parse(d.modelo_a_snapshot); s.irpcAnnual = { 'opportunity:other': other }; d.modelo_a_snapshot = JSON.stringify(s); assert.equal(val(model(d, b).payable), 1108); other.ppc.rows[0].amount = '201'; d.modelo_a_snapshot = JSON.stringify(s); pending(d, b); other.ppc.rows[0].amount = '100'; other.ppc.rows[0].subjectNuit = '999999999'; d.modelo_a_snapshot = JSON.stringify(s); pending(d, b); other.ppc.rows[0].subjectNuit = b.subjectNuit; other.ppc.rows[0].year = '2025'; d.modelo_a_snapshot = JSON.stringify(s); pending(d, b); }); void test('positive PEC or specialcredit stays separated with null final balances,explicitzero permitted', () => { for (const key of ['pec', 'credits']) { const { d, b } = setup(); b[key] = { state: 'known', amount: '10', reference: 'QA saldo positivo exige regra própria', }; const m = pending(d, b); assert.match(m.pending.join(' '), /fora deste recorte/); assert.equal(val(m.knownPpc), 500); b[key].amount = '0'; assert.equal(model(d, b).status, 'payable'); b[key] = { state: 'absent', amount: '0', reference: 'QA ausência contradiz montante', }; pending(d, b); } }); void test('changing receipt date cannot evade identity checks;copied L5 allocation cannot consume larger proof twice', () => { const p = setup(); p.b.ppc.rows.push({ ...p.b.ppc.rows[0], id: 'other-date', date: '2026-07-01', amount: '100', }); pending(p.d, p.b); const { d, b } = setup(); const l5 = irpcBook(d); l5.payments.find((p) => p.id === 'RF-L8').amount = '1000'; d.modelo_a_snapshot = saveIrpcBook(d, recordIrpc(d, l5, now)); b.withholdings.rows = []; const fresh = reuseAnnualWithholding(d, b, 'L8-received', 'RF-L8', 'rf'); Object.assign(fresh.withholdings.rows[0], { amount: '200', incomeIncluded: 'yes', reference: 'QA próprio beneficiário e rendimento incluído', }); const other = structuredClone(fresh); other.withholdings.rows[0].amount = '101'; other.ppc.rows = []; other.ppc.state = 'absent'; const s = JSON.parse(d.modelo_a_snapshot); s.irpcAnnual = { 'opportunity:other': other }; s.irpcWithholdings['opportunity:other'] = structuredClone(l5); d.modelo_a_snapshot = JSON.stringify(s); d.modelo_a_snapshot = saveIrpcBook(d, recordIrpc(d, irpcBook(d), now)); fresh.withholdings.rows[0].sourceKey = annualWithholdingOptions(d).find( (o) => o.rowId === 'L8-received', ).key; other.withholdings.rows[0].sourceKey = fresh.withholdings.rows[0].sourceKey; const current = JSON.parse(d.modelo_a_snapshot); current.irpcAnnual['opportunity:other'] = other; d.modelo_a_snapshot = JSON.stringify(current); assert.match(pending(d, fresh).pending.join(' '), /Mesma afectação L5/); other.withholdings.rows[0].amount = '100'; d.modelo_a_snapshot = JSON.stringify(current); assert.equal(model(d, fresh).status, 'payable'); }); void test('annual accepted L7 accelerated assessment is reused once rather than summed with L6', () => { const d = read('irpc-l7-preserved.json').acceleration, b = reuseAnnualAssessment(d, newAnnualBook()); b.reference = 'QA entidade/exercício'; b.assessmentReference = 'QA colecta L7'; for (const key of ['withholdings', 'ppc', 'pec', 'credits']) { b[key].state = 'absent'; b[key].reference = 'QA ausência declarada'; } const m = model(d, b); assert.deepEqual(m.pending, []); assert.equal(m.assessment.kind, 'special'); assert.equal(val(m.payable), 1996.8); assert.notEqual( val(m.payable), val(normalBook(d).result.model.colecta) + 1996.8, ); }); void test('100 minimum is applied symmetrically;99.99 kept exact without invented rounding or carry', () => { for (const [ppc, status, balance] of [ ['1308.01', 'below_minimum', 99.99], ['1308', 'payable', 100], ['1507.99', 'below_minimum', -99.99], ['1508', 'recoverable', -100], ]) { const { d, b } = setup(null, ppc), m = model(d, b); assert.equal(m.status, status); assert.equal(val(m.arithmeticBalance), balance); if (status === 'below_minimum') { assert.deepEqual(m.belowMinimum, { numerator: '9999', denominator: '100', }); assert.equal(val(m.payable), 0); assert.equal(val(m.recoverable), 0); } } const { d, b } = setup(); b.ppc.rows[0].amount = '0.001'; pending(d, b); }); void test('existing L7 source cannot be bypassed by choosing L6 and positiveautonomous/shortperiod remain scoped', () => { for (const expense of [false, true]) { const d = acceptedL7(expense); let b = reuseAnnualAssessment(d, newAnnualBook()); b.reference = 'QA fecho'; b.assessmentReference = 'QA colecta'; for (const key of ['withholdings', 'ppc', 'pec', 'credits']) { b[key].state = 'absent'; b[key].reference = 'QA sem movimentos'; } assert.equal(b.assessment, 'special'); let m = pending(d, b); if (!expense) assert.match(m.pending.join(' '), /períodos especiais/); if (expense) assert.match(m.pending.join(' '), /Tributação autónoma/); b.assessment = 'normal'; assert.match(pending(d, b).pending.join(' '), /não corrente/); } }); void test('record/recover/recalculate appends history unchanged,preserves all old books/plan,no double deduction', () => { const { d, b } = setup(), before = JSON.parse(d.modelo_a_snapshot), plan = d.business_plan_snapshot; d.modelo_a_snapshot = saveAnnualBook(d, recordAnnual(d, b, now)); const once = annualBook(d), old = structuredClone(once.result); assert.equal(annualCurrent(d, once), true); d.modelo_a_snapshot = saveAnnualBook(d, recordAnnual(d, once, now)); const back = annualBook(JSON.parse(JSON.stringify(d))); assert.deepEqual(back.history, [old]); assert.equal(val(back.result.model.payable), 608); assert.equal(d.business_plan_snapshot, plan); const snapshot = JSON.parse(d.modelo_a_snapshot); delete snapshot.irpcAnnual; assert.deepEqual(snapshot, before); b.ppc.rows[0].amount = '400'; assert.equal(annualCurrent(d, b), false); }); void test('changed L5 or assessment invalidates current L8 while retaining historical report and references', () => { const { d, b } = setup(); d.modelo_a_snapshot = saveAnnualBook(d, recordAnnual(d, b, now)); const back = annualBook(d), old = structuredClone(back.result); back.reference = 'NEW reference'; d.modelo_a_snapshot = saveAnnualBook(d, back); assert.equal(annualCurrent(d, back), false); assert.match(annualReportRows(d).flat().join(' '), /Histórico/); assert.doesNotMatch(annualReportRows(d).flat().join(' '), /NEW reference/); assert.throws(() => annualHtml(d), /fontes actuais/); assert.deepEqual(back.result, old); const n = normalBook(d); n.base.identityReference += ' changed'; d.modelo_a_snapshot = saveNormalBook(d, n); assert.equal(annualCurrent(d, back), false); pending(d, back); const changed = setup(); changed.d.modelo_a_snapshot = saveAnnualBook( changed.d, recordAnnual(changed.d, changed.b, now), ); const saved = annualBook(changed.d), prior = structuredClone(saved.result); const l5 = irpcBook(changed.d); l5.payments.find((p) => p.id === 'RF-L8').reference += ' corrected'; changed.d.modelo_a_snapshot = saveIrpcBook( changed.d, recordIrpc(changed.d, l5, now), ); assert.equal(annualCurrent(changed.d, saved), false); pending(changed.d, saved); assert.deepEqual(saved.result, prior); }); void test('malformed optionalbook never resets accepted books;report explicitly preserves missing states', () => { const { d, b } = setup(); b.credits.state = ''; d.modelo_a_snapshot = saveAnnualBook(d, recordAnnual(d, b, now)); assert.match(annualHtml(d), /Indeterminado/); assert.match(annualHtml(d), /Informação em falta/); assert.match( JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), }), ), /Saldo anual simulado/, ); const old = d.modelo_a_snapshot; b.ppc.rows.push({ ...b.ppc.rows[0] }); assert.throws(() => saveAnnualBook(d, b), /identificador repetido/); assert.equal(d.modelo_a_snapshot, old); }); void test('prepare only L8 delta cases for guarded API and report recovery', () => { const cases = { payable: setup(), recoverable: setup('1000', '600'), balanced: setup('408', '1000'), absent: setup(null, null), missing: setup(), duplicate: setup(), pec: setup(), }; cases.missing.b.ppc.rows[0].effective = ''; cases.duplicate.b.ppc.rows.push({ ...cases.duplicate.b.ppc.rows[0], id: 'duplicate', }); cases.pec.b.pec = { state: 'known', amount: '10', reference: 'QA PEC separado', }; fs.mkdirSync('outputs/irpc-l8-settlement', { recursive: true }); for (const [name, { d, b }] of Object.entries(cases)) { d.modelo_a_snapshot = saveAnnualBook(d, recordAnnual(d, b, now)); fs.writeFileSync( 'outputs/irpc-l8-settlement/' + name + '.json', JSON.stringify(d), ); fs.writeFileSync( 'outputs/irpc-l8-settlement/' + name + '.html', annualHtml(d), ); } const { d } = setup(); fs.writeFileSync( 'outputs/irpc-l8-settlement/initial.json', JSON.stringify(d), ); });