Files
Investidor-V2/tests/frontend/irpc-normal-assessment.test.mjs
T

209 lines
7.6 KiB
JavaScript

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));
});