212 lines
7.4 KiB
JavaScript
212 lines
7.4 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
newPropertyTransfer,
|
|
transferConditions,
|
|
propertyTransferTreatments,
|
|
evaluatePropertyTransfer,
|
|
recordPropertyTransfers,
|
|
savePropertyTransferBook,
|
|
propertyTransferBook,
|
|
propertyTransferCurrent,
|
|
propertyTransferReportRows,
|
|
switchPropertyTreatment,
|
|
} from '../../resources/js/lib/iva-property-transfers.ts';
|
|
const frozen = JSON.parse(
|
|
fs.readFileSync(
|
|
'tests/frontend/fixtures/iva-property-transfers-preserved.json',
|
|
'utf8',
|
|
),
|
|
);
|
|
const draft = {
|
|
...frozen,
|
|
currency: 'MZN',
|
|
context_opportunity: 'opportunity:356',
|
|
project_title: 'SYNTHETIC QA — Transmissões de propriedade / Manica',
|
|
};
|
|
function row(t) {
|
|
return {
|
|
...newPropertyTransfer(t, 'MZN'),
|
|
treatment: t,
|
|
description: 'SYNTHETIC QA ' + t,
|
|
period: '2026-12',
|
|
origin: 'projected',
|
|
operationDate: '2026-12-12',
|
|
operationRef: 'SYNTHETIC QA operação',
|
|
documentRef: 'SYNTHETIC QA documento/pressuposto',
|
|
documentDate: '2026-12-12',
|
|
goodsRef: 'SYNTHETIC QA conjunto identificado',
|
|
scope: 'SYNTHETIC QA bens/operação/período',
|
|
evidence: 'SYNTHETIC QA factos/pressupostos expressos',
|
|
contractRef: 'SYNTHETIC QA contrato/cessão',
|
|
propertyClauseRef: 'SYNTHETIC QA cláusula vinculante ambas as partes',
|
|
acquirerRef: 'SYNTHETIC QA adquirente2(1)a',
|
|
autonomousRef: 'SYNTHETIC QA ramo independente',
|
|
activitiesRef: 'SYNTHETIC QA operações com direito à dedução',
|
|
consideration: '1250.123456',
|
|
considerationRef:
|
|
'SYNTHETIC QA composição obtida/a obter,sem próprioIVA',
|
|
compositionConfirmed: 'yes',
|
|
conditions: Object.fromEntries(
|
|
transferConditions(t).map(([k]) => [k, 'yes']),
|
|
),
|
|
};
|
|
}
|
|
for (const rule of propertyTransferTreatments)
|
|
void test(rule.branch + ' ' + rule.id + ' own facts and references', () => {
|
|
const r = row(rule.id),
|
|
v = evaluatePropertyTransfer(r, 'MZN');
|
|
assert.equal(v.status, 'determined');
|
|
assert.equal(
|
|
v.classification,
|
|
rule.id === 'binding_lease'
|
|
? 'goods_transmission'
|
|
: 'tax_not_exigible_3_5',
|
|
);
|
|
assert.equal(
|
|
v.baseAmount,
|
|
rule.id === 'binding_lease' ? '1250.123456' : null,
|
|
);
|
|
assert.equal(v.vat, null);
|
|
assert.equal(v.rate, null);
|
|
for (const [k] of transferConditions(rule.id)) {
|
|
const missing = structuredClone(r);
|
|
delete missing.conditions[k];
|
|
assert.equal(
|
|
evaluatePropertyTransfer(missing, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
missing.conditions[k] = 'no';
|
|
assert.equal(
|
|
evaluatePropertyTransfer(missing, 'MZN').status,
|
|
'not_applicable',
|
|
);
|
|
}
|
|
for (const field of [
|
|
'description',
|
|
'operationRef',
|
|
'documentRef',
|
|
'goodsRef',
|
|
'scope',
|
|
'evidence',
|
|
'contractRef',
|
|
...(rule.id === 'binding_lease'
|
|
? ['propertyClauseRef']
|
|
: ['acquirerRef', 'autonomousRef', 'activitiesRef']),
|
|
])
|
|
assert.equal(
|
|
evaluatePropertyTransfer({ ...r, [field]: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
field,
|
|
);
|
|
for (const patch of [
|
|
{ operationDate: '2026-02-30' },
|
|
{ documentDate: '2026-02-30' },
|
|
{ period: '2025-12' },
|
|
{ period: '2026-11' },
|
|
])
|
|
assert.equal(
|
|
evaluatePropertyTransfer({ ...r, ...patch }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
});
|
|
void test('P087 classification separatefrom missingbase,exact consideration and no double subtraction', () => {
|
|
const r = row('binding_lease');
|
|
for (const patch of [
|
|
{ consideration: '' },
|
|
{ consideration: '-1' },
|
|
{ consideration: '1e3' },
|
|
{ consideration: '1.1234567' },
|
|
{ compositionConfirmed: '' },
|
|
{ compositionConfirmed: 'no' },
|
|
{ considerationRef: '' },
|
|
{ currency: 'USD' },
|
|
]) {
|
|
const v = evaluatePropertyTransfer({ ...r, ...patch }, 'MZN');
|
|
assert.equal(v.status, 'indeterminate');
|
|
assert.equal(v.classification, 'goods_transmission');
|
|
assert.equal(v.baseAmount, null);
|
|
}
|
|
assert.equal(
|
|
evaluatePropertyTransfer({ ...r, consideration: '0' }, 'MZN')
|
|
.baseAmount,
|
|
'0.00',
|
|
);
|
|
assert.equal(
|
|
evaluatePropertyTransfer(
|
|
{ ...r, consideration: '900719925474099.123456' },
|
|
'MZN',
|
|
).baseAmount,
|
|
'900719925474099.123456',
|
|
);
|
|
assert.match(evaluatePropertyTransfer(r, 'MZN').reason, /15\(1\)/);
|
|
});
|
|
void test('P127 no exigibility is neitherzero nor genericexemption;switchretainsdata', () => {
|
|
for (const t of ['business_onerous', 'business_free']) {
|
|
const v = evaluatePropertyTransfer(
|
|
{
|
|
...row(t),
|
|
consideration: '',
|
|
currency: 'USD',
|
|
compositionConfirmed: '',
|
|
},
|
|
'MZN',
|
|
);
|
|
assert.equal(v.classification, 'tax_not_exigible_3_5');
|
|
assert.equal(v.baseAmount, null);
|
|
assert.match(v.reason, /não é isenção genérica/i);
|
|
}
|
|
const r = row('binding_lease'),
|
|
sw = switchPropertyTreatment(r, 'business_free');
|
|
assert.equal(sw.consideration, r.consideration);
|
|
assert.equal(sw.propertyClauseRef, r.propertyClauseRef);
|
|
assert.deepEqual(sw.conditions, {});
|
|
assert.equal(sw.compositionConfirmed, '');
|
|
});
|
|
void test('draft/report/history and allpriorbooks preserved', () => {
|
|
const rows = propertyTransferTreatments.map((t) => row(t.id)),
|
|
first = recordPropertyTransfers(draft, { rows });
|
|
const next = {
|
|
...draft,
|
|
modelo_a_snapshot: savePropertyTransferBook(draft, first),
|
|
};
|
|
const second = recordPropertyTransfers(next, first);
|
|
next.modelo_a_snapshot = savePropertyTransferBook(next, second);
|
|
assert.equal(second.history.length, 1);
|
|
assert.deepEqual(second.history[0].inputs, rows);
|
|
assert.equal(propertyTransferCurrent(next, second), true);
|
|
assert.equal(
|
|
propertyTransferCurrent({ ...next, currency: 'USD' }, second),
|
|
false,
|
|
);
|
|
assert.equal(propertyTransferReportRows(next).length, 3);
|
|
assert.deepEqual(
|
|
propertyTransferBook({
|
|
...next,
|
|
context_opportunity: 'opportunity:357',
|
|
}),
|
|
{ rows: [] },
|
|
);
|
|
const store = JSON.parse(next.modelo_a_snapshot);
|
|
delete store.propertyTransfers;
|
|
assert.deepEqual(store, JSON.parse(frozen.modelo_a_snapshot));
|
|
assert.throws(() =>
|
|
recordPropertyTransfers(next, { rows: [rows[0], rows[0]] }),
|
|
);
|
|
assert.throws(() =>
|
|
propertyTransferBook({
|
|
...next,
|
|
modelo_a_snapshot: JSON.stringify({
|
|
...store,
|
|
propertyTransfers: [],
|
|
}),
|
|
}),
|
|
);
|
|
if (process.env.IVA_PROPERTY_TRANSFERS_FIXTURE)
|
|
fs.writeFileSync(
|
|
process.env.IVA_PROPERTY_TRANSFERS_FIXTURE,
|
|
JSON.stringify(next, null, 2) + '\n',
|
|
);
|
|
});
|