314 lines
10 KiB
JavaScript
314 lines
10 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
newGoodsLocation,
|
|
switchGoodsTreatment,
|
|
goodsLocationTreatments,
|
|
goodsLocationConditions,
|
|
ownGoodsConditions,
|
|
evaluateGoodsLocation,
|
|
recordGoodsLocations,
|
|
saveGoodsLocationBook,
|
|
goodsLocationBook,
|
|
goodsLocationCurrent,
|
|
goodsLocationReportRows,
|
|
} from '../../resources/js/lib/iva-goods-location.ts';
|
|
import { serviceNormalCurrent } from '../../resources/js/lib/iva-service-normal.ts';
|
|
import { valueReviewCurrent } from '../../resources/js/lib/iva-value-review.ts';
|
|
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
|
|
const frozen = JSON.parse(
|
|
fs.readFileSync(
|
|
new URL('./fixtures/iva-g8a-preserved-inputs.json', import.meta.url),
|
|
'utf8',
|
|
),
|
|
);
|
|
const row = (treatment = 'goods_with_transport') => ({
|
|
...newGoodsLocation('g8a-' + treatment),
|
|
treatment,
|
|
description: 'SYNTHETIC QA bens A',
|
|
period: '2026-12',
|
|
operationDate: '2026-12-12',
|
|
operationRef: 'SYNTHETIC QA operação A',
|
|
documentRef: 'SYNTHETIC QA G8A ' + treatment,
|
|
documentDate: '2026-12-12',
|
|
goodsPlace: 'SYNTHETIC QA local físico dos bens no momento relevante',
|
|
placeCountry: treatment === 'goods_with_transport' ? 'MZ' : 'foreign',
|
|
placeRef: 'SYNTHETIC QA referência do local e momento A',
|
|
transportRef: 'SYNTHETIC QA transporte A',
|
|
importRef: 'SYNTHETIC QA importação nacional A',
|
|
chainRef:
|
|
'SYNTHETIC QA importador A/transmissão subsequente antes da importação',
|
|
scope: 'SYNTHETIC QA bens A/operação A/dezembro2026/condições A',
|
|
evidence: 'SYNTHETIC QA pressupostos expressos,não documento real',
|
|
conditions: Object.fromEntries(
|
|
[...goodsLocationConditions, ...ownGoodsConditions(treatment)].map(
|
|
([key]) => [key, 'yes'],
|
|
),
|
|
),
|
|
});
|
|
const draft = () => ({
|
|
...structuredClone(frozen),
|
|
context_opportunity: 'opportunity:348',
|
|
project_title: 'SYNTHETIC QA — G8A / Localização de bens',
|
|
});
|
|
void test('P105 each route owns facts/references;unknown/no never defaultoutside/exempt orIVA zero', () => {
|
|
for (const t of goodsLocationTreatments) {
|
|
const input = row(t.id),
|
|
ok = evaluateGoodsLocation(input);
|
|
assert.equal(
|
|
ok.territory,
|
|
t.id === 'goods_without_transport' ? 'outside' : 'national',
|
|
);
|
|
assert.equal(ok.baseAmount, null);
|
|
assert.equal(ok.vat, null);
|
|
assert.equal(ok.rate, null);
|
|
for (const [key] of [
|
|
...goodsLocationConditions,
|
|
...ownGoodsConditions(t.id),
|
|
])
|
|
for (const value of ['', 'unknown', 'no']) {
|
|
const r = evaluateGoodsLocation({
|
|
...input,
|
|
conditions: { ...input.conditions, [key]: value },
|
|
});
|
|
assert.equal(
|
|
r.status,
|
|
value === 'no' ? 'not_applicable' : 'indeterminate',
|
|
);
|
|
assert.equal(r.territory, null);
|
|
assert.equal(r.vat, null);
|
|
}
|
|
for (const patch of [
|
|
{ description: '' },
|
|
{ operationRef: '' },
|
|
{ documentRef: '' },
|
|
{ documentDate: '2026-02-30' },
|
|
{ operationDate: '2026-11-12' },
|
|
{ operationDate: '2026-02-30' },
|
|
{ scope: '' },
|
|
{ evidence: '' },
|
|
{ period: '2025-12' },
|
|
{ treatment: '' },
|
|
])
|
|
assert.equal(
|
|
evaluateGoodsLocation({ ...input, ...patch }).territory,
|
|
null,
|
|
);
|
|
const required =
|
|
t.id === 'goods_before_import'
|
|
? ['transportRef', 'importRef', 'chainRef']
|
|
: [
|
|
'goodsPlace',
|
|
'placeCountry',
|
|
'placeRef',
|
|
...(t.id === 'goods_with_transport'
|
|
? ['transportRef']
|
|
: []),
|
|
];
|
|
for (const field of required)
|
|
assert.equal(
|
|
evaluateGoodsLocation({ ...input, [field]: '' }).territory,
|
|
null,
|
|
);
|
|
}
|
|
});
|
|
void test('physical start/disposal determines6(1);preimport6(2)overridesphysicalforeign;no inference fromclient ormoney', () => {
|
|
for (const treatment of ['goods_with_transport', 'goods_without_transport'])
|
|
for (const placeCountry of ['MZ', 'foreign'])
|
|
assert.equal(
|
|
evaluateGoodsLocation({ ...row(treatment), placeCountry })
|
|
.territory,
|
|
placeCountry === 'MZ' ? 'national' : 'outside',
|
|
);
|
|
const before = row('goods_before_import');
|
|
assert.equal(
|
|
evaluateGoodsLocation({
|
|
...before,
|
|
goodsPlace: '',
|
|
placeCountry: '',
|
|
placeRef: '',
|
|
}).territory,
|
|
'national',
|
|
);
|
|
assert.equal(
|
|
evaluateGoodsLocation({ ...before, placeCountry: 'foreign' }).territory,
|
|
'national',
|
|
);
|
|
assert.equal(
|
|
evaluateGoodsLocation({ ...row(), placeCountry: 'unknown' }).territory,
|
|
null,
|
|
);
|
|
const switched = switchGoodsTreatment(
|
|
row('goods_without_transport'),
|
|
'goods_before_import',
|
|
);
|
|
for (const field of [
|
|
'goodsPlace',
|
|
'placeCountry',
|
|
'placeRef',
|
|
'transportRef',
|
|
'importRef',
|
|
'chainRef',
|
|
])
|
|
assert.equal(switched[field], row('goods_without_transport')[field]);
|
|
assert.equal(switched.conditions.beforeImport, undefined);
|
|
assert.equal(evaluateGoodsLocation(switched).territory, null);
|
|
const d = draft(),
|
|
book = recordGoodsLocations(d, { rows: [row()] });
|
|
assert.ok(
|
|
goodsLocationCurrent(
|
|
{
|
|
...d,
|
|
currency: 'USD',
|
|
customer_address: 'foreign',
|
|
customer_nationality: 'foreign',
|
|
},
|
|
book,
|
|
),
|
|
);
|
|
});
|
|
void test('save/recovery/history/report preserve all87 delivered books/currentkeys and territorialclassification distinctfromtax', () => {
|
|
const d = draft(),
|
|
prior = JSON.parse(d.modelo_a_snapshot);
|
|
assert.deepEqual(goodsLocationBook(d), { rows: [] });
|
|
assert.deepEqual(goodsLocationReportRows(d), []);
|
|
let book = recordGoodsLocations(d, {
|
|
rows: goodsLocationTreatments.map((t) => ({
|
|
...row(t.id),
|
|
conditions: {},
|
|
})),
|
|
});
|
|
book = recordGoodsLocations(d, {
|
|
...book,
|
|
rows: goodsLocationTreatments.map((t) => ({
|
|
...row(t.id),
|
|
conditions: { ...row(t.id).conditions, goodsSupply: 'no' },
|
|
})),
|
|
});
|
|
book = recordGoodsLocations(d, {
|
|
...book,
|
|
rows: goodsLocationTreatments.map((t) => row(t.id)),
|
|
});
|
|
assert.equal(book.history.length, 2);
|
|
assert.ok(
|
|
book.history.every((h) =>
|
|
h.rows.every((r) => r.territory === null && r.vat === null),
|
|
),
|
|
);
|
|
assert.ok(goodsLocationCurrent(d, book));
|
|
for (const field of [
|
|
'treatment',
|
|
'placeCountry',
|
|
'goodsPlace',
|
|
'placeRef',
|
|
'importRef',
|
|
'chainRef',
|
|
'scope',
|
|
'operationDate',
|
|
])
|
|
assert.ok(
|
|
!goodsLocationCurrent(d, {
|
|
...book,
|
|
rows: book.rows.map((r) => ({ ...r, [field]: 'changed' })),
|
|
}),
|
|
);
|
|
for (const patch of [
|
|
{ context_opportunity: 'opportunity:349' },
|
|
{ selection_labels: { province_id: 'Maputo' } },
|
|
])
|
|
assert.ok(!goodsLocationCurrent({ ...d, ...patch }, book));
|
|
d.modelo_a_snapshot = saveGoodsLocationBook(d, book);
|
|
assert.deepEqual(goodsLocationBook(JSON.parse(JSON.stringify(d))), book);
|
|
const next = JSON.parse(d.modelo_a_snapshot);
|
|
const { goodsLocations: _goodsLocations, ...untouched } = next;
|
|
assert.deepEqual(untouched, prior);
|
|
for (const [scope, previous] of Object.entries(prior.serviceNormals))
|
|
assert.ok(
|
|
serviceNormalCurrent(
|
|
{ ...d, context_opportunity: scope },
|
|
previous,
|
|
),
|
|
);
|
|
for (const [scope, previous] of Object.entries(prior.valueReviews))
|
|
assert.ok(
|
|
valueReviewCurrent({ ...d, context_opportunity: scope }, previous),
|
|
);
|
|
assert.equal(
|
|
next.serviceNormals['opportunity:347'].result.rows[2].baseAmount,
|
|
'900.75',
|
|
);
|
|
assert.equal(
|
|
next.valueReviews['opportunity:346'].result.rows[1].baseAmount,
|
|
'1400.75',
|
|
);
|
|
assert.equal(
|
|
next.considerationExclusions['opportunity:345'].result.rows[0]
|
|
.baseAmount,
|
|
'799.70',
|
|
);
|
|
assert.equal(
|
|
next.books['opportunity:329'].result.periods[0].fields['11'],
|
|
null,
|
|
);
|
|
const report = JSON.stringify(
|
|
createProjectDossierReport(d, {
|
|
selectedSections: new Set(['finance']),
|
|
version: 'QA G8A',
|
|
}),
|
|
);
|
|
for (const token of [
|
|
'Localização P105',
|
|
'Fora do território nacional',
|
|
'IVA: Indeterminado',
|
|
'opportunity:348',
|
|
'Manica',
|
|
'2026-12',
|
|
'6(1)',
|
|
'6(2)',
|
|
'importador A',
|
|
'não equivale a isenção',
|
|
'campo11',
|
|
])
|
|
assert.ok(report.includes(token), token);
|
|
assert.deepEqual(
|
|
goodsLocationReportRows({
|
|
...d,
|
|
context_opportunity: 'opportunity:349',
|
|
}),
|
|
[],
|
|
);
|
|
if (process.env.IVA_G8A_CALCULATED)
|
|
fs.writeFileSync(process.env.IVA_G8A_CALCULATED, JSON.stringify(d));
|
|
});
|
|
void test('corrupt goods rows/store cannot overwrite originals;duplicateoperationids cannotbe recorded', () => {
|
|
const d = draft(),
|
|
original = d.modelo_a_snapshot;
|
|
for (const patch of [
|
|
{ placeCountry: 4 },
|
|
{ conditions: [] },
|
|
{ chainRef: null },
|
|
])
|
|
assert.throws(
|
|
() => saveGoodsLocationBook(d, { rows: [{ ...row(), ...patch }] }),
|
|
/originais preservados/,
|
|
);
|
|
assert.equal(d.modelo_a_snapshot, original);
|
|
assert.throws(
|
|
() => recordGoodsLocations(d, { rows: [row(), row()] }),
|
|
/distintos/,
|
|
);
|
|
assert.throws(() => recordGoodsLocations(d, { rows: [] }), /distintos/);
|
|
assert.throws(
|
|
() =>
|
|
goodsLocationBook({
|
|
...d,
|
|
modelo_a_snapshot: JSON.stringify({
|
|
...JSON.parse(original),
|
|
goodsLocations: [],
|
|
}),
|
|
}),
|
|
/originais preservados/,
|
|
);
|
|
});
|