Files
Investidor-V2/tests/frontend/iva-import-development.test.mjs
T

307 lines
10 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {
newImportExemption,
evaluateImportExemption,
recordImportExemptions,
saveImportExemptionBook,
importExemptionBook,
importExemptionCurrent,
importExemptionRules,
importDevelopmentSource,
importDevelopmentFields,
} from '../../resources/js/lib/iva-import-exemptions.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const frozen = JSON.parse(
fs.readFileSync(
new URL('./fixtures/iva-g6h-preserved-inputs.json', import.meta.url),
'utf8',
),
);
const rules = importExemptionRules.filter((r) => r.branch === 'P060');
const row = (rule) => ({
...newImportExemption('g6h-' + rule.id, 'MZN'),
treatment: rule.id,
description: 'SYNTHETIC QA materiais/equipamentos projecto ONU',
period: '2026-12',
declaredValue: '5000',
importer: 'SYNTHETIC QA entidade promotora',
documentRef: 'SYNTHETIC QA G6H ' + rule.id,
documentDate: '2026-11-14',
evidence:
'SYNTHETIC QA pressupostos expressos; concessão aduaneira no plano e lista aprovada; não documento real',
...Object.fromEntries(
importDevelopmentFields.map(([key, label]) => [
key,
'SYNTHETIC QA ' +
label +
';operação2026-12/bens A;pressuposto expresso',
]),
),
...(rule.id === 'un_development_reduction'
? {
developmentReductionPercent: '50',
developmentNormalVat: '800',
developmentNormalVatRef:
'SYNTHETIC QA IVA sem benefício informado, não calculado da base pelo portal',
}
: {}),
conditions: Object.fromEntries(
rule.conditions.map(([key]) => [key, 'yes']),
),
});
const draft = () => ({
...structuredClone(frozen),
context_opportunity: 'opportunity:338',
project_title: 'SYNTHETIC QA — G6H / Projecto de desenvolvimento',
});
void test('P060 own funding,accreditation,destination,decision,list/plan and customs conditions;unknown/no never produce exempt zero', () => {
assert.equal(rules.length, 2);
assert.match(importDevelopmentSource, /12\(4\)/);
for (const rule of rules) {
const input = row(rule),
ok = evaluateImportExemption(input, 'MZN');
assert.equal(
ok.importVat,
rule.id === 'un_development_exemption' ? '0.00' : '400.00',
);
assert.equal(
ok.status,
rule.id === 'un_development_exemption' ? 'exempt' : 'reduced',
);
assert.equal(ok.serviceVat, undefined);
for (const [key] of rule.conditions)
for (const value of ['', 'unknown', 'no']) {
const r = evaluateImportExemption(
{
...input,
conditions: { ...input.conditions, [key]: value },
},
'MZN',
);
assert.equal(
r.status,
value === 'no' ? 'not_applicable' : 'indeterminate',
);
assert.equal(r.importVat, null);
}
for (const [key] of importDevelopmentFields)
assert.equal(
evaluateImportExemption({ ...input, [key]: '' }, 'MZN')
.importVat,
null,
);
for (const patch of [
{ period: '2025-12' },
{ documentDate: '2026-02-30' },
{ currency: 'USD' },
{ documentRef: '' },
{ evidence: '' },
])
assert.equal(
evaluateImportExemption({ ...input, ...patch }, 'MZN')
.importVat,
null,
);
}
});
void test('partial benefit is exact proportion of supplied VAT,not a VAT/customs rate or full exemption;missing is not zero', () => {
const input = row(rules[1]);
for (const [normal, percent, expected] of [
['800', '25', '600.00'],
['800', '75', '200.00'],
['1.234567', '33.333333', '0.82304467078189'],
['999999999999999.999999', '99.999999', '9999999.99999999999999'],
['0', '50', '0.00'],
]) {
const r = evaluateImportExemption(
{
...input,
developmentNormalVat: normal,
developmentReductionPercent: percent,
},
'MZN',
);
assert.equal(r.status, 'reduced');
assert.equal(r.importVat, expected);
assert.ok(!r.reason.includes('%/100'));
}
for (const patch of [
{ developmentReductionPercent: '' },
{ developmentReductionPercent: '-1' },
{ developmentReductionPercent: '101' },
{ developmentReductionPercent: '100' },
{ developmentReductionPercent: '0.0000001' },
{ developmentNormalVat: '' },
{ developmentNormalVat: '-1' },
{ developmentNormalVat: 'NaN' },
{ developmentNormalVatRef: '' },
])
assert.equal(
evaluateImportExemption({ ...input, ...patch }, 'MZN').importVat,
null,
);
assert.equal(
evaluateImportExemption(
{ ...input, developmentReductionPercent: '0' },
'MZN',
).status,
'not_applicable',
);
const full = row(rules[0]);
assert.equal(
evaluateImportExemption(
{
...full,
developmentNormalVat: '',
developmentReductionPercent: '50',
},
'MZN',
).importVat,
'0.00',
'hidden stale partial fields do not override full-rights condition',
);
assert.equal(
evaluateImportExemption({ ...full, treatment: rules[1].id }, 'MZN')
.status,
'indeterminate',
'switch does not inherit own rights-reduction eligibility',
);
});
void test('save/recovery/report keep77 delivered branches and partial P084/P085 exact;new contexts/history and reference edits isolated', () => {
const d = draft(),
prior = JSON.parse(d.modelo_a_snapshot);
let book = recordImportExemptions(d, {
rows: rules.map((rule) => ({ ...row(rule), conditions: {} })),
});
book = recordImportExemptions(d, {
...book,
rows: rules.map((rule) => ({
...row(rule),
conditions: {
...row(rule).conditions,
developmentFavourableDecision: 'no',
},
})),
});
book = recordImportExemptions(d, { ...book, rows: rules.map(row) });
assert.equal(book.history.length, 2);
assert.ok(
book.history.every((h) => h.rows.every((r) => r.importVat === null)),
);
assert.ok(importExemptionCurrent(d, book));
assert.match(book.result.sourceKey, /import-un-development\/1/);
for (const field of [
'developmentDecisionRef',
'developmentListRef',
'developmentPlanRef',
'developmentScope',
'developmentRightsRef',
'developmentReductionPercent',
'developmentNormalVat',
])
assert.ok(
!importExemptionCurrent(d, {
...book,
rows: book.rows.map((r) => ({ ...r, [field]: 'changed' })),
}),
);
assert.ok(
!importExemptionCurrent(
{ ...d, context_opportunity: 'opportunity:339' },
book,
),
);
d.modelo_a_snapshot = saveImportExemptionBook(d, book);
assert.deepEqual(importExemptionBook(JSON.parse(JSON.stringify(d))), book);
const next = JSON.parse(d.modelo_a_snapshot);
assert.deepEqual(
{ ...next, importExemptions: prior.importExemptions },
prior,
);
for (const [scope, previous] of Object.entries(prior.importExemptions)) {
assert.deepEqual(next.importExemptions[scope], previous);
assert.ok(
importExemptionCurrent(
{ ...d, context_opportunity: scope },
previous,
),
);
}
assert.equal(
next.importExemptions['opportunity:337'].result.rows[0].importVat,
'0.00',
);
assert.equal(
next.importExemptions['opportunity:336'].result.rows[0].serviceVat,
'0.00',
);
assert.equal(
next.importExemptions['opportunity:336'].result.rows[0].importVat,
null,
);
assert.equal(
next.books['opportunity:329'].result.periods[0].fields['11'],
null,
);
const report = JSON.stringify(
createProjectDossierReport(d, {
selectedSections: new Set(['finance']),
version: 'QA G6H',
}),
);
for (const token of [
'P060',
'12(2)(c)',
'12(4)',
'400.00',
'opportunity:338',
'Manica',
'2026-12',
'Lista discriminada aprovada',
'Plano de importações',
'Redução proporcional',
'campo11',
])
assert.ok(report.includes(token), token);
if (process.env.IVA_G6H_CALCULATED)
fs.writeFileSync(process.env.IVA_G6H_CALCULATED, JSON.stringify(d));
});
void test('optional fields retain documents when switching,while malformed references cannot overwrite saved originals', () => {
const d = draft(),
original = d.modelo_a_snapshot;
for (const key of [
...importDevelopmentFields.map(([key]) => key),
'developmentReductionPercent',
'developmentNormalVat',
'developmentNormalVatRef',
])
assert.throws(
() =>
saveImportExemptionBook(d, {
rows: [{ ...row(rules[1]), [key]: 42 }],
}),
/Referências do projecto de desenvolvimento/,
);
assert.equal(d.modelo_a_snapshot, original);
const changed = { ...row(rules[1]), treatment: 'un_development_exemption' };
d.modelo_a_snapshot = saveImportExemptionBook(d, { rows: [changed] });
assert.equal(
importExemptionBook(d).rows[0].developmentReductionPercent,
'50',
);
assert.equal(
importExemptionBook(d).rows[0].developmentPlanRef,
changed.developmentPlanRef,
);
assert.equal(
evaluateImportExemption(changed, 'MZN').status,
'indeterminate',
);
});