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

455 lines
17 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,
} 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),
);
}
});