import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { digitalTreatments, digitalConditions, newDigitalRow, evaluateDigital, recordDigital, saveDigitalBook, digitalBook, digitalCurrent, digitalReportRows, switchDigitalKind, switchDigitalTreatment, } from '../../resources/js/lib/iva-digital.ts'; import { newForeignOperation, recordForeignOperations, saveForeignOperationBook, foreignOperationCurrent, foreignSources, } from '../../resources/js/lib/iva-foreign-operations.ts'; const frozen = JSON.parse( fs.readFileSync( 'tests/frontend/fixtures/iva-digital-preserved.json', 'utf8', ), ), prior = JSON.parse(frozen.modelo_a_snapshot); const draft = { ...frozen, context_opportunity: 'opportunity:359', project_title: 'SYNTHETIC QA — Digital / Manica', }; function row(rule, direction = 'inbound') { return { ...newDigitalRow(rule.id + '-' + direction), kind: rule.kind, treatment: rule.id, description: 'SYNTHETIC QA ' + rule.label, period: '2026-12', origin: 'projected', operationDate: '2026-12-10', operationRef: 'SYNTHETIC QA op ' + rule.id + '-' + direction, documentRef: 'SYNTHETIC QA contrato/previsão', documentDate: '2026-12-01', subjectRef: 'SYNTHETIC QA objecto/direitos/funcionalidade delimitados', useRef: 'SYNTHETIC QA destinatário e utilização', natureRef: 'SYNTHETIC QA natureza contratual ' + rule.kind, scope: 'SYNTHETIC QA operação/dezembro2026/âmbito identificado', evidence: 'SYNTHETIC QA factos ou pressupostos expressos', providerPlace: 'SYNTHETIC QA estabelecimento fornecedor', providerCountry: direction === 'inbound' ? 'foreign' : 'MZ', providerRef: 'SYNTHETIC QA contrato/estabelecimento fornecedor', buyerPlace: 'SYNTHETIC QA domicílio adquirente', buyerCountry: direction === 'outbound' ? 'foreign' : 'MZ', buyerRef: 'SYNTHETIC QA contrato/domicílio adquirente', buyerTaxable: 'yes', buyerTaxRef: 'SYNTHETIC QA sujeito passivo nacional, incluindo isento sem dedução', providerTaxable: 'yes', providerTaxRef: 'SYNTHETIC QA sujeito passivo fornecedor', goodsPlace: 'MZ', goodsPlaceRef: 'SYNTHETIC QA factos local6(1),não inferido de IP/servidor', conditions: Object.fromEntries( digitalConditions(rule.kind).map(([k]) => [k, 'yes']), ), }; } const cases = digitalTreatments.flatMap((rule) => ['inbound', 'outbound', 'domestic'].map((direction) => row(rule, direction), ), ); for (const r of cases) void test(`${r.kind === 'goods' ? 'P130' : 'P121'} ${r.id} classification and responsibility`, () => { const v = evaluateDigital(r); assert.equal(v.status, 'determined'); assert.equal( v.territory, r.buyerCountry === 'foreign' ? 'outside' : 'national', ); assert.equal( v.responsible, r.buyerCountry === 'foreign' ? 'outside' : r.providerCountry === 'foreign' ? 'acquirer' : 'provider', ); assert.equal( v.declarationReferenceDate, r.providerCountry === 'foreign' && r.buyerCountry === 'MZ' ? '2027-01-10' : null, ); assert.equal( v.procedure, r.buyerCountry === 'foreign' ? 'outside' : r.providerCountry === 'foreign' ? 'regulation_pending' : 'general', ); for (const k of ['vat', 'baseAmount', 'rate', 'deduction']) assert.equal(v[k], null); }); void test('Unknown facts do not become national, exempt or zero; no name-only kind inference', () => { const r = cases[0]; for (const patch of [ { kind: '' }, { kind: 'goods' }, { period: '2025-12' }, { operationDate: '2026-02-30' }, { operationDate: '2026-11-10' }, { origin: 'unknown' }, { documentDate: '2026-02-30' }, { subjectRef: '' }, { useRef: '' }, { natureRef: '' }, { scope: '' }, { evidence: '' }, { buyerCountry: '' }, { buyerRef: '' }, { providerRef: '' }, ]) assert.equal( evaluateDigital({ ...r, ...patch }).status, 'indeterminate', ); for (const [k] of digitalConditions(r.kind)) { assert.equal( evaluateDigital({ ...r, conditions: { ...r.conditions, [k]: '' } }) .status, 'indeterminate', ); assert.equal( evaluateDigital({ ...r, conditions: { ...r.conditions, [k]: 'no' }, }).status, 'not_applicable', ); } const outbound = { ...cases[1], providerCountry: '', providerRef: '', providerPlace: '', buyerTaxable: '', buyerTaxRef: '', }; assert.equal(evaluateDigital(outbound).territory, 'outside'); }); void test('26(4) quality/reference independent of national territory; consumer never automatic withholding', () => { for (const r of [cases[0], cases.find((r) => r.kind === 'goods')]) for (const patch of [ { buyerTaxable: '' }, { buyerTaxRef: '' }, { buyerTaxable: 'no' }, ]) { const v = evaluateDigital({ ...r, ...patch }); assert.equal(v.territory, 'national'); assert.equal(v.status, 'determined'); assert.equal(v.responsible, 'indeterminate'); assert.equal(v.declarationReferenceDate, null); } const r = { ...cases[0], buyerTaxable: 'no', buyerTaxRef: 'SYNTHETIC QA consumidor', representative: 'yes', representativeRef: 'SYNTHETIC QA residente/procuração/poderes', communicationPrior: 'yes', communicationRef: 'SYNTHETIC QA comunicação anterior', }; assert.equal(evaluateDigital(r).responsible, 'representative'); assert.equal(evaluateDigital(r).declarationReferenceDate, null); for (const patch of [ { providerTaxRef: '' }, { representativeRef: '' }, { communicationPrior: 'no' }, { communicationRef: '' }, ]) assert.equal( evaluateDigital({ ...r, ...patch }).responsible, 'indeterminate', ); const business = { ...r, representative: 'no', businessUse: 'yes', businessRef: 'SYNTHETIC QA actividade/aquisição profissional', }; assert.equal(evaluateDigital(business).responsible, 'acquirer'); assert.equal( evaluateDigital({ ...business, businessUse: 'no' }).responsible, 'indeterminate', ); assert.equal( evaluateDigital({ ...business, businessRef: '' }).responsible, 'indeterminate', ); }); void test('Domestic digital goods need demonstrated6(1) location, not consumer address/server; domestic services6(3)', () => { const r = cases.find( (r) => r.kind === 'goods' && r.id.endsWith('domestic'), ); assert.equal(evaluateDigital({ ...r, goodsPlace: '' }).territory, null); assert.equal( evaluateDigital({ ...r, goodsPlaceRef: '' }).status, 'indeterminate', ); assert.equal( evaluateDigital({ ...r, goodsPlace: 'foreign' }).territory, 'outside', ); assert.equal( evaluateDigital({ ...cases[2], goodsPlace: '', goodsPlaceRef: '' }) .territory, 'national', ); assert.equal( evaluateDigital({ ...r, providerTaxable: '' }).responsible, 'indeterminate', ); }); void test('Switching nature/treatment preserves deliberate references and hidden facts, rechecks specific conditions', () => { const r = cases[0], sw = switchDigitalKind(r, 'goods'); assert.equal(sw.treatment, ''); assert.deepEqual(sw.conditions, {}); for (const k of [ 'natureRef', 'buyerTaxRef', 'goodsPlaceRef', 'scope', 'evidence', ]) assert.equal(sw[k], r[k]); assert.deepEqual(switchDigitalTreatment(r, 'teaching').conditions, {}); }); void test('Opportunity isolation, stable history and malformed-store guard; all prior books including P002 immutable', () => { const a = recordDigital(draft, { rows: cases }), d = { ...draft, modelo_a_snapshot: saveDigitalBook(draft, a) }, b = recordDigital(d, a); d.modelo_a_snapshot = saveDigitalBook(d, b); assert.equal(digitalCurrent(d, b), true); assert.equal(b.history.length, 1); assert.equal(digitalReportRows(d).length, 42); assert.deepEqual( digitalBook({ ...d, context_opportunity: 'opportunity:358' }), { rows: [] }, ); const changed = { ...b, rows: b.rows.map((r, i) => i === 0 ? { ...r, buyerCountry: 'foreign' } : r, ), }; assert.equal(digitalCurrent(d, changed), false); assert.equal(b.history[0].inputs[0].buyerCountry, 'MZ'); assert.equal(b.history[0].rows[0].territory, 'national'); const store = JSON.parse(d.modelo_a_snapshot); delete store.digitalOperations; assert.deepEqual(store, prior); assert.throws(() => recordDigital(d, { rows: [cases[0], cases[0]] })); assert.throws(() => digitalBook({ ...d, modelo_a_snapshot: JSON.stringify({ ...store, digitalOperations: [], }), }), ); assert.throws(() => digitalBook({ ...d, modelo_a_snapshot: JSON.stringify({ ...store, digitalOperations: { x: { rows: [{ id: 'incomplete' }] } }, }), }), ); }); void test('P002 reuses new digital location in same opportunity, guards stale source and keeps accepted P002 snapshots', () => { const a = recordDigital(draft, { rows: cases }), d = { ...draft, modelo_a_snapshot: saveDigitalBook(draft, a) }, r = { ...newForeignOperation('digital-outside'), sourceKind: 'digital', sourceRowId: cases[1].id, hypotheticalTaxable: 'yes', hypotheticalRef: 'SYNTHETIC QA hipótese interna', excluded19_2: 'no', scope: 'SYNTHETIC QA operação digital exterior', evidence: 'SYNTHETIC QA pressupostos', }; assert.equal(foreignSources(d, 'digital').length, 42); const b = recordForeignOperations(d, { rows: [r] }); assert.equal(b.result.rows[0].relation19, 'potential'); assert.equal(b.result.rows[0].deduction, null); d.modelo_a_snapshot = saveForeignOperationBook(d, b); assert.equal(foreignOperationCurrent(d, b), true); const next = { ...d, modelo_a_snapshot: saveDigitalBook(d, recordDigital(d, a)), }; assert.equal(foreignOperationCurrent(next, b), false); assert.equal(b.result.rows[0].source.revision, 1); assert.deepEqual( JSON.parse(d.modelo_a_snapshot).foreignOperations['opportunity:358'], prior.foreignOperations['opportunity:358'], ); }); void test('Fixture for private API includes42 examples and unresolved/representative/business cases', () => { const inbound = cases[0], extra = [ { ...inbound, id: 'consumer', buyerTaxable: 'no', buyerTaxRef: 'SYNTHETIC QA consumidor', }, { ...inbound, id: 'unknown_quality', buyerTaxable: '', buyerTaxRef: '', }, { ...inbound, id: 'representative', buyerTaxable: 'no', buyerTaxRef: 'SYNTHETIC QA não sujeito passivo', representative: 'yes', representativeRef: 'SYNTHETIC QA representante/procuração', communicationPrior: 'yes', communicationRef: 'SYNTHETIC QA comunicação anterior', }, { ...inbound, id: 'business_26_3', buyerTaxable: 'no', buyerTaxRef: 'SYNTHETIC QA não sujeito passivo', representative: 'no', businessUse: 'yes', businessRef: 'SYNTHETIC QA actividade profissional', }, ], a = recordDigital(draft, { rows: [...cases, ...extra] }), d = { ...draft, modelo_a_snapshot: saveDigitalBook(draft, a) }, b = recordDigital(d, a); d.modelo_a_snapshot = saveDigitalBook(d, b); assert.equal(b.rows.length, 46); assert.equal(b.history.length, 1); if (process.env.IVA_DIGITAL_FIXTURE) fs.writeFileSync( process.env.IVA_DIGITAL_FIXTURE, JSON.stringify(d, null, 2) + '\n', ); });