Files
Investidor-V2/tests/frontend/irpc-economic-credit.test.mjs
T
2026-11-10 13:23:11 +02:00

433 lines
17 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { economicCase } from './helpers/irpc-economic-case.mjs';
import { internationalCase } from './helpers/irpc-international-case.mjs';
import {
calculateAnnual,
prepareEconomicBook,
annualBook,
recordAnnual,
saveAnnualBook,
annualCurrent,
annualHtml,
annualReportRows,
} from '../../resources/js/lib/irpc-annual-settlement.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
import {
irpcBook,
recordIrpc,
saveIrpcBook,
} from '../../resources/js/lib/irpc-withholdings.ts';
const number = (v) => (v ? Number(v.numerator) / Number(v.denominator) : null);
const row = (c) => c.b.economicCredits.rows[0];
const foreign = (c) => c.b.internationalCredits.positions[0].payments[0];
const calc = (c) => calculateAnnual(c.d, c.b);
const pending = (c) => {
const m = calc(c);
assert.equal(m.status, 'indeterminate', JSON.stringify(m.pending));
assert.equal(m.arithmeticBalance, null);
assert.equal(m.economicCredit.deducted, null);
assert.equal(m.internationalCredit.deducted, null);
assert.equal(m.pecDeduction.deducted, null);
return m;
};
void test('economic60% of documented sourceIRPC20 yields12 before international8,PEC200 andPPC500:688', () => {
const m = calc(economicCase());
assert.deepEqual(m.pending, []);
assert.equal(number(m.economicCredit.rows[0].nominal), 12);
assert.equal(number(m.economicCredit.deducted), 12);
assert.equal(number(m.economicCredit.afterCredit), 1396);
assert.equal(number(m.internationalCredit.deducted), 8);
assert.equal(number(m.internationalCredit.afterCredit), 1388);
assert.equal(number(m.payable), 688);
assert.equal(m.economicCredit.carryCreated, false);
assert.equal(m.economicCredit.officialBalancesConsumed, false);
assert.equal(m.submitted, false);
});
void test('documented proportional ceiling and prior actual use limit economic deduction,not a second tax rate on dividends', () => {
const c = economicCase();
row(c).nationalLimit = '5';
let m = calc(c);
assert.equal(number(m.economicCredit.rows[0].nominal), 12);
assert.equal(number(m.payable), 695);
row(c).previousUse.amount = '3';
m = calc(c);
assert.equal(number(m.economicCredit.deducted), 2);
assert.equal(number(m.payable), 698);
row(c).previousUse.amount = '6';
pending(c);
});
void test('article40 exclusion, payer exemption/foreign residence and special distributions do not become international credit', () => {
for (const patch of [
{ article40: '' },
{ article40: 'yes' },
{ article40Reference: '' },
{ payerResident: '' },
{ payerResident: 'no' },
{ recipientResident: 'no' },
{ payerIrpc: 'no' },
{ payerExempt: '' },
{ payerExempt: 'yes' },
{ kind: 'liquidation' },
{ kind: 'association' },
{ kind: '' },
{ qualificationReference: '' },
]) {
const c = economicCase();
Object.assign(row(c), patch);
const m = pending(c);
assert.equal(m.internationalCredit.positions.length, 1);
assert.equal(number(m.internationalCredit.positions[0].eligible), 8);
if (patch.article40 === 'yes')
assert.equal(m.economicCredit.rows[0].status, 'outside_scope');
}
});
void test('inclusion,credit gross-up and current assessment must be reconciled without silently changing L6', () => {
for (const patch of [
{ incomeIncluded: '' },
{ incomeIncluded: 'no' },
{ incomeReference: '' },
{ assessmentKey: '' },
{ assessmentKey: 'stale' },
{ grossUpIncluded: '' },
{ grossUpIncluded: '0' },
{ grossUpIncluded: '11.99' },
{ grossUpReference: '' },
{ nationalLimit: '' },
{ nationalLimit: '1409' },
{ nationalLimitReference: '' },
{ income: '0' },
]) {
const c = economicCase(),
before = c.d.modelo_a_snapshot;
Object.assign(row(c), patch);
pending(c);
assert.equal(c.d.modelo_a_snapshot, before);
}
});
void test('dividend/source tax identity,date,year,subject and actual allocated source amount require support', () => {
for (const patch of [
{ subjectNuit: '999999999' },
{ payerNuit: '' },
{ year: '2025' },
{ distributionDate: '2026-02-30' },
{ distributionDate: '2025-12-31' },
{ distributionDocument: '' },
{ distributionParcel: '' },
{ taxIssuer: '' },
{ taxDocument: '' },
{ taxParcel: '' },
{ parcelReference: '' },
{ currency: 'USD' },
{ proofAmount: '' },
{ taxAmount: '21' },
{ taxAmount: '' },
{ attributionReference: '' },
{ previouslyAttributed: '' },
{ previouslyAttributed: '1' },
{ priorAttributionReference: '' },
]) {
const c = economicCase();
Object.assign(row(c), patch);
pending(c);
}
});
void test('same distributed profit parcel cannot be re-used by changing source-tax document,id or date', () => {
const c = economicCase();
c.b.economicCredits.rows.push({
...structuredClone(row(c)),
id: 'other',
taxDocument: 'OTHER',
distributionDate: '2026-10-01',
distributionDocument: ' synthetic-dividend2026 ',
distributionParcel: ' DISTRIBUTION-1 ',
});
assert.match(pending(c).pending.join(' '), /Mesma parcela de lucros/);
});
void test('one source-tax parcel can support distinct documented distributions only within its actual available amount', () => {
const c = economicCase(),
other = {
...structuredClone(row(c)),
id: 'second',
distributionParcel: 'distribution-2',
};
c.b.economicCredits.rows.push(other);
assert.match(pending(c).pending.join(' '), /disponível/);
for (const r of c.b.economicCredits.rows) {
r.taxAmount = '10';
r.grossUpIncluded = '6';
}
let m = calc(c);
assert.deepEqual(m.pending, []);
assert.equal(number(m.economicCredit.deducted), 12);
row(c).previouslyAttributed = '1';
other.previouslyAttributed = '1';
pending(c);
row(c).taxAmount = '9';
other.taxAmount = '9';
row(c).grossUpIncluded = '5.4';
other.grossUpIncluded = '5.4';
m = calc(c);
assert.deepEqual(m.pending, []);
assert.equal(number(m.economicCredit.deducted), 10.8);
other.previouslyAttributed = '0';
assert.match(pending(c).pending.join(' '), /divergente/);
});
void test('economic and international use of the same actual tax parcel is rejected even with changed receipt date', () => {
const c = economicCase();
Object.assign(foreign(c), {
issuer: row(c).taxIssuer,
document: row(c).taxDocument,
parcel: ' UNDERLYING-TAX-1 ',
parcelReference: 'SYNTHETIC same parcel',
proofAmount: '20',
date: '2026-10-01',
});
assert.match(pending(c).pending.join(' '), /natureza|naturezas/);
});
void test('an old proof with no parcel overlaps the whole document;new names require supported partition on both sides', () => {
const c = economicCase();
Object.assign(foreign(c), {
issuer: row(c).taxIssuer,
document: row(c).taxDocument,
proofAmount: '20',
});
pending(c);
foreign(c).parcel = 'foreign-tax-line';
pending(c);
foreign(c).parcelReference =
'SYNTHETIC evidence of a distinct foreign-tax line in shared document';
const m = calc(c);
assert.deepEqual(m.pending, []);
assert.equal(number(m.payable), 688);
});
void test('economic source IRPC is not beneficiary withholding,PPC or PEC;distinct supported parcels may share a document', () => {
for (const kind of ['ppc', 'pec']) {
const c = economicCase(),
proof = kind === 'ppc' ? c.b.ppc.rows[0] : c.b.pecPayments.rows[0];
Object.assign(row(c), {
taxIssuer: proof.issuer,
taxDocument: proof.document,
proofAmount: proof.proofAmount,
});
pending(c);
Object.assign(proof, {
parcel: 'own-' + kind,
parcelReference: 'SYNTHETIC distinct payment parcel',
});
assert.deepEqual(calc(c).pending, []);
proof.parcel = row(c).taxParcel;
pending(c);
}
});
void test('underlying domestic IRPC and beneficiary withholding remain separate even when supported by the same paper', () => {
const c = internationalCase('10', '8', '200', '500', '300');
c.b = prepareEconomicBook(c.b);
c.b.economicCredits = economicCase().b.economicCredits;
const withholding = c.b.withholdings.rows[0],
proof = calc(c).claims.find((x) => x.kind === 'withholding');
Object.assign(row(c), {
taxIssuer: proof.issuer,
taxDocument: proof.document,
proofAmount: '300',
});
pending(c);
Object.assign(withholding, {
parcel: 'beneficiary-withholding',
parcelReference: 'SYNTHETIC separate recipient-tax parcel',
});
assert.equal(number(calc(c).payable), 388);
const other = structuredClone(c.b),
s = JSON.parse(c.d.modelo_a_snapshot);
other.economicCredits.rows = [];
other.economicCredits.state = 'absent';
other.internationalCredits.positions = [];
other.internationalCredits.state = 'absent';
other.ppc.rows = [];
other.ppc.state = 'absent';
other.pecPayments.rows = [];
other.pecPayments.state = 'absent';
other.withholdings.rows[0].parcel = 'relabelled-same-L5-allocation';
s.irpcAnnual = { 'opportunity:other': other };
s.irpcWithholdings['opportunity:other'] = structuredClone(
Object.values(s.irpcWithholdings)[0],
);
c.d.modelo_a_snapshot = JSON.stringify(s);
c.d.modelo_a_snapshot = saveIrpcBook(
c.d,
recordIrpc(c.d, irpcBook(c.d), '2026-10-28T14:00:00+02:00'),
);
assert.match(
pending(c).pending.join(' '),
/calculada e reconciliada emL5|afectação L5/,
);
});
void test('documented economic inclusion is not rejected merely because fiscal losses reduce total taxable base below dividends', () => {
const c = economicCase();
row(c).income = '5000';
const m = calc(c);
assert.deepEqual(m.pending, []);
assert.equal(number(m.payable), 688);
});
void test('cross-context source capacity and distributed-income duplication cannot be evaded with new ids/documents', () => {
const c = economicCase(),
other = structuredClone(c.b),
s = JSON.parse(c.d.modelo_a_snapshot);
other.internationalCredits.positions = [];
other.internationalCredits.state = 'absent';
other.ppc.rows = [];
other.ppc.state = 'absent';
other.pecPayments.rows = [];
other.pecPayments.state = 'absent';
other.economicCredits.rows[0].id = 'other-id';
other.economicCredits.rows[0].taxDocument = 'OTHER';
s.irpcAnnual = { 'opportunity:other': other };
c.d.modelo_a_snapshot = JSON.stringify(s);
assert.match(pending(c).pending.join(' '), /lucros económicos já/);
other.economicCredits.rows[0].distributionParcel = 'other-distribution';
other.economicCredits.rows[0].taxDocument = row(c).taxDocument;
c.d.modelo_a_snapshot = JSON.stringify(s);
pending(c);
other.economicCredits.rows[0].taxAmount = '10';
row(c).taxAmount = '10';
row(c).grossUpIncluded = '6';
c.d.modelo_a_snapshot = JSON.stringify(s);
assert.deepEqual(calc(c).pending, []);
});
void test('economic and accepted carry increments compose:1408-12-8-50-200-100-500=538', () => {
const m = calc(economicCase(true));
assert.deepEqual(m.pending, []);
assert.equal(number(m.payable), 538);
assert.equal(number(m.creditCarry.afterInternational), 1338);
assert.equal(number(m.creditCarry.afterPec), 1038);
});
void test('economic priority leaves prior explicit allocations intact when remaining collecta becomes insufficient', () => {
const c = economicCase(true);
c.b.creditCarry.lots[0].eligible = '2000';
c.b.creditCarry.lots[0].selected = '1300';
c.b.creditCarry.currentPec = '0';
const before = structuredClone(c.b.creditCarry);
assert.match(pending(c).pending.join(' '), /ultrapassam a colecta/);
assert.deepEqual(c.b.creditCarry, before);
c.b.creditCarry.lots[0].selected = '1288';
const m = calc(c);
assert.deepEqual(m.pending, []);
assert.equal(number(m.recoverable), 500);
assert.equal(m.economicCredit.carryCreated, false);
});
void test('zero,absence and missing differ; earlier deliberate economic summary remains frozen and does not block detailed calculation', () => {
const c = economicCase();
c.b.internationalCredits.economic = {
state: 'known',
amount: '999',
reference: 'SYNTHETIC previous deliberate summary',
};
assert.equal(number(calc(c).payable), 688);
assert.equal(c.b.internationalCredits.economic.amount, '999');
c.b.economicCredits.state = 'absent';
pending(c);
c.b.economicCredits.rows = [];
assert.equal(number(calc(c).payable), 700);
c.b.economicCredits.state = '';
pending(c);
const z = economicCase();
Object.assign(row(z), {
taxAmount: '0',
proofAmount: '0',
grossUpIncluded: '0',
income: '0',
nationalLimit: '0',
});
assert.equal(number(calc(z).payable), 700);
});
void test('exact60% arithmetic and fractional quota never invent fiscal rounding', () => {
const c = economicCase();
Object.assign(row(c), {
taxAmount: '0.01',
proofAmount: '0.01',
grossUpIncluded: '0.006',
});
const m = calc(c);
assert.deepEqual(m.economicCredit.deducted, {
numerator: '3',
denominator: '500',
});
assert.deepEqual(m.payable, { numerator: '349997', denominator: '500' });
row(c).nationalLimit = '1/1000';
assert.deepEqual(calc(c).economicCredit.deducted, {
numerator: '1',
denominator: '1000',
});
});
void test('save/recover/history,HTML and dossier preserve current L6,original snapshots and accepted carry results', () => {
const c = economicCase(true),
prior = structuredClone(c.b);
delete prior.economicCredits;
c.d.modelo_a_snapshot = saveAnnualBook(
c.d,
recordAnnual(c.d, prior, '2026-10-28T12:00:00+02:00'),
);
const old = annualBook(c.d),
frozen = structuredClone(old.result),
base = JSON.parse(c.d.modelo_a_snapshot),
plan = c.d.business_plan_snapshot;
const next = prepareEconomicBook(old);
next.economicCredits = c.b.economicCredits;
c.d.modelo_a_snapshot = saveAnnualBook(
c.d,
recordAnnual(c.d, next, '2026-10-28T14:00:00+02:00'),
);
const back = annualBook(JSON.parse(JSON.stringify(c.d)));
assert.equal(annualCurrent(c.d, back), true);
assert.deepEqual(back.history, [frozen]);
assert.equal(number(back.result.model.payable), 538);
const after = JSON.parse(c.d.modelo_a_snapshot);
delete after.irpcAnnual;
delete base.irpcAnnual;
assert.deepEqual(after, base);
assert.equal(c.d.business_plan_snapshot, plan);
assert.match(annualHtml(c.d), /Crédito económico — antes do internacional/);
assert.match(annualHtml(c.d), /538.00/);
assert.match(
JSON.stringify(
createProjectDossierReport(c.d, {
selectedSections: new Set(['finance']),
}),
),
/Crédito económico/,
);
back.economicCredits.rows[0].nationalLimit = '5';
c.d.modelo_a_snapshot = saveAnnualBook(c.d, back);
assert.equal(annualCurrent(c.d, back), false);
assert.deepEqual(back.result, annualBook(c.d).result);
assert.throws(() => annualHtml(c.d), /fontes actuais/);
assert.match(annualReportRows(c.d).flat().join(' '), /Histórico/);
});
void test('malformed optional evidence and parcels are rejected without resetting snapshots', () => {
for (const mutate of [
(c) => (c.b.economicCredits.version = 2),
(c) => (row(c).previousUse = null),
(c) => (row(c).article40 = null),
(c) => (foreign(c).parcel = 1),
]) {
const c = economicCase(),
before = c.d.modelo_a_snapshot;
mutate(c);
assert.throws(() => saveAnnualBook(c.d, c.b), /recuperável/);
assert.equal(c.d.modelo_a_snapshot, before);
}
const c = internationalCase();
const once = prepareEconomicBook(c.b);
assert.equal(prepareEconomicBook(once), once);
});
void test('a partially identified document parcel remains recoverable and indeterminate rather than acquiring absent fields', () => {
const c = economicCase();
foreign(c).parcel = 'foreign-tax-line';
const model = pending(c);
c.d.modelo_a_snapshot = saveAnnualBook(c.d, recordAnnual(c.d, c.b));
const back = annualBook(JSON.parse(JSON.stringify(c.d)));
assert.deepEqual(calculateAnnual(c.d, back), back.result.model);
assert.equal(back.result.model.status, model.status);
});