import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newSalesOperation, recordSales, saveSalesBook, salesBook, operationTreatments, } from '../../resources/js/lib/iva-operations.ts'; import { newAcquisition, evaluateAcquisition, recordAcquisitions, saveAcquisitionBook, acquisitionBook, acquisitionCurrent, acquisitionReportRows, readAcquisitionStore, } from '../../resources/js/lib/iva-acquisitions.ts'; import { createAcquisitionRightLink, linkedOperationRight, } from '../../resources/js/lib/iva-acquisition-right.ts'; const frozen = JSON.parse( fs.readFileSync( new URL('./fixtures/iva-l2a-preserved.json', import.meta.url), 'utf8', ), ); export function rightFixture() { const draft = { ...structuredClone(frozen), context_opportunity: 'opportunity:368', project_title: 'SYNTHETIC QA — L2-A aquisição e direito', }; const types = [ 'general', 'export_goods', 'listed_maize', 'housing_rent', 'private_health', ]; const operations = { currency: 'MZN', periods: [{ period: '2026-12', complete: true }], rows: types.map((t, i) => ({ ...newSalesOperation('operation-' + i, '2026-12', 'MZN'), description: 'SYNTHETIC QA ' + t, amount: '100', basis: 'net', establishment: 'Mozambique', treatment: t, confirmed: operationTreatments .find((x) => x.id === t) .conditions.map((_, j) => j), evidence: 'SYNTHETIC QA fonte e condições', })), }; draft.modelo_a_snapshot = saveSalesBook( draft, recordSales(draft, operations), ); const rows = types.map((_, i) => ({ ...newAcquisition('purchase-' + i, '2026-12', 'MZN'), net: '100', vat: '16', gross: '116', description: 'SYNTHETIC QA compra ' + i, documentType: 'invoice', documentRef: 'SYNTHETIC QA ' + i, documentDate: '2026-12-10', supplier: 'SYNTHETIC QA fornecedor', supplierRegistered: 'yes', legalDocument: 'yes', held: 'yes', domestic: 'yes', allocation: 'taxable_only', exclusion: 'none', integrity: 'yes', deductionLink: { ...createAcquisitionRightLink(draft, 'operation-' + i), scopeConfirmed: 'yes', allocationRef: 'Afectação exclusiva SYNTHETIC QA ' + i, noExcludedPayments: 'yes', }, })); return { draft, book: { currency: 'MZN', taxpayerRegistered: 'yes', rows, periods: [ { period: '2026-12', complete: true, absent: ['11', '12', '13'], }, ], }, }; } void test('right follows classified operation, including exempt with right and taxed17-A without right', () => { const { draft, book } = rightFixture(); const results = book.rows.map((r) => evaluateAcquisition(r, 'MZN', 'yes', draft), ); assert.deepEqual( results.map((r) => r.eligibility.status), ['eligible', 'eligible', 'eligible', 'no_right', 'no_right'], ); assert.deepEqual( results.map((r) => r.deductible), ['16.00', '16.00', '16.00', '0.00', '0.00'], ); for (const r of results) { assert.ok(r.eligibility.reason); assert.match(r.eligibility.source, /Lei10\/2025/); } assert.match(results[4].reason, /17-A/); }); void test('own documentary conditions, missing data, imports and mixed use remain distinct from operation right', () => { const { draft, book } = rightFixture(), row = book.rows[0]; for (const patch of [ { held: '' }, { documentRef: '' }, { documentDate: '2026-11-10' }, { allocation: 'mixed' }, { domestic: 'no' }, { exclusion: 'special' }, { sourceCurrency: 'USD' }, { vat: '0', gross: '100', held: '' }, { sourceMonth: 1, sourceAmount: '999', sourceBasis: 'net' }, ]) { const r = evaluateAcquisition( { ...row, ...patch }, 'MZN', 'yes', draft, ); assert.equal( r.eligibility.status, 'indeterminate', JSON.stringify(patch), ); assert.equal(r.deductible, null); } for (const patch of [ { exclusion: 'excluded' }, { supplierRegistered: 'no' }, { integrity: 'no' }, ]) assert.equal( evaluateAcquisition({ ...row, ...patch }, 'MZN', 'yes', draft) .eligibility.status, 'no_right', ); assert.equal( evaluateAcquisition( { ...row, deductionLink: { ...row.deductionLink, scopeConfirmed: '' }, }, 'MZN', 'yes', draft, ).deductible, null, ); assert.equal( evaluateAcquisition( { ...row, deductionLink: { ...row.deductionLink, noExcludedPayments: 'no', }, }, 'MZN', 'yes', draft, ).deductible, '0.00', ); assert.equal(evaluateAcquisition(row, 'MZN', 'yes').deductible, null); }); void test('totals F include only eligible amounts; unknown never becomes zero; no duplicated projected/effective invoice', () => { const { draft, book } = rightFixture(); const result = recordAcquisitions(draft, book).result; assert.equal(result.periods[0].fields['09'], '48.00'); assert.equal(result.periods[0].fields['15'], '48.00'); assert.deepEqual( ['14', '15', '16', '17', '18'].map((f) => result.periods[0].fields[f]), ['500.00', '48.00', '21.00', '0.00', '27.00'], ); const cleared = structuredClone(book); cleared.rightVersion = 'acquisition-operation-right/1'; cleared.rows = cleared.rows.map( ({ deductionLink: _deductionLink, ...row }) => row, ); const empty = recordAcquisitions(draft, cleared).result; assert.ok( empty.rows.every((r) => r.eligibility.status === 'indeterminate'), ); assert.equal(empty.periods[0].fields['15'], null); const unknown = structuredClone(book); unknown.rows[0].held = ''; assert.equal( recordAcquisitions(draft, unknown).result.periods[0].fields['15'], null, ); const duplicate = structuredClone(book); duplicate.rows.push({ ...duplicate.rows[0], id: 'copy', origin: 'effective', }); assert.throws(() => recordAcquisitions(draft, duplicate), /dupla dedução/); }); void test('source edits require explicit adoption; save recovery report and historical versions preserve old books byte for byte', () => { let { draft, book } = rightFixture(); const before = JSON.parse(frozen.modelo_a_snapshot); book = recordAcquisitions(draft, book); draft.modelo_a_snapshot = saveAcquisitionBook(draft, book); const first = structuredClone(book.result); book = recordAcquisitions(draft, book); draft.modelo_a_snapshot = saveAcquisitionBook(draft, book); const recovered = JSON.parse(JSON.stringify(draft)); assert.deepEqual(acquisitionBook(recovered), book); assert.ok(acquisitionCurrent(recovered, book)); assert.deepEqual(book.history, [first]); const after = JSON.parse(draft.modelo_a_snapshot); for (const key of Object.keys(before)) { if (key === 'version') continue; for (const [id, value] of Object.entries(before[key])) assert.deepEqual(after[key][id], value, key + id); } const report = JSON.stringify(acquisitionReportRows(recovered)); for (const word of [ 'Elegível', 'Sem direito', 'Lei10/2025', '48.00', 'operation-4', ]) assert.ok(report.includes(word), word); const ops = salesBook(draft); ops.rows[0].description = 'Alteração deliberada'; draft.modelo_a_snapshot = saveSalesBook(draft, recordSales(draft, ops)); assert.equal(acquisitionCurrent(draft, book), false); assert.equal( linkedOperationRight(draft, book.rows[0].deductionLink).status, 'indeterminate', ); assert.deepEqual(book.history[0], first); assert.deepEqual( book.result, recovered ? acquisitionBook(recovered).result : null, ); const adopted = createAcquisitionRightLink( draft, book.rows[0].deductionLink.operationId, ); assert.equal(adopted.scopeConfirmed, ''); assert.equal(adopted.allocationRef, ''); assert.equal(linkedOperationRight(draft, adopted).status, 'eligible'); assert.equal( evaluateAcquisition( { ...book.rows[0], deductionLink: adopted }, 'MZN', 'yes', draft, ).deductible, null, ); assert.equal( linkedOperationRight( { ...draft, context_opportunity: 'opportunity:329' }, adopted, ).status, 'indeterminate', ); const malformed = JSON.parse(draft.modelo_a_snapshot); malformed.books['opportunity:368'].rows[0].deductionLink.version = 9; assert.throws( () => readAcquisitionStore(JSON.stringify(malformed)), /Vínculo/, ); if (process.env.IVA_L2A_CALCULATED) fs.writeFileSync( process.env.IVA_L2A_CALCULATED, JSON.stringify(recovered), ); });