Files
Investidor-V2/tests/frontend/iva-annex-i.test.mjs
T

269 lines
9.6 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import fs from 'node:fs';
import {
annexIEntries,
annexIVersion,
} from '../../resources/js/lib/iva-annex-i.ts';
import {
operationTreatments,
newSalesOperation,
evaluateSalesOperation,
continueAnnexIOperation,
recordSales,
saveSalesBook,
salesBook,
salesCurrent,
} from '../../resources/js/lib/iva-operations.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const rule = operationTreatments.find((t) => t.id === 'annexI_goods');
const seed = () =>
JSON.parse(
fs.readFileSync(
new URL('./fixtures/iva-pharma-inputs.json', import.meta.url),
'utf8',
),
);
const operation = (entry, i = 0) => ({
...newSalesOperation(`g2l-${i}`, '2026-09', 'MZN'),
description: `SYNTHETIC QA ${entry.code} ${entry.id}`,
establishment: 'SYNTHETIC QA estabelecimento Manica',
amount: '100',
basis: i % 2 ? 'included' : 'net',
treatment: rule.id,
annexIItem: entry.id,
confirmed: rule.conditions.map((_, n) => n),
evidence:
'SYNTHETIC QA: correspondência código/designação e qualificadores da posição expressamente pressupostos; não é classificação aduaneira ou certificação',
});
function fixture() {
const draft = seed();
draft.context_opportunity = 'opportunity:321';
draft.project_title = 'SYNTHETIC QA — G2L Anexo I';
const codes = [
'0306.36.10',
'3102.10.00',
'1007.10.00',
'8501.61.00',
'8701.95.00',
'8201.50.00',
'0702.00.00',
'3808.91.00',
'1101.00.00',
'0402.21.10',
];
const rows = codes.map((code, i) => {
const entry = annexIEntries.find((e) => e.code === code);
let row = operation(entry, i);
if (entry.relatedRequired) {
row = continueAnnexIOperation(row, entry.relatedTreatments[0]);
row.confirmed = operationTreatments
.find((t) => t.id === row.treatment)
.conditions.map((_, n) => n);
} else if (entry.relatedTreatments) {
row.annexIOnly = true;
row.evidence +=
code === '1101.00.00'
? '; mistura de trigo com centeio, não farinha de trigo simples'
: '; leite para utilização industrial, sem destino a lactente até um ano';
}
return row;
});
const book = recordSales(draft, {
currency: 'MZN',
rows,
periods: [{ period: '2026-09', complete: true }],
});
draft.modelo_a_snapshot = saveSalesBook(draft, book);
return { draft, book };
}
void test('AnexoI has 172 distinct documentary positions, own qualifiers, cross-page text and five contextual tractor entries', () => {
assert.equal(annexIEntries.length, 172);
assert.equal(new Set(annexIEntries.map((e) => e.code)).size, 172);
assert.equal(new Set(annexIEntries.map((e) => e.id)).size, 172);
const scissors = annexIEntries.find((e) => e.code === '8201.50.00');
assert.equal(scissors.pdfPage, 8);
assert.equal(scissors.lastPdfPage, 9);
assert.match(scissors.label, /uma das mãos/);
assert.equal(
annexIEntries.filter((e) => e.context === 'Outros tractores').length,
5,
);
assert.equal(
annexIEntries
.find((e) => e.code === '8701.30.00')
.label.includes('Outros tractores'),
false,
);
for (const [i, entry] of annexIEntries.entries()) {
const row = { ...operation(entry, i), annexIOnly: true },
r = evaluateSalesOperation(row, 'MZN');
assert.equal(r.vat, entry.relatedRequired ? null : '0.00');
if (!entry.relatedRequired) {
assert.equal(r.field, '07');
assert.equal(r.gross, '100.00');
}
for (const token of [
entry.id,
entry.code,
entry.label,
`PDF${entry.pdfPage}`,
annexIVersion,
])
assert.ok(r.source.includes(token), token);
}
});
void test('P035 requires actual position and qualifiers; overlapping descriptions require explicit applicability, never silently field07', () => {
const { draft, book } = fixture(),
row = book.rows[0];
for (const missing of row.confirmed)
assert.equal(
evaluateSalesOperation(
{
...row,
confirmed: row.confirmed.filter((n) => n !== missing),
},
'MZN',
).vat,
null,
);
for (const patch of [
{ annexIItem: undefined },
{ annexIItem: '' },
{ annexIItem: '0306.36.10' },
{ annexIItem: 'annexIII-2022-001' },
{ evidence: '' },
{ establishment: '' },
{ amount: '' },
{ period: '2025-09' },
{ sourceCurrency: 'USD' },
])
assert.equal(
evaluateSalesOperation({ ...row, ...patch }, 'MZN').vat,
null,
);
assert.equal(evaluateSalesOperation(row, 'USD').vat, null);
const overlaps = annexIEntries.filter((e) => e.relatedTreatments);
assert.equal(overlaps.length, 13);
assert.equal(overlaps.filter((e) => e.relatedRequired).length, 3);
for (const entry of overlaps) {
const pending = operation(entry);
assert.equal(evaluateSalesOperation(pending, 'MZN').vat, null);
assert.equal(
evaluateSalesOperation({ ...pending, annexIOnly: true }, 'MZN').vat,
entry.relatedRequired ? null : '0.00',
);
}
const incomplete = recordSales(draft, {
...book,
rows: [{ ...row, annexIItem: '' }],
});
assert.equal(incomplete.result.periods[0].fields['07'], null);
assert.deepEqual(incomplete.history.at(-1), book.result);
});
void test('explicit continuation reuses existing treatment identity, preserves money/origin/annex and requires new conditions', () => {
for (const entry of annexIEntries.filter((e) => e.relatedTreatments)) {
for (const target of entry.relatedTreatments) {
const before = operation(entry),
after = continueAnnexIOperation(before, target),
targetRule = operationTreatments.find((t) => t.id === target);
assert.equal(after.treatment, target);
assert.equal(after.annexIItem, entry.id);
assert.deepEqual(after.confirmed, []);
assert.ok(after.source.startsWith(before.source));
assert.ok(after.source.includes(entry.id));
for (const key of [
'id',
'period',
'amount',
'basis',
'sourceCurrency',
'sourcePeriod',
'establishment',
'description',
'evidence',
])
assert.equal(after[key], before[key], key);
assert.equal(evaluateSalesOperation(after, 'MZN').vat, null);
const r = evaluateSalesOperation(
{ ...after, confirmed: targetRule.conditions.map((_, n) => n) },
'MZN',
);
assert.equal(r.field, '05');
assert.equal(r.vat, '0.00');
}
}
assert.throws(() =>
continueAnnexIOperation(operation(annexIEntries[0]), 'general'),
);
const e = annexIEntries.find((v) => v.code === '0702.00.00');
assert.throws(() =>
continueAnnexIOperation(
{ ...operation(e), treatment: 'listed_fresh_chilled_tomato' },
'listed_fresh_chilled_tomato',
),
);
});
void test('G2L recovery/report preserve twelve current books including G2K and calendar, without recalculation', () => {
const { draft, book } = fixture(),
original = seed(),
old = JSON.parse(original.modelo_a_snapshot).salesOperations;
const recovered = JSON.parse(JSON.stringify(draft)),
store = JSON.parse(recovered.modelo_a_snapshot).salesOperations;
assert.equal(Object.keys(old).length, 12);
for (const [id, value] of Object.entries(old)) {
assert.deepEqual(store[id], value);
assert.equal(
salesCurrent({ ...recovered, context_opportunity: id }, value),
true,
id,
);
}
assert.equal(salesCurrent(recovered, salesBook(recovered)), true);
assert.equal(book.result.periods[0].fields['07'], '800.00');
assert.equal(book.result.periods[0].fields['05'], '200.00');
const report = JSON.stringify(
createProjectDossierReport(recovered, {
selectedSections: new Set(['finance']),
}),
);
for (const token of [
'800.00',
'200.00',
'opportunity:321',
'Manica',
'2026-09',
'MZN',
'AnexoI/2022',
'Outros tractores',
annexIVersion,
...book.rows.map((r) => r.annexIItem),
])
assert.ok(report.includes(token), token);
for (const token of [
'pharma_manufacturing_inputs',
'fundraising_public',
'production_forestry_opted',
])
assert.equal(report.includes(token), false);
const changed = {
...book,
rows: book.rows.map((r, i) =>
i === 8 ? { ...r, annexIOnly: false } : r,
),
};
assert.equal(salesCurrent(draft, changed), false);
assert.deepEqual(changed.result, book.result);
assert.deepEqual(recovered.selection_labels, original.selection_labels);
assert.equal(recovered.currency, original.currency);
});
if (process.env.IVA_G2L_OUT)
fs.writeFileSync(
process.env.IVA_G2L_OUT,
JSON.stringify(fixture().draft, null, 2),
);