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 { validateSpecial } from '../../resources/js/lib/irpc-special.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); function accepted() { const d = read('irpc-l7-preserved.json').acceleration, f = read('irpc-l7-continuation-preserved.json'); d.business_plan_snapshot = f.plan; d.modelo_a_snapshot = saveNormalBook(d, f.book); return { d, b: normalBook(d) }; } function setup(expense = false) { const { d, b } = accepted(); const i = b.special; Object.assign(i.cooperative, { kind: 'agrarian', allIncomeEligible: 'yes', withheldIncome: 'absent', }); Object.assign(i.cooperative.qualification, { state: 'known', eligible: 'yes', reference: 'QA cooperativa agrária12,base ordinária integralmente elegível;sem rendimentos sujeitos a retenção', }); i.acceleration.rows[0].kind = 'agroindustrial_equipment'; i.combinations = { version: 1, reference: 'QA mesmo sujeito/projecto/período;reduçãoCIRPC12 eCBF16 genérico,efeitos em etapas distintas', specificState: 'absent', specificReference: 'QA sem estatuto/benefício específicoCBF20–48 neste projecto/período;CBF13', specificException: '', otherState: 'absent', otherReference: 'QA sem outros benefícios além dos tratamentosL7 registados', }; if (expense) { const old = normalBook(read('irpc-l7-preserved.json').expense); b.schedules.rows.push(structuredClone(old.schedules.rows[0])); b.profit.topics.expenseCorrections = structuredClone( old.profit.topics.expenseCorrections, ); i.expenses = structuredClone(old.special.expenses); Object.assign(i.expenses.qualification, { from: b.periodsFx.from, to: b.periodsFx.to, }); } return { d, b }; } void test('accepted13 model,key and allhistorical balances reproduce exactly without optionalcombination', () => { const { d, b } = accepted(); assert.equal(normalCurrent(d, b), true); assert.deepEqual(calculateNormal(d, b), b.result.model); assert.deepEqual(normalBook(d).history, b.history); }); void test('qualified cooperative12 and genericCBF16 combine in order,additional25 once then16percent,prior15 already included', () => { const { d, b } = setup(), assets = JSON.stringify(b.depreciation), m = calculateNormal(d, b), s = m.special, c = s.combinations; assert.equal(m.version, 'IRPC-normal-adjustments/14'); assert.equal(c.status, 'compatible'); assert.equal(val(m.taxableProfit), 3130); assert.equal(val(m.colecta), 1001.6); assert.equal(val(s.acceleration.additionalDeduction), 25); assert.equal(val(s.taxableProfit), 3105); assert.equal(val(s.taxableBase), 3105); assert.equal(val(s.cooperative.rate), 16); assert.equal(val(s.colecta), 496.8); assert.equal(val(s.combinedColecta), 496.8); assert.equal(val(c.assetClaims[0].acceleratedDeduction), 75); assert.equal(val(c.assetClaims[0].priorRecoveredIncluded), 15); assert.equal(val(c.assetClaims[0].additionalDeduction), 25); assert.equal(JSON.stringify(b.depreciation), assets); assert.equal(s.finalBalance.payable, null); assert.doesNotMatch(s.acceleration.source, /Sem cumulação[.]/); }); void test('autonomousexpense35percent is not halved by cooperative rate or added again to the taxableprofit', () => { const { d, b } = setup(true), m = calculateNormal(d, b), s = m.special; assert.equal(val(m.taxableProfit), 3230); assert.equal(val(s.taxableProfit), 3205); assert.equal(val(s.taxableBase), 3205); assert.equal(val(s.expenses.rows[0].l6Adjustment), 100); assert.equal(val(s.expenses.rows[0].additionalProfitAdjustment), 0); assert.equal(val(s.expenses.autonomousTax), 35); assert.equal(val(s.colecta), 512.8); assert.equal(val(s.combinedColecta), 547.8); assert.equal(val(s.combinations.limits.autonomousRate), 35); }); void test('specificCBF22 with generic16 and declaredabsence of exception is incompatible,neither benefit automatically selected', () => { const { d, b } = setup(); Object.assign(b.special.combinations, { specificState: 'known', specificReference: 'QA CBF22 benefício específico infra-estruturas declarado no mesmo projecto/período', specificException: 'absent', }); const input = structuredClone(b.special), m = calculateNormal(d, b), s = m.special; assert.equal(s.combinations.status, 'incompatible'); assert.equal(s.acceleration.additionalDeduction, null); assert.equal(s.taxableProfit, null); assert.equal(s.colecta, null); assert.equal(s.combinedColecta, null); assert.equal(val(m.colecta), 1001.6); assert.deepEqual(b.special, input); assert.match(s.pending.join(' '), /IncompatibilidadeCBF4\/13/); }); void test('claimedexception,unknownspecificpresence,otherbenefit or missingsupport remain indeterminate without provisionalrate', () => { for (const patch of [ { specificState: 'known', specificReference: 'QA excepção invocada,artigo/limite não correspondidos', specificException: 'claimed', }, { specificState: '' }, { otherState: 'known', otherReference: 'QA outro benefício fora dos ramos calculados', }, { reference: '' }, { specificReference: '' }, { otherReference: '' }, ]) { const { d, b } = setup(); Object.assign(b.special.combinations, patch); const m = calculateNormal(d, b); assert.equal(m.special.combinations.status, 'indeterminate'); assert.equal(m.special.colecta, null); assert.equal(val(m.colecta), 1001.6); } }); void test('missingcooperativeperiod or mixedincome blocks its dependenttotal without choosing eligibility from location', () => { for (const patch of [ { allIncomeEligible: 'no' }, { withheldIncome: 'known' }, ]) { const { d, b } = setup(); Object.assign(b.special.cooperative, patch); d.province_id = 'QA-ZEE-address'; const s = calculateNormal(d, b).special; assert.equal(s.colecta, null); assert.match(s.cooperative.reason, /mistas\/retidas/); } const { d, b } = setup(); b.special.cooperative.qualification.from = '2026-02-01'; assert.equal(calculateNormal(d, b).special.colecta, null); }); void test('duplicateassetqualification cannot duplicate CBF16 deduction;remainingfiscal20 cap keepsadditionalzero', () => { const { d, b } = setup(); b.special.acceleration.rows.push({ ...b.special.acceleration.rows[0], id: 'same-asset-again', }); let s = calculateNormal(d, b).special; assert.equal(s.acceleration.additionalDeduction, null); assert.match(s.acceleration.reason, /Activo repetido/); const cap = setup(); Object.assign(cap.b.depreciation.assets[0], { previousAccounting: '1000', previousFiscal: '980', priorAvailable: '20', }); s = calculateNormal(cap.d, cap.b).special; assert.equal(val(s.acceleration.additionalDeduction), 0); assert.equal(val(s.combinations.assetClaims[0].acceleratedDeduction), 20); assert.equal(val(s.combinations.assetClaims[0].remainingFiscal), 0); }); void test('negativecooperative or absentCBF16 retains the other independentlyqualified treatment', () => { const negative = setup(); negative.b.special.cooperative.qualification.eligible = 'no'; let s = calculateNormal(negative.d, negative.b).special; assert.equal(s.cooperative.status, 'not_applicable'); assert.equal(val(s.colecta), 993.6); const absent = setup(); absent.b.special.acceleration.rows = []; Object.assign(absent.b.special.acceleration.qualification, { state: 'absent', eligible: '', }); s = calculateNormal(absent.d, absent.b).special; assert.equal(s.acceleration.status, 'absent'); assert.equal(val(s.acceleration.additionalDeduction), 0); assert.equal(val(s.colecta), 500.8); }); void test('save-recover14 appends13 verbatim,leaves inputbalances/plan/otherbooks unchanged,and report explains order and no double deduction', () => { const { d, b } = setup(true), old = structuredClone(b.result), history = structuredClone(b.history), assets = JSON.stringify(b.depreciation), plan = d.business_plan_snapshot, other = JSON.parse(d.modelo_a_snapshot).irpcWithholdings; d.modelo_a_snapshot = saveNormalBook(d, recordNormal(d, b)); let back = normalBook(JSON.parse(JSON.stringify(d))); assert.equal(normalCurrent(d, back), true); assert.deepEqual(back.history, [...history, old]); assert.equal(old.model.version, 'IRPC-normal-adjustments/13'); assert.equal(JSON.stringify(back.depreciation), assets); assert.equal(d.business_plan_snapshot, plan); assert.deepEqual(JSON.parse(d.modelo_a_snapshot).irpcWithholdings, other); const html = normalHtml(d); assert.match(html, /Combinação permitida no recorte/); assert.match(html, /parcela anterior já incluída na dedução CBF16:15.00/); assert.match(html, /única diferença adicional:25.00/); assert.match(html, /imposto autónomo independente:35.00/); assert.match(html, /colecta combinada:547.80/); assert.match(html, /Saldo final a pagar\/recuperar:Indeterminado/); assert.match( JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), }), ), /Cumulações — qualificação/, ); d.modelo_a_snapshot = saveNormalBook(d, recordNormal(d, back)); back = normalBook(d); assert.equal(val(back.result.model.special.combinedColecta), 547.8); assert.equal(back.depreciation.assets[0].priorAvailable, '50'); back.special.combinations.otherState = 'known'; assert.equal(normalCurrent(d, back), false); }); void test('positive unclassified L6benefit is preserved and blocks another deduction until reconciled;zero base never offsets autonomous35', () => { const extra = setup(); extra.b.base.benefits = { state: 'known', amount: '100', reference: 'QA dedução já declarada sem correspondência à combinação', }; let m = calculateNormal(extra.d, extra.b); assert.equal(m.special.combinations.status, 'indeterminate'); assert.equal(m.special.colecta, null); assert.notEqual(m.taxableProfit, null); assert.equal(extra.b.base.benefits.amount, '100'); assert.match(m.special.pending.join(' '), /já registado emL6/); const loss = setup(true), p = JSON.parse(loss.d.business_plan_snapshot); p.plan.products[0].unitPrice = '10'; loss.d.business_plan_snapshot = JSON.stringify(p); loss.b.schedules.currentLossReference = 'QA perda própria do período reconciliada;sem transporte oficial automático'; m = calculateNormal(loss.d, loss.b); assert.ok(val(m.special.taxableProfit) < 0); assert.equal(val(m.special.taxableBase), 0); assert.equal(val(m.special.colecta), 0); assert.equal(val(m.special.expenses.autonomousTax), 35); assert.equal(val(m.special.combinedColecta), 35); }); void test('malformedoptionalcombination cannot overwrite acceptedbooks', () => { for (const value of [ null, { version: 2 }, { version: 1, reference: 'QA', specificState: 'unknown', specificReference: 'QA', specificException: '', otherState: 'absent', otherReference: 'QA', }, ]) { const { b } = setup(); b.special.combinations = value; assert.throws(() => validateSpecial(b.special), /não recuperável/); } }); void test('prepare only new guardedAPI cases;accepted13 proofs remain separate', () => { const cases = { combined: setup(), autonomous: setup(true), incompatible: setup(), missing: setup(), exception: setup(), negative: setup(), absent: setup(), }; Object.assign(cases.incompatible.b.special.combinations, { specificState: 'known', specificReference: 'QA CBF22 no mesmo projecto/período', specificException: 'absent', }); cases.missing.b.special.combinations.specificReference = ''; Object.assign(cases.exception.b.special.combinations, { specificState: 'known', specificReference: 'QA excepção expressa invocada sem correspondência de artigo/limites', specificException: 'claimed', }); cases.negative.b.special.cooperative.qualification.eligible = 'no'; cases.absent.b.special.acceleration.rows = []; Object.assign(cases.absent.b.special.acceleration.qualification, { state: 'absent', eligible: '', }); fs.mkdirSync('outputs/irpc-l7-combinations', { recursive: true }); for (const [name, { d, b }] of Object.entries(cases)) { d.modelo_a_snapshot = saveNormalBook( d, recordNormal(d, b, '2026-10-26T16:00:00+02:00'), ); fs.writeFileSync( 'outputs/irpc-l7-combinations/' + name + '.json', JSON.stringify(d), ); fs.writeFileSync( 'outputs/irpc-l7-combinations/' + name + '.html', normalHtml(d), ); } });