Files
Investidor-V2/tests/frontend/iva-goods-presumptions.test.mjs
T

243 lines
8.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {
newGoodsPresumption,
presumptionConditions,
goodsPresumptionTreatments,
evaluateGoodsPresumption,
recordGoodsPresumptions,
saveGoodsPresumptionBook,
goodsPresumptionBook,
goodsPresumptionCurrent,
goodsPresumptionReportRows,
switchPresumptionTreatment,
} from '../../resources/js/lib/iva-goods-presumptions.ts';
const frozen = JSON.parse(
fs.readFileSync(
'tests/frontend/fixtures/iva-goods-presumptions-preserved.json',
'utf8',
),
);
const draft = {
...frozen,
context_opportunity: 'opportunity:355',
project_title: 'SYNTHETIC QA — Consignação e presunções / Manica',
};
function row(t) {
return {
...newGoodsPresumption(t),
treatment: t,
description: 'SYNTHETIC QA ' + t,
period: '2026-12',
origin: 'projected',
operationDate: '2026-12-12',
operationRef: 'SYNTHETIC QA operação/conferência',
documentRef: 'SYNTHETIC QA documento/pressuposto',
documentDate: '2026-12-12',
goodsRef: 'SYNTHETIC QA conjunto individual',
scope: 'SYNTHETIC QA todos os estabelecimentos/período/conjunto',
evidence: 'SYNTHETIC QA factos/pressupostos expressos',
deliveryDate: '2026-06-01',
recipientRef: 'SYNTHETIC QA destinatário/entrega',
inventoryRef: 'SYNTHETIC QA levantamento todos estabelecimentos',
productionRef: 'SYNTHETIC QA volume de produção/comparação',
quantity: '125.123456',
quantityUnit: 'kg',
contraryProof: 'no',
contraryProofRef: '',
conditions: Object.fromEntries(
presumptionConditions(t).map(([k]) => [k, 'yes']),
),
};
}
for (const rule of goodsPresumptionTreatments)
void test(
rule.branch +
' ' +
rule.id +
' own facts/references and no fiscal amount',
() => {
const r = row(rule.id),
result = evaluateGoodsPresumption(r);
assert.equal(result.status, 'determined');
assert.equal(
result.classification,
rule.id === 'consignment_180'
? 'consignment_transmission'
: rule.id === 'found_goods'
? 'presumed_acquisition'
: 'presumed_transmission',
);
assert.equal(result.baseAmount, null);
assert.equal(result.vat, null);
assert.equal(result.rate, null);
for (const [k] of presumptionConditions(rule.id)) {
const missing = structuredClone(r);
delete missing.conditions[k];
assert.equal(
evaluateGoodsPresumption(missing).status,
'indeterminate',
);
missing.conditions[k] = 'no';
assert.equal(
evaluateGoodsPresumption(missing).status,
'not_applicable',
);
}
for (const field of [
'description',
'operationRef',
'documentRef',
'goodsRef',
'scope',
'evidence',
...(rule.id === 'consignment_180'
? ['deliveryDate', 'recipientRef']
: ['inventoryRef']),
...(rule.id === 'excess_consumption'
? ['productionRef', 'quantity', 'quantityUnit']
: []),
])
assert.equal(
evaluateGoodsPresumption({ ...r, [field]: '' }).status,
'indeterminate',
field,
);
for (const patch of [
{ operationDate: '2026-02-30' },
{ documentDate: '2026-02-30' },
{ period: '2025-12' },
{ period: '2026-11' },
])
assert.equal(
evaluateGoodsPresumption({ ...r, ...patch }).status,
'indeterminate',
);
},
);
void test('P123 exact180-day boundary,yearcrossing and chronology', () => {
const r = row('consignment_180');
const day = (n) =>
new Date(Date.parse(r.deliveryDate + 'T00:00:00Z') + n * 86400000)
.toISOString()
.slice(0, 10);
for (const n of [179, 180, 181]) {
const d = day(n),
v = evaluateGoodsPresumption({
...r,
operationDate: d,
period: d.slice(0, 7),
});
assert.equal(v.elapsedDays, n);
assert.equal(v.deadline, day(180));
assert.equal(v.status, n > 180 ? 'determined' : 'not_applicable');
}
assert.equal(
evaluateGoodsPresumption({
...r,
deliveryDate: '2025-12-31',
operationDate: '2026-06-30',
period: '2026-06',
}).elapsedDays,
181,
);
assert.equal(
evaluateGoodsPresumption({ ...r, deliveryDate: '2026-12-13' }).status,
'indeterminate',
);
const returned = structuredClone(r);
returned.conditions.notReturned = 'no';
assert.equal(evaluateGoodsPresumption(returned).status, 'not_applicable');
});
void test('P126 rebuttable presumption,unknown proof and scope retained', () => {
for (const t of ['missing_goods', 'excess_consumption', 'found_goods']) {
const r = row(t);
assert.equal(
evaluateGoodsPresumption({ ...r, contraryProof: '' }).status,
'indeterminate',
);
assert.equal(
evaluateGoodsPresumption({ ...r, contraryProof: 'yes' }).status,
'indeterminate',
);
const v = evaluateGoodsPresumption({
...r,
contraryProof: 'yes',
contraryProofRef: 'SYNTHETIC QA prova/conjunto/período',
});
assert.equal(v.classification, 'rebutted');
assert.equal(v.baseAmount, null);
assert.equal(v.vat, null);
}
for (const quantity of ['', '0', '-1', '1e3', '1.1234567'])
assert.equal(
evaluateGoodsPresumption({ ...row('excess_consumption'), quantity })
.status,
'indeterminate',
);
const switched = switchPresumptionTreatment(
{
...row('excess_consumption'),
contraryProof: 'yes',
contraryProofRef: 'retained',
},
'consignment_180',
);
assert.equal(
switched.productionRef,
row('excess_consumption').productionRef,
);
assert.equal(switched.contraryProofRef, 'retained');
assert.equal(switched.contraryProof, '');
assert.deepEqual(switched.conditions, {});
});
void test('private draft/report/history preserve allpreviousbooks and opportunity', () => {
const rows = goodsPresumptionTreatments.map((t) => row(t.id)),
first = recordGoodsPresumptions(draft, { rows });
const next = {
...draft,
modelo_a_snapshot: saveGoodsPresumptionBook(draft, first),
};
const second = recordGoodsPresumptions(next, first);
next.modelo_a_snapshot = saveGoodsPresumptionBook(next, second);
assert.equal(second.history.length, 1);
assert.deepEqual(second.history[0].inputs, rows);
assert.equal(goodsPresumptionCurrent(next, second), true);
assert.equal(
goodsPresumptionCurrent(next, {
...second,
rows: rows.map((r, i) => (i ? r : { ...r, scope: 'changed' })),
}),
false,
);
assert.equal(goodsPresumptionReportRows(next).length, 4);
assert.deepEqual(
goodsPresumptionBook({
...next,
context_opportunity: 'opportunity:356',
}),
{ rows: [] },
);
const store = JSON.parse(next.modelo_a_snapshot);
delete store.goodsPresumptions;
assert.deepEqual(store, JSON.parse(frozen.modelo_a_snapshot));
assert.throws(() =>
recordGoodsPresumptions(next, { rows: [rows[0], rows[0]] }),
);
assert.throws(() =>
goodsPresumptionBook({
...next,
modelo_a_snapshot: JSON.stringify({
...store,
goodsPresumptions: [],
}),
}),
);
if (process.env.IVA_GOODS_PRESUMPTIONS_FIXTURE)
fs.writeFileSync(
process.env.IVA_GOODS_PRESUMPTIONS_FIXTURE,
JSON.stringify(next, null, 2) + '\n',
);
});