import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { normalBook, normalCurrent, calculateNormal, recordNormal, saveNormalBook, normalHtml, } from '../../resources/js/lib/irpc-normal.ts'; import { newSpecialInput, newQualification, newSpecialExpense, newAcceleratedAsset, } from '../../resources/js/lib/irpc-special.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const seed = () => JSON.parse( fs.readFileSync( new URL( './fixtures/irpc-l6-values-preserved.json', import.meta.url, ), 'utf8', ), ); const value = (v) => (v ? Number(v.numerator) / Number(v.denominator) : null); const qualification = ( state = 'absent', from = '2026-07-01', to = '2026-12-31', ) => ({ ...newQualification(), state, eligible: state === 'known' ? 'yes' : '', from, to, reference: 'QA declaração/prova das condições legais no sujeito e parcela,sem inferência territorial', periodReference: 'QA norma/exercício2026 e período documentado', }); function setup() { const d = seed(), b = normalBook(d); b.special = newSpecialInput(); for (const part of [ b.special.expenses, b.special.cooperative, b.special.acceleration, ]) part.qualification = qualification(); return { d, b }; } function expenses() { const { d, b } = setup(); b.schedules.rows.push({ id: 'expense36g', rule: 'undocumented', amount: '100', sourceCode: 'operating_expenses', document: 'QA-despesa', line: '1', reference: 'QA despesa100 efectivamente incluída e não documentada36g', fiscalYear: '', conditions: 'yes', }); b.profit.topics.expenseCorrections = { state: 'known', amount: '100', reference: 'QA acréscimo36g já conferido,sem outra correcção', }; b.special.expenses.qualification = qualification('known'); b.special.expenses.rows = [ { ...newSpecialExpense('autonomous1'), scheduleId: 'expense36g', nature: 'undocumented', eligible: 'yes', reference: 'QA qualificação legal61(4),não inferida de anexo em falta', }, ]; return { d, b }; } function cooperative() { const { d, b } = setup(); b.special.cooperative = { qualification: qualification('known'), kind: 'agrarian', allIncomeEligible: 'yes', withheldIncome: 'absent', }; return { d, b }; } function acceleration() { const { d, b } = setup(); delete b.periodsFx; delete b.forms; b.schedules.interest.amount = '240'; Object.assign(b.depreciation.assets[0], { category: 'machine', description: 'Máquina industrial existente QA', cost: '1000', rate: '10', accounting: '120', start: '2026-01-01', timing: 'annual', }); for (const part of [ b.special.expenses, b.special.cooperative, b.special.acceleration, ]) part.qualification = qualification( 'absent', '2026-01-01', '2026-12-31', ); b.special.acceleration = { qualification: qualification('known', '2026-01-01', '2026-12-31'), cbfRequirements: 'yes', recognition: 'documented', recognitionReference: 'QA instrumento do projecto/reconhecimento10,pressupostos3/9 e afectação industrial documentados', noOtherBenefits: 'yes', rows: [ { ...newAcceleratedAsset('accelerated1'), assetId: b.depreciation.assets[0].id, kind: 'industrial_equipment', eligible: 'yes', reference: 'QA factura/afectação da máquina ao projecto industrialCBF16', }, ], }; return { d, b }; } void test('no optionalL7 keeps exact accepted9 result and key; installed history is not recalculated on read', () => { const d = seed(), b = normalBook(d), old = structuredClone(b.result); assert.equal(normalCurrent(d, b), true); assert.deepEqual(calculateNormal(d, b), old.model); assert.deepEqual(normalBook(d).result, old); }); void test('61(4) reuses100 addback36g and computes35 autonomously without another profit adjustment', () => { const { d, b } = expenses(), m = calculateNormal(d, b), s = m.special; assert.equal(m.version, 'IRPC-normal-adjustments/10'); assert.equal(value(m.taxableProfit), 3230); assert.equal(value(m.colecta), 1033.6); assert.equal(value(s.taxableProfit), 3230); assert.equal(value(s.expenses.rows[0].l6Adjustment), 100); assert.equal(value(s.expenses.rows[0].additionalProfitAdjustment), 0); assert.equal(value(s.expenses.autonomousTax), 35); assert.equal(value(s.combinedColecta), 1068.6); assert.equal(s.finalBalance.payable, null); }); void test('missing, absent and notapplicable differ; attachment presence alone never classifies an expense', () => { const { d, b } = setup(); b.special.expenses.qualification = qualification(''); let s = calculateNormal(d, b).special; assert.equal(s.expenses.status, 'indeterminate'); assert.equal(s.expenses.autonomousTax, null); b.special.expenses.qualification = qualification('absent'); s = calculateNormal(d, b).special; assert.equal(s.expenses.status, 'absent'); assert.equal(value(s.expenses.autonomousTax), 0); b.special.expenses.qualification = qualification('not_applicable'); assert.equal( calculateNormal(d, b).special.expenses.status, 'not_applicable', ); const c = expenses(); c.b.special.expenses.rows[0].nature = ''; assert.equal( calculateNormal(c.d, c.b).special.expenses.autonomousTax, null, ); }); void test('false condition keeps existing addback and no autonomous tax; contradictory absence cannot erase expense', () => { const { d, b } = expenses(); b.special.expenses.rows[0].eligible = 'no'; let m = calculateNormal(d, b); assert.equal(m.special.expenses.rows[0].status, 'not_applicable'); assert.equal(value(m.special.expenses.autonomousTax), 0); assert.equal(value(m.taxableProfit), 3230); b.special.expenses.rows = []; b.special.expenses.qualification = qualification('absent'); m = calculateNormal(d, b); assert.equal(m.special.expenses.status, 'indeterminate'); assert.equal(value(m.taxableProfit), 3230); }); void test('duplicate, unlinked or uncalculated36g cannot doublecharge or manufacture tax', () => { for (const mode of [ 'duplicate', 'unlinked', 'uncalculated', 'missingcoverage', ]) { const { d, b } = expenses(); if (mode === 'duplicate') b.special.expenses.rows.push({ ...b.special.expenses.rows[0], id: 'duplicate', }); if (mode === 'unlinked') b.special.expenses.rows[0].scheduleId = 'not-found'; if (mode === 'uncalculated') b.schedules.rows[0].conditions = ''; if (mode === 'missingcoverage') b.special.expenses.rows = []; assert.equal( calculateNormal(d, b).special.expenses.autonomousTax, null, mode, ); } }); void test('common qualification rejects wrong period/year or missing identity without blocking independent L6 totals', () => { for (const mutate of [ (b) => (b.special.expenses.qualification.to = '2025-12-31'), (b) => (b.special.expenses.qualification.periodReference = ''), (b) => (b.base.subjectNuit = ''), ]) { const { d, b } = expenses(); mutate(b); const m = calculateNormal(d, b); assert.equal(m.special.expenses.autonomousTax, null); if (b.base.subjectNuit) assert.equal(value(m.colecta), 1033.6); } }); void test('unknown benefit does not suppress separately calculable autonomous expense or normal reference', () => { const { d, b } = expenses(); b.special.acceleration.qualification = qualification(''); const m = calculateNormal(d, b); assert.equal(value(m.special.expenses.autonomousTax), 35); assert.equal(value(m.special.reference.colecta), 1033.6); assert.equal(m.special.combinedColecta, null); }); void test('eligible cooperative uses16percent without changing reference32percent or autonomous expense rate', () => { const { d, b } = cooperative(), m = calculateNormal(d, b); assert.equal(value(m.colecta), 1001.6); assert.equal(m.special.cooperative.status, 'calculated'); assert.equal(value(m.special.cooperative.rate), 16); assert.equal(value(m.special.colecta), 500.8); assert.equal(value(m.special.taxableBase), 3130); assert.equal(value(m.special.combinedColecta), 500.8); const x = expenses(); x.b.special.cooperative = structuredClone(b.special.cooperative); assert.equal( value(calculateNormal(x.d, x.b).special.combinedColecta), 551.8, ); }); void test('mixed, withheld, unclassified or false cooperative conditions never grant blanket reduction', () => { for (const mutate of [ (c) => (c.allIncomeEligible = 'no'), (c) => (c.withheldIncome = 'known'), (c) => (c.kind = 'other'), ]) { const { d, b } = cooperative(); mutate(b.special.cooperative); const m = calculateNormal(d, b); assert.equal(m.special.cooperative.status, 'indeterminate'); assert.equal(m.special.colecta, null); assert.equal(value(m.colecta), 1001.6); } const { d, b } = cooperative(); b.special.cooperative.qualification.eligible = 'no'; assert.equal(value(calculateNormal(d, b).special.colecta), 1001.6); }); void test('cooperative treatment does not require mislabelling special rate as L6 general; contradictory absence remains pending', () => { const { d, b } = cooperative(); b.assessment.treatment = 'other'; let m = calculateNormal(d, b); assert.equal(m.colecta, null); assert.equal(value(m.special.colecta), 500.8); b.special.cooperative.qualification = qualification('absent'); m = calculateNormal(d, b); assert.equal(m.special.cooperative.status, 'indeterminate'); assert.equal(m.special.colecta, null); }); void test('common period follows declared shortperiod even without schedules; calendar dates cannot replace it', () => { const { d, b } = cooperative(); delete b.schedules; b.special.expenses.qualification = qualification( 'absent', '2026-01-01', '2026-12-31', ); const m = calculateNormal(d, b); assert.equal(m.special.period.from, '2026-07-01'); assert.equal(m.special.expenses.status, 'indeterminate'); }); void test('CBF16 reuses asset and rate10to15 but respects120 accounted cap; additional deduction20 not50', () => { const { d, b } = acceleration(), input = JSON.stringify(b.depreciation), m = calculateNormal(d, b), s = m.special; assert.equal(s.acceleration.status, 'calculated', s.acceleration.reason); assert.equal(value(m.depreciation.assets[0].quota), 100); assert.equal(value(s.acceleration.accelerated.assets[0].quota), 150); assert.equal(value(s.acceleration.accelerated.assets[0].deduction), 120); assert.equal(value(s.acceleration.additionalDeduction), 20); assert.equal(value(m.taxableProfit), 6260); assert.equal(value(s.taxableProfit), 6240); assert.equal(value(s.taxableBase), 6240); assert.equal(value(s.colecta), 1996.8); assert.equal(JSON.stringify(b.depreciation), input); }); void test('new project building reuses land separation and legal table rate before bounded acceleration', () => { const { d, b } = acceleration(); Object.assign(b.depreciation.assets[0], { category: 'commercial_building', cost: '5000', land: '0', rate: '2', }); b.special.acceleration.rows[0].kind = 'new_project_building'; const m = calculateNormal(d, b); assert.equal(m.special.acceleration.status, 'calculated'); assert.equal( value(m.special.acceleration.accelerated.assets[0].quota), 150, ); assert.equal(value(m.special.acceleration.additionalDeduction), 20); }); void test('lower optional normal quota remains valid L6 but is not treated as legally fixed rate in CBF16', () => { const { d, b } = acceleration(); b.depreciation.assets[0].rate = '5'; const m = calculateNormal(d, b); assert.equal(m.depreciation.assets[0].status, 'calculated'); assert.equal(m.special.acceleration.additionalDeduction, null); assert.match(m.special.acceleration.reason, /quota inferior/); }); void test('location alone, wrong activity, prior quotas, unsupported periods and benefit combinations cannot accelerate', () => { for (const mutate of [ (b) => (b.special.acceleration.cbfRequirements = ''), (b) => (b.special.acceleration.recognitionReference = ''), (b) => (b.special.acceleration.rows[0].kind = 'other'), (b) => (b.depreciation.assets[0].timing = 'months'), (b) => (b.depreciation.assets[0].previousAccounting = '1'), (b) => (b.special.acceleration.noOtherBenefits = 'no'), (b) => { b.special.cooperative = { qualification: qualification( 'known', '2026-01-01', '2026-12-31', ), kind: 'agrarian', allIncomeEligible: 'yes', withheldIncome: 'absent', }; }, ]) { const { d, b } = acceleration(); d.province_id = 'ZEE-candidate'; mutate(b); const m = calculateNormal(d, b); assert.equal(m.special.acceleration.additionalDeduction, null); assert.notEqual(m.taxableProfit, null); assert.equal(m.special.acceleration.status, 'indeterminate'); } }); void test('save/recover/report preserves9history and L5/books; repeated calculation never accumulates tax or asset deduction', () => { const { d, b } = expenses(), old = structuredClone(b.result), plan = d.business_plan_snapshot; d.modelo_a_snapshot = saveNormalBook( d, recordNormal(d, b, '2026-10-26T14:00:00+02:00'), ); let back = normalBook(JSON.parse(JSON.stringify(d))); assert.equal(normalCurrent(d, back), true); assert.deepEqual(back.history.at(-1), old); assert.equal(d.business_plan_snapshot, plan); assert.ok(JSON.parse(d.modelo_a_snapshot).irpcWithholdings); const html = normalHtml(d); assert.match(html, /imposto autónomo:35/); assert.match(html, /novo ajustamento ao lucro:0/); assert.match(html, /Saldo final a pagar\/recuperar:Indeterminado/); assert.match( JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), }), ), /Despesas — imposto autónomo/, ); d.modelo_a_snapshot = saveNormalBook(d, recordNormal(d, back)); back = normalBook(d); assert.equal(value(back.result.model.special.expenses.autonomousTax), 35); assert.equal(value(back.result.model.taxableProfit), 3230); d.province_id = 'changed'; assert.equal(normalCurrent(d, normalBook(d)), false); assert.throws(() => normalHtml(d), /Calcule/); }); void test('new evidence changes key; malformedqualification or duplicate row ID cannot overwrite book', () => { const { d, b } = expenses(); d.modelo_a_snapshot = saveNormalBook(d, recordNormal(d, b)); const back = normalBook(d); back.special.expenses.rows[0].reference += ' alterado'; assert.equal(normalCurrent(d, back), false); back.special.expenses.rows.push( structuredClone(back.special.expenses.rows[0]), ); assert.throws(() => saveNormalBook(d, back), /identificador repetido/); }); void test('report presents context labels and retains provenance internally without dumping raw context snapshots', () => { const { d, b } = setup(); d.province_id_label = 'Província QA'; d.context_opportunity_snapshot = '{"internal":"QA implementation blob"}'; d.modelo_a_snapshot = saveNormalBook(d, recordNormal(d, b)); assert.match(normalHtml(d), /Província: Província QA/); assert.doesNotMatch(normalHtml(d), /QA implementation blob/); assert.equal( normalBook(d).result.model.special.context.context_opportunity_snapshot, d.context_opportunity_snapshot, ); }); void test('write only new QA cases for transactional API and recovered reports', () => { const missing = expenses(), negative = expenses(); missing.b.special.expenses.rows[0].nature = ''; negative.b.special.expenses.rows[0].eligible = 'no'; const cases = { expense: expenses(), missing, negative, absent: setup(), cooperative: cooperative(), acceleration: acceleration(), }; fs.mkdirSync('outputs/irpc-l7-common', { recursive: true }); for (const [name, { d, b }] of Object.entries(cases)) { d.modelo_a_snapshot = saveNormalBook( d, recordNormal(d, b, '2026-10-26T14:00:00+02:00'), ); fs.writeFileSync( 'outputs/irpc-l7-common/' + name + '.json', JSON.stringify(d), ); fs.writeFileSync( 'outputs/irpc-l7-common/' + name + '.html', normalHtml(d), ); } });