Files
Investidor-V2/tests/frontend/iva-exclusion-base.test.mjs
T

431 lines
13 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {
newExclusionBase,
newExclusionPart,
switchExclusionPart,
exclusionTreatments,
exclusionConditions,
partConditions,
evaluateExclusion,
recordExclusions,
saveExclusionBook,
exclusionBook,
exclusionCurrent,
exclusionReportRows,
} from '../../resources/js/lib/iva-exclusion-base.ts';
import { compositionCurrent } from '../../resources/js/lib/iva-composition-base.ts';
import { fuelBaseCurrent } from '../../resources/js/lib/iva-fuel-base.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const frozen = JSON.parse(
fs.readFileSync(
new URL('./fixtures/iva-g7g-preserved-inputs.json', import.meta.url),
'utf8',
),
);
const part = (treatment = 'judicial_indemnity', id = treatment) => ({
...newExclusionPart(id),
treatment,
description: 'SYNTHETIC QA ' + treatment,
amount: {
judicial_indemnity: '100.10',
granted_discount: '50.25',
third_party_payment: '30.15',
returnable_packaging: '20.05',
}[treatment],
included: 'yes',
reference:
'SYNTHETIC QA referência ' +
id +
' / declaração judicial e contrato quando aplicável',
scope: 'SYNTHETIC QA operação A,montante e condições deste tratamento',
accountRef: 'SYNTHETIC QA contas de terceiros A',
beneficiaryRef: 'SYNTHETIC QA adquirente B',
documentExcerpt:
'SYNTHETIC QA factura A,embalagens separadas,devolução acordada expressamente',
conditions: Object.fromEntries(
partConditions(treatment).map(([key]) => [key, 'yes']),
),
});
const row = () => ({
...newExclusionBase('g7g-operation-A', 'MZN'),
description: 'SYNTHETIC QA exclusões operação A',
period: '2026-12',
operationRef: 'SYNTHETIC QA operação A',
initialAmount: '1000.25',
initialRef:
'SYNTHETIC QA montante sem próprioIVA,inclusões15(5)consideradas',
documentRef: 'SYNTHETIC QA G7G documento A',
documentDate: '2026-12-12',
exclusionRef: 'SYNTHETIC QA quatro exclusões reconciliadas,sem duplicação',
evidence: 'SYNTHETIC QA pressupostos expressos,não documento real',
conditions: Object.fromEntries(
exclusionConditions.map(([key]) => [key, 'yes']),
),
parts: exclusionTreatments.map((t) => part(t.id)),
});
const draft = () => ({
...structuredClone(frozen),
context_opportunity: 'opportunity:345',
project_title: 'SYNTHETIC QA — G7G / Exclusões da contraprestação',
});
void test('P102 four treatments each own statutoryconditions and references;unknown/no never become automatic exclusion', () => {
const input = row(),
ok = evaluateExclusion(input, 'MZN');
assert.equal(ok.baseAmount, '799.70');
assert.equal(ok.vat, null);
assert.equal(ok.rate, null);
for (const [key] of exclusionConditions)
for (const value of ['', 'unknown', 'no']) {
const r = evaluateExclusion(
{ ...input, conditions: { ...input.conditions, [key]: value } },
'MZN',
);
assert.equal(
r.status,
value === 'no' ? 'not_applicable' : 'indeterminate',
);
assert.equal(r.baseAmount, null);
}
for (const t of exclusionTreatments) {
const p = part(t.id);
assert.equal(
evaluateExclusion({ ...input, parts: [p] }, 'MZN').status,
'determined',
);
for (const [key] of partConditions(t.id))
for (const value of ['', 'unknown', 'no']) {
const r = evaluateExclusion(
{
...input,
parts: [
{
...p,
conditions: { ...p.conditions, [key]: value },
},
],
},
'MZN',
);
assert.equal(
r.status,
value === 'no' ? 'not_applicable' : 'indeterminate',
);
assert.equal(r.baseAmount, null);
assert.equal(r.vat, null);
}
for (const patch of [
{ reference: '' },
{ scope: '' },
{ description: '' },
{ included: '' },
{ amount: '' },
])
assert.equal(
evaluateExclusion(
{ ...input, parts: [{ ...p, ...patch }] },
'MZN',
).baseAmount,
null,
);
}
for (const patch of [
{ description: '' },
{ operationRef: '' },
{ initialRef: '' },
{ documentRef: '' },
{ documentDate: '2026-02-30' },
{ exclusionRef: '' },
{ evidence: '' },
{ period: '2025-12' },
{ currency: 'USD' },
])
assert.equal(
evaluateExclusion({ ...input, ...patch }, 'MZN').baseAmount,
null,
);
for (const patch of [{ accountRef: '' }, { beneficiaryRef: '' }])
assert.equal(
evaluateExclusion(
{
...input,
parts: [{ ...part('third_party_payment'), ...patch }],
},
'MZN',
).baseAmount,
null,
);
assert.equal(
evaluateExclusion(
{
...input,
parts: [
{ ...part('returnable_packaging'), documentExcerpt: '' },
],
},
'MZN',
).baseAmount,
null,
);
});
void test('subtract included exclusions only,alreadyexcluded retained;exactdecimal/zero/excess;switch retains unrelated references and clearsconditions', () => {
const input = row();
assert.equal(
evaluateExclusion(
{
...input,
parts: input.parts.map((p) => ({ ...p, included: 'no' })),
},
'MZN',
).baseAmount,
'1000.25',
);
assert.equal(
evaluateExclusion(
{
...input,
parts: input.parts.map((p) => ({
...p,
included:
p.treatment === 'judicial_indemnity' ? 'no' : 'yes',
})),
},
'MZN',
).baseAmount,
'899.80',
);
assert.equal(
evaluateExclusion(
{
...input,
initialAmount: '0',
parts: [{ ...part(), amount: '0' }],
},
'MZN',
).baseAmount,
'0.00',
);
assert.equal(
evaluateExclusion(
{
...input,
initialAmount: '1.000002',
parts: [{ ...part(), amount: '0.000001' }],
},
'MZN',
).baseAmount,
'1.000001',
);
assert.equal(
evaluateExclusion(
{
...input,
initialAmount: '999999999999999.999999',
parts: [{ ...part(), amount: '0.000001' }],
},
'MZN',
).baseAmount,
'999999999999999.999998',
);
for (const amount of ['-1', 'NaN', '0.0000001', '', '1000.26'])
assert.equal(
evaluateExclusion(
{ ...input, parts: [{ ...part(), amount }] },
'MZN',
).baseAmount,
null,
);
assert.equal(
evaluateExclusion({ ...input, initialAmount: '' }, 'MZN').baseAmount,
null,
);
const switched = switchExclusionPart(
part('third_party_payment'),
'returnable_packaging',
);
assert.deepEqual(switched.conditions, {});
for (const field of [
'amount',
'reference',
'scope',
'accountRef',
'beneficiaryRef',
'documentExcerpt',
'included',
])
assert.equal(switched[field], part('third_party_payment')[field]);
assert.equal(
evaluateExclusion({ ...input, parts: [switched] }, 'MZN').baseAmount,
null,
);
assert.equal(
evaluateExclusion({ ...input, parts: [] }, 'MZN').baseAmount,
null,
);
assert.equal(
evaluateExclusion({ ...input, parts: [part(), part()] }, 'MZN')
.baseAmount,
null,
);
});
void test('save/recovery/history/report keep one base/four exclusions and all84 previous books/currentkeys unchanged', () => {
const d = draft(),
prior = JSON.parse(d.modelo_a_snapshot);
assert.deepEqual(exclusionBook(d), { rows: [] });
assert.deepEqual(exclusionReportRows(d), []);
let book = recordExclusions(d, { rows: [{ ...row(), conditions: {} }] });
book = recordExclusions(d, {
...book,
rows: [
{
...row(),
parts: [
{
...part('granted_discount'),
conditions: { granted: 'no' },
},
],
},
],
});
book = recordExclusions(d, { ...book, rows: [row()] });
assert.equal(book.history.length, 2);
assert.ok(
book.history.every((h) =>
h.rows.every((r) => r.baseAmount === null && r.vat === null),
),
);
assert.ok(exclusionCurrent(d, book));
assert.equal(book.result.rows.length, 1);
assert.equal(book.result.inputs[0].parts.length, 4);
for (const field of [
'amount',
'included',
'reference',
'treatment',
'scope',
'accountRef',
'beneficiaryRef',
'documentExcerpt',
])
assert.ok(
!exclusionCurrent(d, {
...book,
rows: book.rows.map((r) => ({
...r,
parts: r.parts.map((p) => ({ ...p, [field]: 'changed' })),
})),
}),
);
for (const patch of [
{ context_opportunity: 'opportunity:346' },
{ currency: 'USD' },
{ selection_labels: { province_id: 'Maputo' } },
])
assert.ok(!exclusionCurrent({ ...d, ...patch }, book));
d.modelo_a_snapshot = saveExclusionBook(d, book);
assert.deepEqual(exclusionBook(JSON.parse(JSON.stringify(d))), book);
const next = JSON.parse(d.modelo_a_snapshot);
const { considerationExclusions: _considerationExclusions, ...untouched } =
next;
assert.deepEqual(untouched, prior);
for (const [scope, previous] of Object.entries(
prior.considerationCompositions,
))
assert.ok(
compositionCurrent({ ...d, context_opportunity: scope }, previous),
);
for (const [scope, previous] of Object.entries(prior.regulatedFuelBases))
assert.ok(
fuelBaseCurrent({ ...d, context_opportunity: scope }, previous),
);
assert.equal(
next.considerationCompositions['opportunity:344'].result.rows[0]
.baseAmount,
'1150.60',
);
assert.equal(
next.noncashBases['opportunity:343'].result.rows[1].baseAmount,
'2700.75',
);
assert.equal(
next.regulatedFuelBases['opportunity:342'].result.rows[0].baseAmount,
'1400.15',
);
assert.equal(
next.importExemptions['opportunity:338'].result.rows[1].importVat,
'400.00',
);
assert.equal(
next.books['opportunity:329'].result.periods[0].fields['11'],
null,
);
const report = JSON.stringify(
createProjectDossierReport(d, {
selectedSections: new Set(['finance']),
version: 'QA G7G',
}),
);
for (const token of [
'Base P102',
'799.70',
'IVA: Indeterminado',
'opportunity:345',
'Manica',
'2026-12',
'operação A',
'15(6)',
'100.10',
'27(5)(b)',
'contas de terceiros A',
'devolução acordada',
'campo11',
])
assert.ok(report.includes(token), token);
assert.equal(exclusionReportRows(d).length, 1);
assert.deepEqual(
exclusionReportRows({ ...d, context_opportunity: 'opportunity:346' }),
[],
);
if (process.env.IVA_G7G_CALCULATED)
fs.writeFileSync(process.env.IVA_G7G_CALCULATED, JSON.stringify(d));
});
void test('corrupt nested exclusions/store cannot overwrite originals;duplicate operation ids cannot be recorded', () => {
const d = draft(),
original = d.modelo_a_snapshot;
for (const patch of [
{ initialAmount: 4 },
{ conditions: [] },
{ parts: {} },
{ parts: [{ ...part(), amount: 4 }] },
{ parts: [{ ...part(), conditions: [] }] },
{ parts: [null] },
])
assert.throws(
() => saveExclusionBook(d, { rows: [{ ...row(), ...patch }] }),
/originais preservados/,
);
assert.equal(d.modelo_a_snapshot, original);
assert.throws(
() => recordExclusions(d, { rows: [row(), row()] }),
/distintos/,
);
assert.throws(() => recordExclusions(d, { rows: [] }), /distintos/);
assert.throws(
() =>
exclusionBook({
...d,
modelo_a_snapshot: JSON.stringify({
...JSON.parse(original),
considerationExclusions: [],
}),
}),
/originais preservados/,
);
});