import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newForeignOperation, evaluateForeignOperation, foreignSources, foreignEvents, recordForeignOperations, saveForeignOperationBook, foreignOperationBook, foreignOperationCurrent, foreignOperationReportRows, switchForeignSource, } from '../../resources/js/lib/iva-foreign-operations.ts'; import { recordGoodsLocations, saveGoodsLocationBook, goodsLocationBook, } from '../../resources/js/lib/iva-goods-location.ts'; import { recordServiceLocations, saveServiceLocationBook, } from '../../resources/js/lib/iva-service-location.ts'; import { recordListedServices, saveListedServiceBook, } from '../../resources/js/lib/iva-listed-services.ts'; import { recordCurrencyEvents, saveCurrencyEventBook, } from '../../resources/js/lib/iva-currency-events.ts'; const frozen = JSON.parse( fs.readFileSync( 'tests/frontend/fixtures/iva-foreign-operations-preserved.json', 'utf8', ), ), original = JSON.parse(frozen.modelo_a_snapshot); function seed() { const d = { ...frozen, context_opportunity: 'opportunity:358', project_title: 'SYNTHETIC QA — Operações no estrangeiro / Manica', }; for (const [map, record, save] of [ ['goodsLocations', recordGoodsLocations, saveGoodsLocationBook], ['serviceLocations', recordServiceLocations, saveServiceLocationBook], ['listedServices', recordListedServices, saveListedServiceBook], ]) { const rows = structuredClone(Object.values(original[map])[0].rows).map( (r) => ({ ...r, operationRef: 'SYNTHETIC QA op ' + r.id }), ); if (map === 'serviceLocations') { const r = structuredClone( rows.find((x) => x.id === 'transport_service-MZ'), ); rows.push({ ...r, id: 'transport_partial', operationRef: 'SYNTHETIC QA op transport_partial', departure: 'MZ', arrival: 'foreign', nationalDistance: '20', totalDistance: '100', }); } d.modelo_a_snapshot = save(d, record(d, { rows })); } const event = structuredClone( original.currencyEvents['opportunity:357'].rows.find( (r) => r.treatment === 'goods_available', ), ); event.operationRef = 'SYNTHETIC QA op g8a-goods_without_transport'; d.modelo_a_snapshot = saveCurrencyEventBook( d, recordCurrencyEvents(d, { rows: [event] }), ); return d; } const draft = seed(); function row(id, kind, source) { return { ...newForeignOperation(id), sourceKind: kind, sourceRowId: source, territorialPart: 'outside', hypotheticalTaxable: 'yes', hypotheticalRef: 'SYNTHETIC QA hipótese interna/natureza tributável e19(2),fundamento identificado', excluded19_2: 'no', scope: 'SYNTHETIC QA conjunto/parcela exterior/período identificado', evidence: 'SYNTHETIC QA factos/pressupostos expressos', }; } const cases = [ row('foreign_goods', 'goods', 'g8a-goods_without_transport'), row('foreign_services', 'services', 'general_service-foreign'), row('foreign_listed', 'listed', 'rights_service-outbound'), row('foreign_transport_part', 'services', 'transport_partial'), ]; cases[0].eventRowId = 'goods_available'; for (const r of cases) void test( 'P002 ' + r.id + ' reuses delivered territoriality and potential19only', () => { const v = evaluateForeignOperation(draft, r); assert.equal(v.status, 'determined'); assert.equal(v.relation19, 'potential'); assert.equal( v.territory, r.id === 'foreign_transport_part' ? 'outside_portion' : 'outside', ); assert.equal(v.deduction, null); assert.equal(v.vat, null); assert.equal(v.baseAmount, null); assert.equal(v.source.id, r.sourceRowId); assert.equal(v.source.current, true); if (r.eventRowId) assert.equal(v.event.eventDate, '2026-12-10'); }, ); void test('P002 unknown/national/partial do not imply foreign or exemption', () => { assert.equal( evaluateForeignOperation(draft, { ...cases[0], sourceRowId: '' }) .status, 'indeterminate', ); assert.equal( evaluateForeignOperation(draft, { ...cases[0], sourceRowId: 'g8a-goods_with_transport', }).status, 'not_applicable', ); assert.equal( evaluateForeignOperation(draft, { ...cases[3], territorialPart: '' }) .status, 'indeterminate', ); assert.equal( evaluateForeignOperation(draft, { ...cases[3], territorialPart: 'national', }).status, 'not_applicable', ); for (const patch of [ { scope: '' }, { evidence: '' }, { hypotheticalRef: '' }, { hypotheticalTaxable: '' }, { excluded19_2: '' }, ]) assert.equal( evaluateForeignOperation(draft, { ...cases[0], ...patch }).status, 'indeterminate', ); const no = evaluateForeignOperation(draft, { ...cases[0], hypotheticalTaxable: 'no', }); assert.equal(no.relation19, 'not_demonstrated'); assert.equal(no.deduction, null); const excluded = evaluateForeignOperation(draft, { ...cases[0], excluded19_2: 'yes', }); assert.equal(excluded.relation19, 'excluded_19_2'); assert.equal(excluded.deduction, null); }); void test('P002 stale source and event scope mismatch never overwrite prior acceptance', () => { const b = goodsLocationBook(draft), changed = { ...draft, modelo_a_snapshot: saveGoodsLocationBook(draft, { ...b, rows: b.rows.map((r) => r.id === cases[0].sourceRowId ? { ...r, placeCountry: 'MZ' } : r, ), }), }; assert.equal( evaluateForeignOperation(changed, cases[0]).status, 'indeterminate', ); assert.equal( evaluateForeignOperation( { ...draft, context_opportunity: 'opportunity:359' }, cases[0], ).status, 'indeterminate', ); assert.equal( evaluateForeignOperation(draft, { ...cases[1], eventRowId: 'goods_available', }).status, 'indeterminate', ); const sw = switchForeignSource( cases[0], 'services', 'general_service-foreign', ); assert.equal(sw.hypotheticalRef, cases[0].hypotheticalRef); assert.equal(sw.hypotheticalTaxable, ''); assert.equal(sw.eventRowId, ''); assert.equal(foreignEvents(draft).length, 1); assert.equal(foreignSources(draft, 'goods').length, 3); }); void test('P002 dependency changes invalidate new analysis while snapshot/history stay immutable', () => { const a = recordForeignOperations(draft, { rows: cases }), d = { ...draft, modelo_a_snapshot: saveForeignOperationBook(draft, a) }; assert.equal(foreignOperationCurrent(d, a), true); const b = goodsLocationBook(d), changed = { ...d, modelo_a_snapshot: saveGoodsLocationBook( d, recordGoodsLocations(d, b), ), }; assert.equal(foreignOperationCurrent(changed, a), false); assert.deepEqual(a.result.inputs, cases); assert.equal(foreignOperationReportRows(d).length, 4); }); void test('P002 private save/recovery/report preserve 120delivered books and P104currency facts', () => { const rows = [ ...cases, row('national', 'goods', 'g8a-goods_with_transport'), { ...cases[1], id: 'hypothesis_not_taxable', hypotheticalTaxable: 'no', }, { ...cases[2], id: 'exclusion19_2', excluded19_2: 'yes' }, ], a = recordForeignOperations(draft, { rows }), d = { ...draft, modelo_a_snapshot: saveForeignOperationBook(draft, a) }, b = recordForeignOperations(d, a); d.modelo_a_snapshot = saveForeignOperationBook(d, b); assert.equal(b.history.length, 1); assert.equal(foreignOperationReportRows(d).length, 7); const store = JSON.parse(d.modelo_a_snapshot); delete store.foreignOperations; for (const name of [ 'goodsLocations', 'serviceLocations', 'listedServices', 'currencyEvents', ]) delete store[name]['opportunity:358']; assert.deepEqual(store, original); assert.deepEqual( foreignOperationBook({ ...d, context_opportunity: 'opportunity:359' }), { rows: [] }, ); assert.throws(() => recordForeignOperations(d, { rows: [rows[0], rows[0]] }), ); assert.throws(() => foreignOperationBook({ ...d, modelo_a_snapshot: JSON.stringify({ ...store, foreignOperations: [], }), }), ); if (process.env.IVA_FOREIGN_OPERATIONS_FIXTURE) fs.writeFileSync( process.env.IVA_FOREIGN_OPERATIONS_FIXTURE, JSON.stringify(d, null, 2) + '\n', ); });