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

251 lines
9.8 KiB
JavaScript

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