176 lines
6.6 KiB
JavaScript
176 lines
6.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { internationalCase } from './helpers/irpc-international-case.mjs';
|
|
import { newPtMzRoyaltyPreparation } from '../../resources/js/lib/irpc-international-credit.ts';
|
|
import {
|
|
calculateAnnual,
|
|
recordAnnual,
|
|
saveAnnualBook,
|
|
annualBook,
|
|
annualCurrent,
|
|
annualHtml,
|
|
} from '../../resources/js/lib/irpc-annual-settlement.ts';
|
|
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
|
|
function treatyCase() {
|
|
const c = internationalCase();
|
|
Object.assign(c.b.internationalCredits.positions[0], {
|
|
country: 'PT',
|
|
qualificationCountry: 'PT',
|
|
incomeAmount: '40',
|
|
treaty: 'yes',
|
|
treatyMethod: 'ptMzRoyalty',
|
|
treatyReference:
|
|
'SYNTHETIC QA PT-MZ12/23(3)a actual royalty qualification, no real treaty decision',
|
|
treatyPreparation: {
|
|
...newPtMzRoyaltyPreparation(),
|
|
gross: '60',
|
|
from: '2026-01-01',
|
|
to: '2026-12-31',
|
|
reference:
|
|
'SYNTHETIC QA residence certificate, royalty contract and all conditions documented',
|
|
residentMz: 'yes',
|
|
beneficialOwner: 'yes',
|
|
sourcePortugal: 'yes',
|
|
payerResidentPt: 'yes',
|
|
noLinkedEstablishment: 'yes',
|
|
armLength: 'yes',
|
|
royaltyDefinition: 'yes',
|
|
nonDigital: 'yes',
|
|
},
|
|
});
|
|
return c;
|
|
}
|
|
void test('PT royalty credit derives a6 treaty ceiling from gross60 and leaves national fraction,paid tax and L6 separate', () => {
|
|
const c = treatyCase(),
|
|
before = c.d.modelo_a_snapshot,
|
|
m = calculateAnnual(c.d, c.b),
|
|
p = m.internationalCredit.positions[0];
|
|
assert.deepEqual(m.pending, []);
|
|
assert.deepEqual(p.treatyLimit, { numerator: '6', denominator: '1' });
|
|
assert.deepEqual(p.eligible, { numerator: '6', denominator: '1' });
|
|
assert.deepEqual(m.arithmeticBalance, {
|
|
numerator: '702',
|
|
denominator: '1',
|
|
});
|
|
assert.equal(c.d.modelo_a_snapshot, before);
|
|
});
|
|
void test('PT royalty matching rejects wrong country,unknown facts,expired coverage and contradictory gross without silently using the manual limit', () => {
|
|
for (const patch of [
|
|
{ country: 'ZA' },
|
|
{ treaty: 'no' },
|
|
{ treatyPreparation: { beneficialOwner: '' } },
|
|
{ treatyPreparation: { sourcePortugal: 'no' } },
|
|
{ treatyPreparation: { to: '2026-09-01' } },
|
|
{ treatyPreparation: { gross: '30' } },
|
|
{ treatyPreparation: { from: '2026-02-30' } },
|
|
]) {
|
|
const c = treatyCase(),
|
|
p = c.b.internationalCredits.positions[0];
|
|
const q = patch.treatyPreparation;
|
|
if (q) Object.assign(p.treatyPreparation, q);
|
|
else Object.assign(p, patch);
|
|
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
|
|
}
|
|
});
|
|
void test('PT royalty ceiling is exact and can be lower than paid tax without creating official use or refund', () => {
|
|
const c = treatyCase();
|
|
c.b.internationalCredits.positions[0].treatyPreparation.gross = '60.01';
|
|
const m = calculateAnnual(c.d, c.b);
|
|
assert.deepEqual(m.internationalCredit.positions[0].treatyLimit, {
|
|
numerator: '6001',
|
|
denominator: '1000',
|
|
});
|
|
assert.equal(m.internationalCredit.officialBalancesConsumed, false);
|
|
});
|
|
void test('PT royalty limit survives save,recovery and both report consumers; previous documented mode stays unchanged', () => {
|
|
const c = treatyCase(),
|
|
b = recordAnnual(c.d, c.b, '2026-11-10T17:00:00+02:00'),
|
|
d = JSON.parse(
|
|
JSON.stringify({
|
|
...c.d,
|
|
modelo_a_snapshot: saveAnnualBook(c.d, b),
|
|
}),
|
|
),
|
|
back = annualBook(d);
|
|
assert.equal(annualCurrent(d, back), true);
|
|
assert.deepEqual(
|
|
calculateAnnual(d, back).internationalCredit,
|
|
back.result.model.internationalCredit,
|
|
);
|
|
assert.match(annualHtml(d), /IRPC-PT-MZ-royalty-credit\/1/);
|
|
assert.match(
|
|
JSON.stringify(
|
|
createProjectDossierReport(d, {
|
|
selectedSections: new Set(['finance']),
|
|
generatedAt: '2026-11-10T17:00:00+02:00',
|
|
}),
|
|
),
|
|
/IRPC-PT-MZ-royalty-credit\/1/,
|
|
);
|
|
const old = internationalCase();
|
|
assert.equal(
|
|
calculateAnnual(old.d, old.b).internationalCredit.positions[0]
|
|
.treatyDerivation,
|
|
undefined,
|
|
);
|
|
});
|
|
|
|
void test('PT dividends use the2009 treaty10percent ceiling and interest uses ordinary11 conditions, preserving royalty evidence', () => {
|
|
for (const method of ['ptMzDividend', 'ptMzInterest']) {
|
|
const c = treatyCase(),
|
|
p = c.b.internationalCredits.positions[0];
|
|
p.treatyMethod = method;
|
|
Object.assign(p.treatyPreparation, {
|
|
capitalDefinition: 'yes',
|
|
governmentInterestExemption: 'no',
|
|
royaltyDefinition: '',
|
|
nonDigital: '',
|
|
...(method === 'ptMzDividend' ? { armLength: '' } : {}),
|
|
});
|
|
const m = calculateAnnual(c.d, c.b),
|
|
r = m.internationalCredit.positions[0];
|
|
assert.deepEqual(m.pending, []);
|
|
assert.deepEqual(r.treatyLimit, { numerator: '6', denominator: '1' });
|
|
assert.equal(r.treatyDerivation.nature, method);
|
|
assert.match(
|
|
r.treatyDerivation.source,
|
|
method === 'ptMzDividend' ? /art6/ : /11/,
|
|
);
|
|
const d = {
|
|
...c.d,
|
|
modelo_a_snapshot: saveAnnualBook(
|
|
c.d,
|
|
recordAnnual(c.d, c.b, '2026-11-10T17:10:00+02:00'),
|
|
),
|
|
};
|
|
assert.match(annualHtml(d), /IRPC-PT-MZ-capital-credit\/1/);
|
|
assert.match(
|
|
JSON.stringify(
|
|
createProjectDossierReport(d, {
|
|
selectedSections: new Set(['finance']),
|
|
generatedAt: '2026-11-10T17:10:00+02:00',
|
|
}),
|
|
),
|
|
/IRPC-PT-MZ-capital-credit\/1/,
|
|
);
|
|
}
|
|
});
|
|
void test('PT capital matching does not presume article11 governmental exemption or classification', () => {
|
|
for (const patch of [
|
|
{ capitalDefinition: '' },
|
|
{ governmentInterestExemption: '' },
|
|
{ governmentInterestExemption: 'yes' },
|
|
{ armLength: '' },
|
|
]) {
|
|
const c = treatyCase(),
|
|
p = c.b.internationalCredits.positions[0];
|
|
p.treatyMethod = 'ptMzInterest';
|
|
Object.assign(
|
|
p.treatyPreparation,
|
|
{ capitalDefinition: 'yes', governmentInterestExemption: 'no' },
|
|
patch,
|
|
);
|
|
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
|
|
}
|
|
});
|