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

214 lines
7.3 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,
importInvestmentSource,
} 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-g6g-preserved-inputs.json', import.meta.url),
'utf8',
),
);
const rule = importExemptionRules.find((r) => r.branch === 'P056');
const row = () => ({
...newImportExemption('g6g-equipment', 'MZN'),
treatment: rule.id,
description: 'SYNTHETIC QA equipamento industrial classe K',
period: '2026-12',
declaredValue: '5000',
goodsCode: 'SYNTHETIC QA código não determina classe',
importer: 'SYNTHETIC QA empreendimento',
documentRef: 'SYNTHETIC QA G6G importação',
documentDate: '2026-11-14',
investmentAuthorizationRef:
'SYNTHETIC QA autorização A, pressuposto expresso',
investmentScope:
'SYNTHETIC QA equipamento industrial desta operação,2026-12,condições A; não alargar a outros bens',
evidence:
'SYNTHETIC QA classificação K e destino ao empreendimento autorizado; projecção, não documento real',
conditions: Object.fromEntries(
rule.conditions.map(([key]) => [key, 'yes']),
),
});
const draft = () => ({
...structuredClone(frozen),
context_opportunity: 'opportunity:337',
project_title: 'SYNTHETIC QA — G6G / Equipamento de investimento',
});
void test('P056 needs equipment,class K,authorization and own destination; sector/code/request alone cannot yield exemption', () => {
assert.equal(rule.article, '12(1)(k)');
assert.match(importInvestmentSource, /Lei10\/2025/);
for (const origin of ['projected', 'effective'])
assert.equal(
evaluateImportExemption({ ...row(), origin }, 'MZN').importVat,
'0.00',
);
for (const [key] of rule.conditions)
for (const value of ['', 'unknown', 'no']) {
const r = evaluateImportExemption(
{ ...row(), conditions: { ...row().conditions, [key]: value } },
'MZN',
);
assert.equal(
r.status,
value === 'no' ? 'not_applicable' : 'indeterminate',
);
assert.equal(r.importVat, null);
assert.equal(r.serviceVat, undefined);
}
for (const patch of [
{ investmentAuthorizationRef: '' },
{ investmentScope: '' },
{ documentRef: '' },
{ evidence: '' },
{ documentDate: '2026-02-30' },
{ period: '2025-12' },
{ currency: 'USD' },
])
assert.equal(
evaluateImportExemption({ ...row(), ...patch }, 'MZN').importVat,
null,
);
const presented = {
...row(),
investmentAuthorizationRef: 'Pedido apresentado; ainda sem autorização',
conditions: { ...row().conditions, investmentAuthorized: 'no' },
};
assert.equal(
evaluateImportExemption(presented, 'MZN').status,
'not_applicable',
);
assert.equal(
evaluateImportExemption({ ...row(), conditions: {} }, 'MZN').status,
'indeterminate',
);
});
void test('P056 preserves all delivered books,services,partial offer states and history; own edits/context invalidate only current result', () => {
const d = draft(),
prior = JSON.parse(d.modelo_a_snapshot);
let book = recordImportExemptions(d, {
rows: [{ ...row(), conditions: {} }],
});
book = recordImportExemptions(d, {
...book,
rows: [
{
...row(),
conditions: { ...row().conditions, investmentAuthorized: 'no' },
},
],
});
book = recordImportExemptions(d, { ...book, rows: [row()] });
assert.equal(book.history.length, 2);
assert.ok(book.history.every((h) => h.rows[0].importVat === null));
assert.ok(importExemptionCurrent(d, book));
assert.match(book.result.sourceKey, /import-investment-equipment\/1/);
for (const patch of [
{ investmentScope: 'another operation' },
{ investmentAuthorizationRef: 'different authorization' },
{ treatment: 'fire_brigade_vehicle' },
])
assert.ok(
!importExemptionCurrent(d, {
...book,
rows: [{ ...row(), ...patch }],
}),
);
assert.ok(
!importExemptionCurrent(
{ ...d, context_opportunity: 'opportunity:338' },
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: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 G6G',
}),
);
for (const token of [
'P056',
'12(1)(k)',
'5000',
'opportunity:337',
'Manica',
'2026-12',
'autorização A',
'não alargar',
'campo11',
])
assert.ok(report.includes(token), token);
if (process.env.IVA_G6G_CALCULATED)
fs.writeFileSync(process.env.IVA_G6G_CALCULATED, JSON.stringify(d));
});
void test('investment references survive treatment switches;malformed writes preserve originals and do not require new fields on delivered rows', () => {
const d = draft(),
original = d.modelo_a_snapshot;
for (const field of ['investmentAuthorizationRef', 'investmentScope'])
assert.throws(
() =>
saveImportExemptionBook(d, {
rows: [{ ...row(), [field]: 42 }],
}),
/Referências do investimento/,
);
assert.equal(d.modelo_a_snapshot, original);
const changed = {
...row(),
treatment: 'central_bank_gold',
conditions: { ...row().conditions, gold: 'yes', centralBank: 'yes' },
};
d.modelo_a_snapshot = saveImportExemptionBook(d, { rows: [changed] });
assert.equal(
importExemptionBook(d).rows[0].investmentScope,
row().investmentScope,
);
assert.equal(evaluateImportExemption(changed, 'MZN').importVat, '0.00');
assert.ok(
!importExemptionCurrent(
{ ...d, context_opportunity: 'opportunity:338' },
{ rows: [row()] },
),
);
});