import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { normalBook, normalFinancialSource, recordNormal, calculateNormal, normalCurrent, saveNormalBook, normalHtml, normalReportRows, } from '../../resources/js/lib/irpc-normal.ts'; import { newNormalProfitInput, profitTopics, } from '../../resources/js/lib/irpc-normal-profit.ts'; import { restoreBusinessPlanSnapshot, serializeBusinessPlanSnapshot, } from '../../resources/js/lib/business-financial-plan.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; import { irpcBook, saveIrpcBook, } from '../../resources/js/lib/irpc-withholdings.ts'; const seed = () => JSON.parse( fs.readFileSync( new URL('./fixtures/irpc-normal-preserved.json', import.meta.url), 'utf8', ), ); function example() { const d = seed(), b = normalBook(d), profit = newNormalProfitInput(); b.rows[1].amount = '120'; b.rows[1].reference = 'QA todos120MZN de juros reconhecidos são compensatórios documentados;nenhuma taxa L5 calculada'; profit.completenessReference = 'QA plano cobre sujeito residente/exercício2026 completo,sem outros estabelecimentos,receitas,custos ou operações omitidos'; profit.lines = normalFinancialSource(d).accountingLines.map((l) => ({ code: l.code, state: l.code === 'depreciation' ? 'absent' : 'known', reference: 'QA qualificação ordinária/exercício/reconciliação de ' + l.origin + ';restante custo indispensável sem outras exclusões', })); for (const [k] of profitTopics) profit.topics[k] = { state: 'absent', amount: '', reference: 'QA ausência verificada de ' + k, }; profit.topics.incomeCorrections = { state: 'known', amount: '0', reference: 'QA revisão de correcções ao rendimento:valor conhecido zero', }; b.profit = profit; return { d, b }; } void test('documented financial result plus supported addbacks reaches scoped simulated taxable profit without tax/base', () => { const { d, b } = example(), m = calculateNormal(d, b); assert.equal(m.accountingProfit.numerator, '6480'); assert.equal(m.additions.numerator, '220'); assert.equal(m.taxableProfit.numerator, '6700'); assert.equal(m.taxableBase, null); assert.equal(m.tax, null); assert.equal(m.profit.pending.length, 0); assert.equal( m.profit.lines.find((l) => l.code === 'interest_expense').remainder .numerator, '0', ); assert.equal( m.profit.lines.find((l) => l.code === 'operating_expenses').remainder .numerator, '1100', ); }); void test('known zero,declared absence,and missing information keep distinct saved evidence and effects', () => { const { d, b } = example(); b.profit.topics.incomeCorrections = { state: 'known', amount: '0', reference: 'QA total revisto de correcções ao rendimento é zero', }; let m = calculateNormal(d, b); assert.equal(m.taxableProfit.numerator, '6700'); assert.equal( m.profit.topics.find((t) => t.key === 'incomeCorrections').state, 'known', ); assert.equal( m.profit.topics.find((t) => t.key === 'positivePatrimonial').state, 'absent', ); b.profit.topics.negativePatrimonial = { state: '', amount: '', reference: '', }; m = calculateNormal(d, b); assert.equal(m.taxableProfit, null); assert.equal(m.additions.numerator, '220'); assert.equal( m.profit.topics.find((t) => t.key === 'negativePatrimonial').value, null, ); assert.match(m.profit.pending.join(' '), /sem zero presumido/); }); void test('absence cannot override known nonzero financial values or silently discard an entered amount', () => { const { d, b } = example(); b.profit.lines.find((l) => l.code === 'operating_expenses').state = 'absent'; assert.equal(calculateNormal(d, b).taxableProfit, null); b.profit.lines.find((l) => l.code === 'operating_expenses').state = 'known'; b.profit.topics.positivePatrimonial.amount = '100'; assert.equal(calculateNormal(d, b).taxableProfit, null); }); void test('known unimplemented variation,depreciation and remaining financial interest stay visible without presumed treatment', () => { for (const patch of ['variation', 'depreciation', 'interest']) { const { d, b } = example(); if (patch === 'variation') b.profit.topics.positivePatrimonial = { state: 'known', amount: '500', reference: 'QA variação500,regra específica por corresponder', }; if (patch === 'depreciation') { const p = restoreBusinessPlanSnapshot(d.business_plan_snapshot); p.assetDepreciation = '120'; d.business_plan_snapshot = serializeBusinessPlanSnapshot(p); b.profit.lines.find((l) => l.code === 'depreciation').state = 'known'; } if (patch === 'interest') b.rows[1].amount = '20'; const m = calculateNormal(d, b); assert.equal(m.taxableProfit, null); assert.ok(m.profit.pending.length > 0); if (patch === 'variation') assert.equal(m.profit.topics[0].value.numerator, '500'); } }); void test('complete line classifications and subject-year completeness are required,not a bare project subtotal', () => { for (const patch of [ 'line', 'reference', 'completeness', 'scope', 'year', ]) { const { d, b } = example(); if (patch === 'line') b.profit.lines.pop(); if (patch === 'reference') b.profit.lines[0].reference = ''; if (patch === 'completeness') b.profit.completenessReference = ''; if (patch === 'scope') b.scope = 'other'; if (patch === 'year') b.year = '2025'; assert.equal(calculateNormal(d, b).taxableProfit, null); } }); void test('declared no addbacks can close only after full documented review,and fiscal losses are not clamped to zero', () => { const { d, b } = example(); let p = restoreBusinessPlanSnapshot(d.business_plan_snapshot); p.monthlyInterestExpense = '0'; d.business_plan_snapshot = serializeBusinessPlanSnapshot(p); b.rows = []; b.profit.lines.find((l) => l.code === 'interest_expense').state = 'absent'; assert.equal(calculateNormal(d, b).taxableProfit.numerator, '6600'); p.products[0].unitPrice = '1'; d.business_plan_snapshot = serializeBusinessPlanSnapshot(p); assert.equal(calculateNormal(d, b).taxableProfit.numerator, '-5280'); }); void test('L5 uncertainty does not block independent known expense classification or annual profit', () => { const { d, b } = example(), s = JSON.parse(d.modelo_a_snapshot); for (const v of Object.values(s.irpcWithholdings ?? {})) { if (v.mrfta) { v.mrfta.codes = []; v.mrfta.interest.mode = ''; v.mrfta.interest.calculation = undefined; } } d.modelo_a_snapshot = JSON.stringify(s); assert.equal(calculateNormal(d, b).taxableProfit.numerator, '6700'); }); void test('old result remains current and unchanged;new closure history and stale-input guards survive roundtrip and dossier', () => { const legacy = seed(), old = structuredClone(normalBook(legacy)); assert.equal(normalCurrent(legacy, old), true); assert.equal(old.result.model.version, 'IRPC-normal-adjustments/1'); const { d, b } = example(); const saved = recordNormal(d, b, '2026-10-25T22:00:00Z'); assert.deepEqual(saved.history.at(-1), old.result); const before = JSON.parse(d.modelo_a_snapshot); d.modelo_a_snapshot = saveNormalBook(d, saved); assert.deepEqual( JSON.parse(d.modelo_a_snapshot).irpcWithholdings, before.irpcWithholdings, ); const back = JSON.parse(JSON.stringify(d)); assert.equal(normalCurrent(back, normalBook(back)), true); assert.match(normalHtml(back), /lucro tributável simulado:6700/); assert.match( JSON.stringify( createProjectDossierReport(back, { selectedSections: new Set(['finance']), }), ), /6700/, ); assert.match(JSON.stringify(normalReportRows(back)), /Ausência declarada/); const l5 = irpcBook(back); back.modelo_a_snapshot = saveIrpcBook(back, l5); assert.deepEqual(normalBook(back), saved); normalBook(back).profit.lines[0].reference = ''; const changed = normalBook(back); changed.profit.lines[0].reference = ''; back.modelo_a_snapshot = saveNormalBook(back, changed); assert.equal(normalCurrent(back, normalBook(back)), false); assert.throws(() => normalHtml(back)); fs.mkdirSync('outputs/irpc-l6-profit', { recursive: true }); fs.writeFileSync( 'outputs/irpc-l6-profit/calculated.json', JSON.stringify(d), ); fs.writeFileSync('outputs/irpc-l6-profit/preparation.html', normalHtml(d)); const missing = normalBook(d); missing.profit.topics.negativePatrimonial = { state: '', amount: '', reference: '', }; const md = structuredClone(d); md.modelo_a_snapshot = saveNormalBook(md, recordNormal(md, missing)); fs.writeFileSync('outputs/irpc-l6-profit/missing.json', JSON.stringify(md)); }); void test('malformed added evidence and unsupported stored versions fail without resetting the book', () => { const { d, b } = example(); b.profit.topics.positivePatrimonial.amount = 100; assert.throws(() => saveNormalBook(d, b)); b.profit.topics.positivePatrimonial.amount = ''; b.profit.lines.push({ ...b.profit.lines[0] }); assert.throws(() => saveNormalBook(d, b)); });