227 lines
8.0 KiB
JavaScript
227 lines
8.0 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
newOwnName,
|
|
switchOwnNameTreatment,
|
|
ownNameConditions,
|
|
ownNameSpecificConditions,
|
|
ownNameTreatments,
|
|
evaluateOwnName,
|
|
recordOwnNames,
|
|
saveOwnNameBook,
|
|
ownNameBook,
|
|
ownNameCurrent,
|
|
ownNameReportRows,
|
|
} from '../../resources/js/lib/iva-own-name.ts';
|
|
const frozen = JSON.parse(
|
|
fs.readFileSync(
|
|
'tests/frontend/fixtures/iva-g10-own-name-preserved.json',
|
|
'utf8',
|
|
),
|
|
);
|
|
const draft = {
|
|
...frozen,
|
|
currency: 'MZN',
|
|
context_opportunity: 'opportunity:352',
|
|
project_title: 'SYNTHETIC QA — G10 nome próprio / Manica',
|
|
};
|
|
function row(t) {
|
|
return {
|
|
...newOwnName(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',
|
|
principalRef: 'SYNTHETIC QA comitente/mandante A',
|
|
agentRef: 'SYNTHETIC QA agente B',
|
|
thirdPartyRef: 'SYNTHETIC QA terceiro C',
|
|
contractRef: 'SYNTHETIC QA contrato/mandato',
|
|
subjectRef: 'SYNTHETIC QA objecto da operação',
|
|
firstAmount: '1000.25',
|
|
secondAmount: '1100.75',
|
|
firstLegRef: 'SYNTHETIC QA relação1',
|
|
secondLegRef: 'SYNTHETIC QA relação2',
|
|
existingBaseRef: 'SYNTHETIC QA referênciaP091preservada',
|
|
scope: 'SYNTHETIC QA partes/objecto/operação/período',
|
|
evidence: 'SYNTHETIC QA pressupostos expressos',
|
|
conditions: Object.fromEntries(
|
|
[...ownNameConditions, ...ownNameSpecificConditions(t)].map(
|
|
([key]) => [key, 'yes'],
|
|
),
|
|
),
|
|
};
|
|
}
|
|
for (const rule of ownNameTreatments)
|
|
void test(
|
|
rule.branch +
|
|
'/' +
|
|
rule.id +
|
|
' direction,own facts and original separate amounts',
|
|
() => {
|
|
const r = row(rule.id),
|
|
result = evaluateOwnName(r, 'MZN');
|
|
assert.equal(result.status, 'determined');
|
|
assert.equal(result.legs.length, 2);
|
|
assert.deepEqual(
|
|
result.legs.map((l) => [l.supplier, l.acquirer]),
|
|
rule.direction === 'sale'
|
|
? [
|
|
[r.principalRef, r.agentRef],
|
|
[r.agentRef, r.thirdPartyRef],
|
|
]
|
|
: [
|
|
[r.thirdPartyRef, r.agentRef],
|
|
[r.agentRef, r.principalRef],
|
|
],
|
|
);
|
|
assert.deepEqual(
|
|
result.legs.map((l) => l.consideration),
|
|
['1000.25', '1100.75'],
|
|
);
|
|
assert.deepEqual(
|
|
['baseAmount', 'vat', 'rate'].map((k) => result[k]),
|
|
[null, null, null],
|
|
);
|
|
for (const [key] of [
|
|
...ownNameConditions,
|
|
...ownNameSpecificConditions(rule.id),
|
|
]) {
|
|
const missing = structuredClone(r);
|
|
delete missing.conditions[key];
|
|
assert.equal(
|
|
evaluateOwnName(missing, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
missing.conditions[key] = 'no';
|
|
assert.equal(
|
|
evaluateOwnName(missing, 'MZN').status,
|
|
'not_applicable',
|
|
);
|
|
assert.equal(evaluateOwnName(missing, 'MZN').legs.length, 0);
|
|
}
|
|
for (const field of [
|
|
'description',
|
|
'operationRef',
|
|
'documentRef',
|
|
'contractRef',
|
|
'subjectRef',
|
|
'principalRef',
|
|
'agentRef',
|
|
'thirdPartyRef',
|
|
'firstLegRef',
|
|
'secondLegRef',
|
|
'firstAmount',
|
|
'secondAmount',
|
|
'scope',
|
|
'evidence',
|
|
])
|
|
assert.equal(
|
|
evaluateOwnName({ ...r, [field]: '' }, 'MZN').status,
|
|
'indeterminate',
|
|
field,
|
|
);
|
|
for (const patch of [
|
|
{ operationDate: '2026-11-12' },
|
|
{ documentDate: '2026-02-30' },
|
|
{ period: '2025-12' },
|
|
{ currency: 'USD' },
|
|
{ firstAmount: '1e3' },
|
|
{ secondAmount: '-1' },
|
|
])
|
|
assert.equal(
|
|
evaluateOwnName({ ...r, ...patch }, 'MZN').status,
|
|
'indeterminate',
|
|
);
|
|
assert.equal(
|
|
evaluateOwnName({ ...r, currency: 'USD' }, 'USD').legs[0]
|
|
.currency,
|
|
'USD',
|
|
);
|
|
assert.equal(
|
|
evaluateOwnName({ ...r, firstAmount: '0' }, 'MZN').legs[0]
|
|
.consideration,
|
|
'0',
|
|
);
|
|
assert.equal(
|
|
evaluateOwnName({ ...r, existingBaseRef: '' }, 'MZN').status,
|
|
'determined',
|
|
);
|
|
assert.match(
|
|
result.reason,
|
|
rule.kind === 'goods'
|
|
? /comissário considerado comprador|comitente considerado comprador/
|
|
: /adquirente eprestador/,
|
|
);
|
|
},
|
|
);
|
|
void test('Changing direction/kind keeps references and values but requires own confirmations', () => {
|
|
const original = row('goods_sale_commission');
|
|
const changed = switchOwnNameTreatment(
|
|
original,
|
|
'service_purchase_mandate',
|
|
);
|
|
assert.equal(changed.firstAmount, original.firstAmount);
|
|
assert.equal(changed.secondAmount, original.secondAmount);
|
|
assert.equal(changed.existingBaseRef, original.existingBaseRef);
|
|
assert.equal(changed.principalRef, original.principalRef);
|
|
assert.equal(changed.conditions.directionConfirmed, undefined);
|
|
assert.equal(evaluateOwnName(changed, 'MZN').status, 'indeterminate');
|
|
changed.conditions = {
|
|
...changed.conditions,
|
|
...Object.fromEntries(
|
|
ownNameSpecificConditions(changed.treatment).map(([k]) => [
|
|
k,
|
|
'yes',
|
|
]),
|
|
),
|
|
};
|
|
const result = evaluateOwnName(changed, 'MZN');
|
|
assert.equal(result.status, 'determined');
|
|
assert.equal(result.legs[0].supplier, original.thirdPartyRef);
|
|
assert.match(result.reason, /Não transformar/);
|
|
});
|
|
void test('Four circuits save/recover/history/report;P091 and all prior books unchanged', () => {
|
|
const rows = ownNameTreatments.map((t) => row(t.id));
|
|
let book = recordOwnNames(draft, { rows });
|
|
book = recordOwnNames(draft, book);
|
|
assert.equal(book.history.length, 1);
|
|
assert.notEqual(book.result.inputs, book.rows);
|
|
const next = { ...draft, modelo_a_snapshot: saveOwnNameBook(draft, book) };
|
|
assert.deepEqual(ownNameBook(next), book);
|
|
assert.ok(ownNameCurrent(next, book));
|
|
assert.equal(ownNameCurrent({ ...next, currency: 'USD' }, book), false);
|
|
assert.equal(
|
|
ownNameCurrent({ ...next, context_opportunity: 'other' }, book),
|
|
false,
|
|
);
|
|
assert.equal(ownNameReportRows(next).length, 4);
|
|
assert.ok(
|
|
ownNameReportRows(next).every((r) =>
|
|
r[2].includes('sem soma das duas relações'),
|
|
),
|
|
);
|
|
const store = JSON.parse(next.modelo_a_snapshot);
|
|
delete store.ownNames;
|
|
assert.deepEqual(store, JSON.parse(frozen.modelo_a_snapshot));
|
|
assert.throws(() => recordOwnNames(next, { rows: [rows[0], rows[0]] }));
|
|
assert.throws(() =>
|
|
ownNameBook({
|
|
...next,
|
|
modelo_a_snapshot: JSON.stringify({
|
|
...JSON.parse(next.modelo_a_snapshot),
|
|
ownNames: [],
|
|
}),
|
|
}),
|
|
);
|
|
if (process.env.IVA_OWN_NAME_FIXTURE)
|
|
fs.writeFileSync(
|
|
process.env.IVA_OWN_NAME_FIXTURE,
|
|
JSON.stringify(next, null, 2) + '\n',
|
|
);
|
|
});
|