248 lines
8.5 KiB
JavaScript
248 lines
8.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
newObjectiveImport,
|
|
objectiveImportTreatments,
|
|
evaluateObjectiveImport,
|
|
reuseObjectiveImport,
|
|
recordObjectiveImports,
|
|
saveObjectiveImportBook,
|
|
objectiveImportBook,
|
|
objectiveImportCurrent,
|
|
objectiveImportReportRows,
|
|
} from '../../resources/js/lib/iva-objective-imports.ts';
|
|
import { annexIEntries } from '../../resources/js/lib/iva-annex-i.ts';
|
|
const frozen = JSON.parse(
|
|
fs.readFileSync(
|
|
'tests/frontend/fixtures/iva-objective-imports-preserved.json',
|
|
'utf8',
|
|
),
|
|
),
|
|
prior = JSON.parse(frozen.modelo_a_snapshot);
|
|
const draft = {
|
|
...frozen,
|
|
context_opportunity: 'opportunity:361',
|
|
project_title: 'SYNTHETIC QA — Importações objectivas / Manica',
|
|
};
|
|
function row(treatment, id = treatment) {
|
|
const r = {
|
|
...newObjectiveImport(id, 'MZN'),
|
|
description: 'SYNTHETIC QA bens ' + treatment,
|
|
period: '2026-10',
|
|
importer: 'SYNTHETIC QA importador',
|
|
documentRef: 'SYNTHETIC QA DU/previsão',
|
|
documentDate: '2026-10-01',
|
|
scope: 'SYNTHETIC QA bens/operação/período',
|
|
evidence: 'SYNTHETIC QA factos/pressupostos da correspondência',
|
|
definitive: 'yes',
|
|
goods: 'yes',
|
|
sameGoods: 'yes',
|
|
internalApplicable: 'yes',
|
|
};
|
|
const rule = objectiveImportTreatments.find((t) => t.id === treatment);
|
|
r.reference = {
|
|
...r.reference,
|
|
treatment,
|
|
confirmed: rule?.conditions.map((_, i) => i) ?? [],
|
|
annexIItem: 'annexI-2022-001',
|
|
annexIOnly: true,
|
|
pharmaAnnexItem: 'annexIII-2022-001',
|
|
};
|
|
return r;
|
|
}
|
|
const rows = objectiveImportTreatments.map((t) => row(t.id));
|
|
for (const r of rows)
|
|
void test(
|
|
'P046 ' +
|
|
r.reference.treatment +
|
|
' explicit correspondence,without domestic sale or deduction',
|
|
() => {
|
|
const v = evaluateObjectiveImport(r, 'MZN');
|
|
assert.equal(v.status, 'exempt');
|
|
assert.equal(v.importVat, '0.00');
|
|
assert.equal(v.deduction, null);
|
|
assert.match(v.source, /12\(1\)a/);
|
|
assert.match(v.source, /9\(/);
|
|
},
|
|
);
|
|
void test('P046 documentary and factual unknowns remain indeterminate; explicit failed prerequisites remain distinct', () => {
|
|
for (const patch of [
|
|
{ period: '2025-12' },
|
|
{ period: '2026-13' },
|
|
{ currency: 'USD' },
|
|
{ origin: '' },
|
|
{ description: '' },
|
|
{ importer: '' },
|
|
{ documentRef: '' },
|
|
{ documentDate: '2026-02-30' },
|
|
{ scope: '' },
|
|
{ evidence: '' },
|
|
{ definitive: '' },
|
|
{ goods: '' },
|
|
{ sameGoods: '' },
|
|
{ internalApplicable: '' },
|
|
]) {
|
|
const v = evaluateObjectiveImport({ ...rows[0], ...patch }, 'MZN');
|
|
assert.equal(v.status, 'indeterminate');
|
|
assert.equal(v.importVat, null);
|
|
}
|
|
for (const field of [
|
|
'definitive',
|
|
'goods',
|
|
'sameGoods',
|
|
'internalApplicable',
|
|
]) {
|
|
const v = evaluateObjectiveImport({ ...rows[0], [field]: 'no' }, 'MZN');
|
|
assert.equal(v.status, 'not_applicable');
|
|
assert.equal(v.importVat, null);
|
|
}
|
|
for (const t of [
|
|
'export_goods',
|
|
'public_health',
|
|
'private_education',
|
|
'production_agriculture',
|
|
'temporary_sugar',
|
|
'unknown',
|
|
])
|
|
assert.equal(
|
|
evaluateObjectiveImport(row(t), 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
});
|
|
void test('P046 does not infer conditions,annex qualifiers or extend another reference to the goods', () => {
|
|
for (const r of rows)
|
|
for (const condition of r.reference.confirmed) {
|
|
const v = evaluateObjectiveImport(
|
|
{
|
|
...r,
|
|
reference: {
|
|
...r.reference,
|
|
confirmed: r.reference.confirmed.filter(
|
|
(n) => n !== condition,
|
|
),
|
|
},
|
|
},
|
|
'MZN',
|
|
);
|
|
assert.equal(v.status, 'indeterminate');
|
|
assert.equal(v.importVat, null);
|
|
}
|
|
for (const field of ['annexIItem', 'pharmaAnnexItem']) {
|
|
const t =
|
|
field === 'annexIItem'
|
|
? 'annexI_goods'
|
|
: 'pharma_manufacturing_inputs';
|
|
assert.equal(
|
|
evaluateObjectiveImport(
|
|
{
|
|
...row(t),
|
|
reference: { ...row(t).reference, [field]: 'missing' },
|
|
},
|
|
'MZN',
|
|
).status,
|
|
'indeterminate',
|
|
);
|
|
}
|
|
const overlap = row('annexI_goods');
|
|
overlap.reference.annexIItem = 'annexI-2022-013';
|
|
overlap.reference.annexIOnly = undefined;
|
|
assert.equal(
|
|
evaluateObjectiveImport(overlap, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
overlap.reference.annexIOnly = true;
|
|
assert.equal(evaluateObjectiveImport(overlap, 'MZN').status, 'exempt');
|
|
const required = row('annexI_goods');
|
|
required.reference.annexIItem = annexIEntries.find(
|
|
(a) => a.relatedRequired,
|
|
).id;
|
|
assert.equal(
|
|
evaluateObjectiveImport(required, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
});
|
|
void test('P046 reuse fills only missing fields and never copies confirmations or overwrites deliberate edits', () => {
|
|
const source = {
|
|
...rows[0].reference,
|
|
id: 'source',
|
|
description: 'source description',
|
|
period: '2026-11',
|
|
evidence: 'source evidence',
|
|
treatment: 'annexI_goods',
|
|
annexIItem: 'annexI-2022-001',
|
|
};
|
|
const empty = newObjectiveImport('reuse', 'MZN'),
|
|
copy = reuseObjectiveImport(empty, source);
|
|
assert.equal(copy.description, source.description);
|
|
assert.equal(copy.period, source.period);
|
|
assert.equal(copy.reference.treatment, 'annexI_goods');
|
|
assert.deepEqual(copy.reference.confirmed, []);
|
|
assert.equal(copy.internalApplicable, '');
|
|
const original = structuredClone(rows[0]),
|
|
edited = reuseObjectiveImport(original, source);
|
|
assert.equal(edited.description, original.description);
|
|
assert.equal(edited.evidence, original.evidence);
|
|
assert.deepEqual(edited.reference, original.reference);
|
|
assert.equal(edited.reusedFrom, 'source');
|
|
});
|
|
let book = recordObjectiveImports(draft, { rows });
|
|
draft.modelo_a_snapshot = saveObjectiveImportBook(draft, book);
|
|
void test('P046 versions,history,project isolation and every accepted book remain intact', () => {
|
|
assert.equal(objectiveImportCurrent(draft, book), true);
|
|
const changed = {
|
|
...book,
|
|
rows: book.rows.map((r, i) => (i ? r : { ...r, scope: 'changed' })),
|
|
};
|
|
assert.equal(objectiveImportCurrent(draft, changed), false);
|
|
const next = recordObjectiveImports(draft, changed);
|
|
assert.equal(next.history.length, 1);
|
|
assert.deepEqual(next.history[0], book.result);
|
|
assert.notEqual(next.result.sourceKey, book.result.sourceKey);
|
|
assert.equal(
|
|
objectiveImportBook({
|
|
...draft,
|
|
context_opportunity: 'opportunity:999',
|
|
}).rows.length,
|
|
0,
|
|
);
|
|
assert.deepEqual(
|
|
prior,
|
|
Object.fromEntries(
|
|
Object.entries(JSON.parse(draft.modelo_a_snapshot)).filter(
|
|
([key]) => key !== 'objectiveImports',
|
|
),
|
|
),
|
|
);
|
|
assert.throws(() =>
|
|
objectiveImportBook({
|
|
...draft,
|
|
modelo_a_snapshot: '{"version":1,"books":{},"objectiveImports":[]}',
|
|
}),
|
|
);
|
|
assert.match(objectiveImportReportRows(draft)[0][3], /versão1/);
|
|
assert.match(
|
|
objectiveImportReportRows(draft)[0][3],
|
|
/sem alteração dos livros internos/,
|
|
);
|
|
book = recordObjectiveImports(draft, book);
|
|
draft.modelo_a_snapshot = saveObjectiveImportBook(draft, book);
|
|
});
|
|
void test('P046 final fixture keeps digital formalities and travel fiscal limitations visible', () => {
|
|
const s = JSON.parse(draft.modelo_a_snapshot);
|
|
assert.equal(
|
|
s.digitalOperations['opportunity:359'].result.rows[0].procedure,
|
|
'regulation_pending',
|
|
);
|
|
for (const p of s.travelOperations['opportunity:360'].result.periods) {
|
|
assert.equal(p.vat, null);
|
|
assert.equal(p.deduction, null);
|
|
}
|
|
assert.equal(book.result.rows.length, 28);
|
|
if (process.env.IVA_OBJECTIVE_IMPORT_FIXTURE)
|
|
fs.writeFileSync(
|
|
process.env.IVA_OBJECTIVE_IMPORT_FIXTURE,
|
|
JSON.stringify(draft),
|
|
);
|
|
});
|