408 lines
16 KiB
JavaScript
408 lines
16 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import crypto from 'node:crypto';
|
|
import { countryIsoCodes } from '../../resources/js/lib/country-iso-codes.ts';
|
|
import { internationalCase } from './helpers/irpc-international-case.mjs';
|
|
import {
|
|
calculateAnnual,
|
|
annualBook,
|
|
recordAnnual,
|
|
saveAnnualBook,
|
|
annualCurrent,
|
|
annualHtml,
|
|
annualReportRows,
|
|
prepareInternationalBook,
|
|
} from '../../resources/js/lib/irpc-annual-settlement.ts';
|
|
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
|
|
const value = (v) => (v ? Number(v.numerator) / Number(v.denominator) : null);
|
|
const now = '2026-10-27T17:00:00+02:00';
|
|
const calc = ({ d, b }) => calculateAnnual(d, 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.internationalCredit.deducted, null);
|
|
assert.equal(m.pecDeduction.deducted, null);
|
|
return m;
|
|
};
|
|
const position = (c) => c.b.internationalCredits.positions[0];
|
|
const proof = (c) => position(c).payments[0];
|
|
|
|
void test('country code projection exactly reuses the existing master and its source hash', () => {
|
|
const raw = Buffer.from(
|
|
fs
|
|
.readFileSync(
|
|
new URL('../../resources/data/iso3166.tab', import.meta.url),
|
|
'utf8',
|
|
)
|
|
.replace(/\r\n/g, '\n'),
|
|
);
|
|
const codes = raw
|
|
.toString('utf8')
|
|
.split(/\r?\n/)
|
|
.filter((l) => l && !l.startsWith('#'))
|
|
.map((l) => l.split('\t')[0]);
|
|
assert.deepEqual(countryIsoCodes, codes);
|
|
const source = fs.readFileSync(
|
|
new URL('../../resources/js/lib/country-iso-codes.ts', import.meta.url),
|
|
'utf8',
|
|
);
|
|
assert.ok(
|
|
source.includes(crypto.createHash('sha256').update(raw).digest('hex')),
|
|
);
|
|
});
|
|
void test('10 paid capped at documented national8 precedes PEC200/PPC500:1408-8-200-500=700', () => {
|
|
const m = calc(internationalCase());
|
|
assert.deepEqual(m.pending, []);
|
|
const p = m.internationalCredit.positions[0];
|
|
assert.equal(value(p.paid), 10);
|
|
assert.equal(value(p.eligible), 8);
|
|
assert.equal(value(p.aboveLimit), 2);
|
|
assert.equal(value(m.internationalCredit.deducted), 8);
|
|
assert.equal(value(m.internationalCredit.afterCredit), 1400);
|
|
assert.equal(value(m.pecDeduction.deducted), 200);
|
|
assert.equal(value(m.payable), 700);
|
|
assert.equal(m.internationalCredit.carryCreated, false);
|
|
assert.equal(m.officialBalancesConsumed, false);
|
|
});
|
|
void test('documented treaty limit6 caps credit without country-based automatic entitlement', () => {
|
|
const c = internationalCase();
|
|
Object.assign(position(c), {
|
|
treaty: 'yes',
|
|
treatyLimit: '6',
|
|
treatyReference:
|
|
'SYNTHETIC QA convention/article/exercise/limit, not real treaty data',
|
|
});
|
|
const m = calc(c);
|
|
assert.equal(value(m.internationalCredit.deducted), 6);
|
|
assert.equal(value(m.payable), 702);
|
|
assert.equal(value(m.internationalCredit.positions[0].aboveLimit), 4);
|
|
position(c).treatyLimit = '';
|
|
pending(c);
|
|
position(c).treatyLimit = '6';
|
|
position(c).treatyReference = '';
|
|
pending(c);
|
|
});
|
|
void test('multiple actual receipts share one country limit;two countries keep separate limits', () => {
|
|
const c = internationalCase();
|
|
proof(c).amount = '6';
|
|
proof(c).proofAmount = '6';
|
|
position(c).payments.push({
|
|
...proof(c),
|
|
id: 'foreign-second',
|
|
document: 'OTHER-RECEIPT',
|
|
amount: '4',
|
|
proofAmount: '4',
|
|
});
|
|
assert.equal(value(calc(c).internationalCredit.deducted), 8);
|
|
const other = structuredClone(position(c));
|
|
other.id = 'country-pt';
|
|
other.country = 'PT';
|
|
other.qualificationCountry = 'PT';
|
|
other.nationalLimit = '4';
|
|
other.payments = [
|
|
{
|
|
...other.payments[0],
|
|
id: 'pt-tax',
|
|
document: 'PT-OTHER-RECEIPT',
|
|
proofAmount: '5',
|
|
amount: '5',
|
|
},
|
|
];
|
|
c.b.internationalCredits.positions.push(other);
|
|
assert.equal(value(calc(c).internationalCredit.deducted), 12);
|
|
assert.equal(value(calc(c).payable), 696);
|
|
});
|
|
void test('same country cannot multiply the national fraction across positions or other context maps', () => {
|
|
const a = internationalCase(),
|
|
copy = structuredClone(position(a));
|
|
copy.id = 'duplicate-country';
|
|
copy.payments[0].id = 'other-proof';
|
|
copy.payments[0].document = 'OTHER';
|
|
a.b.internationalCredits.positions.push(copy);
|
|
assert.match(pending(a).pending.join(' '), /país\/exercício/);
|
|
const b = internationalCase(),
|
|
other = structuredClone(b.b);
|
|
other.internationalCredits.positions[0].payments[0].id = 'elsewhere';
|
|
other.internationalCredits.positions[0].payments[0].document =
|
|
'ELSEWHERE-RECEIPT';
|
|
const s = JSON.parse(b.d.modelo_a_snapshot);
|
|
s.irpcAnnual = { 'opportunity:other': other };
|
|
b.d.modelo_a_snapshot = JSON.stringify(s);
|
|
assert.match(pending(b).pending.join(' '), /noutro mapa/);
|
|
});
|
|
void test('actual previous credit use reduces eligible credit,not gross tax or simulated history', () => {
|
|
const c = internationalCase();
|
|
position(c).previousUse.amount = '3';
|
|
let m = calc(c);
|
|
assert.equal(value(m.internationalCredit.positions[0].eligible), 8);
|
|
assert.equal(value(m.internationalCredit.positions[0].available), 5);
|
|
assert.equal(value(m.payable), 703);
|
|
position(c).previousUse.amount = '9';
|
|
assert.match(pending(c).pending.join(' '), /excede/);
|
|
position(c).previousUse = {
|
|
state: 'absent',
|
|
amount: '',
|
|
reference: 'QA no actual previous use',
|
|
};
|
|
assert.equal(value(calc(c).payable), 700);
|
|
});
|
|
void test('lack of collecta is separated from tax above eligibility limits and never refunds credit or PEC', () => {
|
|
const c = internationalCase('2000', '2000', '200', '0'),
|
|
m = calc(c);
|
|
assert.equal(m.status, 'balanced');
|
|
assert.equal(value(m.internationalCredit.deducted), 1408);
|
|
assert.equal(value(m.internationalCredit.insufficientCollecta), 592);
|
|
assert.equal(value(m.internationalCredit.positions[0].aboveLimit), 0);
|
|
assert.equal(value(m.pecDeduction.deducted), 0);
|
|
assert.equal(value(m.pecDeduction.remaining), 200);
|
|
assert.equal(value(m.recoverable), 0);
|
|
assert.equal(m.internationalCredit.countryAllocationCreated, false);
|
|
c.b.ppc = { ...internationalCase().b.ppc };
|
|
const recovered = calc(c);
|
|
assert.equal(value(recovered.recoverable), 500);
|
|
assert.equal(
|
|
value(recovered.internationalCredit.insufficientCollecta),
|
|
592,
|
|
);
|
|
assert.equal(recovered.internationalCredit.carryCreated, false);
|
|
});
|
|
void test('known zero,declared absence and missing retain distinct inputs and outcomes', () => {
|
|
const zero = internationalCase('0');
|
|
assert.equal(value(calc(zero).internationalCredit.deducted), 0);
|
|
assert.equal(value(calc(zero).payable), 708);
|
|
const a = internationalCase();
|
|
a.b.internationalCredits.state = 'absent';
|
|
a.b.internationalCredits.positions = [];
|
|
assert.equal(value(calc(a).payable), 708);
|
|
a.b.internationalCredits.state = '';
|
|
pending(a);
|
|
a.b.internationalCredits.state = 'known';
|
|
pending(a);
|
|
const b = internationalCase();
|
|
b.b.internationalCredits.state = 'absent';
|
|
pending(b);
|
|
position(b).previousUse = {
|
|
state: 'absent',
|
|
amount: '0',
|
|
reference: 'QA contradiction',
|
|
};
|
|
pending(b);
|
|
});
|
|
void test('country,entity,year,inclusion,current assessment,domestic fraction and convention require support', () => {
|
|
for (const patch of [
|
|
{ country: 'MZ' },
|
|
{ country: 'ZZ' },
|
|
{ country: '' },
|
|
{ country: 'PT' },
|
|
{ qualificationCountry: '' },
|
|
{ subjectNuit: '999999999' },
|
|
{ year: '2025' },
|
|
{ incomeIncluded: '' },
|
|
{ incomeIncluded: 'no' },
|
|
{ incomeAmount: '' },
|
|
{ incomeAmount: '0' },
|
|
{ incomeReference: '' },
|
|
{ nationalLimit: '' },
|
|
{ nationalLimitReference: '' },
|
|
{ assessmentKey: 'stale' },
|
|
{ treaty: '' },
|
|
{ treaty: 'no', treatyLimit: '0' },
|
|
{ treatyReference: '' },
|
|
]) {
|
|
const c = internationalCase();
|
|
Object.assign(position(c), patch);
|
|
pending(c);
|
|
}
|
|
for (const patch of [{ state: '' }, { amount: '' }, { reference: '' }]) {
|
|
const c = internationalCase();
|
|
Object.assign(position(c).previousUse, patch);
|
|
pending(c);
|
|
}
|
|
});
|
|
void test('actual foreign income tax proof is required,not projections,other taxes,wrong exercise or unsupported currency', () => {
|
|
for (const patch of [
|
|
{ effective: '' },
|
|
{ effective: 'no' },
|
|
{ incomeTax: '' },
|
|
{ incomeTax: 'no' },
|
|
{ taxReference: '' },
|
|
{ document: '' },
|
|
{ issuer: '' },
|
|
{ reference: '' },
|
|
{ subjectNuit: '999999999' },
|
|
{ year: '2025' },
|
|
{ date: '2026-02-30' },
|
|
{ date: '2025-09-30' },
|
|
{ currency: 'USD' },
|
|
{ amount: '10.01' },
|
|
{ amount: '0.001' },
|
|
]) {
|
|
const c = internationalCase();
|
|
Object.assign(proof(c), patch);
|
|
pending(c);
|
|
}
|
|
const c = internationalCase();
|
|
position(c).payments = [];
|
|
pending(c);
|
|
});
|
|
void test('payment date differs from income exercise only with explicit correspondence,never an automatic carry', () => {
|
|
const c = internationalCase();
|
|
proof(c).date = '2027-01-15';
|
|
pending(c);
|
|
proof(c).exerciseReference =
|
|
'SYNTHETIC QA own-exercise2026 assessment and payment relation';
|
|
const m = calc(c);
|
|
assert.equal(value(m.payable), 700);
|
|
assert.equal(m.internationalCredit.carryCreated, false);
|
|
});
|
|
void test('same physical foreign receipt cannot be duplicated,re-dated or used as PPC/PEC/RF', () => {
|
|
const a = internationalCase();
|
|
position(a).payments.push({
|
|
...proof(a),
|
|
id: 'other-date',
|
|
date: '2026-10-01',
|
|
});
|
|
pending(a);
|
|
for (const kind of ['ppc', 'pec', 'rf']) {
|
|
const c = internationalCase(
|
|
'10',
|
|
'8',
|
|
'200',
|
|
'500',
|
|
kind === 'rf' ? '300' : '0',
|
|
);
|
|
const physical =
|
|
kind === 'ppc'
|
|
? c.b.ppc.rows[0]
|
|
: kind === 'pec'
|
|
? c.b.pecPayments.rows[0]
|
|
: {
|
|
issuer: 'QA AT',
|
|
document: 'QA-RF-PEC-2026',
|
|
proofAmount: '300',
|
|
};
|
|
Object.assign(proof(c), {
|
|
issuer: physical.issuer,
|
|
document: physical.document,
|
|
proofAmount: physical.proofAmount,
|
|
});
|
|
assert.match(pending(c).pending.join(' '), /naturez|comprovativo/i);
|
|
}
|
|
});
|
|
void test('a foreign receipt cannot move country/entity across context maps;external changes invalidate current result', () => {
|
|
const c = internationalCase(),
|
|
other = structuredClone(c.b);
|
|
other.ppc.rows = [];
|
|
other.ppc.state = 'absent';
|
|
other.pecPayments.rows = [];
|
|
other.pecPayments.state = 'absent';
|
|
other.internationalCredits.positions[0].country = 'PT';
|
|
const s = JSON.parse(c.d.modelo_a_snapshot);
|
|
s.irpcAnnual = { 'opportunity:other': other };
|
|
c.d.modelo_a_snapshot = JSON.stringify(s);
|
|
pending(c);
|
|
other.internationalCredits.positions[0].payments[0].document = 'OTHER-PT';
|
|
c.d.modelo_a_snapshot = JSON.stringify(s);
|
|
assert.equal(value(calc(c).payable), 700);
|
|
c.d.modelo_a_snapshot = saveAnnualBook(c.d, recordAnnual(c.d, c.b, now));
|
|
const saved = annualBook(c.d);
|
|
assert.equal(annualCurrent(c.d, saved), true);
|
|
const edit = JSON.parse(c.d.modelo_a_snapshot);
|
|
edit.irpcAnnual[
|
|
'opportunity:other'
|
|
].internationalCredits.positions[0].country = 'ZA';
|
|
c.d.modelo_a_snapshot = JSON.stringify(edit);
|
|
assert.equal(annualCurrent(c.d, saved), false);
|
|
pending({ ...c, b: saved });
|
|
});
|
|
void test('economic/benefit positive or missing states block only the dependent annual balance,not known eligibility', () => {
|
|
for (const kind of ['economic', 'benefits'])
|
|
for (const patch of [
|
|
{ state: '' },
|
|
{ state: 'known', amount: '1' },
|
|
{ reference: '' },
|
|
]) {
|
|
const c = internationalCase();
|
|
Object.assign(c.b.internationalCredits[kind], patch);
|
|
const m = pending(c);
|
|
assert.equal(value(m.internationalCredit.positions[0].eligible), 8);
|
|
assert.equal(value(m.assessment.colecta), 1408);
|
|
}
|
|
});
|
|
void test('exact decimals and withholding are included once after credit and PEC', () => {
|
|
const c = internationalCase('10.25', '8.15', '200', '500', '300');
|
|
position(c).previousUse.amount = '3.01';
|
|
const m = calc(c);
|
|
assert.deepEqual(m.internationalCredit.deducted, {
|
|
numerator: '257',
|
|
denominator: '50',
|
|
});
|
|
assert.equal(value(m.payable), 402.86);
|
|
assert.equal(value(m.knownWithholdings), 300);
|
|
});
|
|
void test('documented fractional ceilings retain exact arithmetic without assumed tax rounding', () => {
|
|
const c = internationalCase('10', '1/3');
|
|
const m = calc(c);
|
|
assert.deepEqual(m.internationalCredit.deducted, {
|
|
numerator: '1',
|
|
denominator: '3',
|
|
});
|
|
assert.deepEqual(m.payable, { numerator: '2123', denominator: '3' });
|
|
position(c).nationalLimit = '1/0';
|
|
pending(c);
|
|
});
|
|
void test('prepare preserves deliberate prior summary and history;save/recover/report appends frozen records', () => {
|
|
const c = internationalCase(),
|
|
detail = structuredClone(c.b.internationalCredits);
|
|
delete c.b.internationalCredits;
|
|
const original = JSON.parse(c.d.modelo_a_snapshot),
|
|
plan = c.d.business_plan_snapshot;
|
|
c.d.modelo_a_snapshot = saveAnnualBook(c.d, recordAnnual(c.d, c.b, now));
|
|
const prior = structuredClone(annualBook(c.d).result);
|
|
assert.equal(value(prior.model.payable), 708);
|
|
let next = prepareInternationalBook(annualBook(c.d));
|
|
next.internationalCredits = detail;
|
|
c.d.modelo_a_snapshot = saveAnnualBook(c.d, recordAnnual(c.d, next, now));
|
|
const back = annualBook(JSON.parse(JSON.stringify(c.d)));
|
|
assert.deepEqual(back.history, [prior]);
|
|
assert.equal(annualCurrent(c.d, back), true);
|
|
assert.equal(value(back.result.model.payable), 700);
|
|
assert.deepEqual(back.credits, {
|
|
state: 'known',
|
|
amount: '0',
|
|
reference: 'QA créditos precedentes conhecidos zero',
|
|
});
|
|
const after = JSON.parse(c.d.modelo_a_snapshot);
|
|
delete after.irpcAnnual;
|
|
assert.deepEqual(after, original);
|
|
assert.equal(c.d.business_plan_snapshot, plan);
|
|
const html = annualHtml(c.d);
|
|
assert.match(html, /Crédito internacional — antes do PEC/);
|
|
assert.match(html, /700.00/);
|
|
assert.match(html, /1400.00/);
|
|
assert.match(
|
|
JSON.stringify(
|
|
createProjectDossierReport(c.d, {
|
|
selectedSections: new Set(['finance']),
|
|
}),
|
|
),
|
|
/Crédito internacional — ZA/,
|
|
);
|
|
const frozen = structuredClone(back.result);
|
|
back.internationalCredits.positions[0].nationalLimit = '7';
|
|
c.d.modelo_a_snapshot = saveAnnualBook(c.d, back);
|
|
assert.equal(annualCurrent(c.d, back), false);
|
|
assert.deepEqual(back.result, frozen);
|
|
assert.match(annualReportRows(c.d).flat().join(' '), /Histórico/);
|
|
assert.throws(() => annualHtml(c.d), /fontes actuais/);
|
|
});
|
|
void test('malformed optional international detail never resets existing snapshots', () => {
|
|
const c = internationalCase(),
|
|
snapshot = c.d.modelo_a_snapshot;
|
|
proof(c).incomeTax = null;
|
|
assert.throws(() => saveAnnualBook(c.d, c.b), /não recuperável/);
|
|
assert.equal(c.d.modelo_a_snapshot, snapshot);
|
|
});
|