import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newPublicBase, publicBaseTreatments, publicBaseConditions, evaluatePublicBase, recordPublicBases, savePublicBaseBook, publicBaseBook, publicBaseCurrent, publicBaseReportRows, } from '../../resources/js/lib/iva-public-authority-base.ts'; import { importExemptionCurrent } from '../../resources/js/lib/iva-import-exemptions.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const frozen = JSON.parse( fs.readFileSync( new URL('./fixtures/iva-g7a-preserved-inputs.json', import.meta.url), 'utf8', ), ); const row = (treatment = publicBaseTreatments[0].id) => ({ ...newPublicBase('g7a-' + treatment, 'MZN'), treatment, description: 'SYNTHETIC QA compensação por acto público', operationNature: treatment === 'public_authority_indemnity' ? 'goods' : 'services', period: '2026-12', authority: 'SYNTHETIC QA autoridade pública', actRef: 'SYNTHETIC QA acto A,operação própria', documentRef: 'SYNTHETIC QA G7A ' + treatment, documentDate: '2026-11-14', compensationForm: treatment === 'public_authority_indemnity' ? 'money' : 'mixed', moneyAmount: treatment === 'public_authority_indemnity' ? '1500.25' : '1000.10', nonMoneyValue: '250.20', valuationRef: 'SYNTHETIC QA valor normal nos termos15(4),pressuposto explícito', compositionRef: 'SYNTHETIC QA documento A,composição15(5)/(6),semIVA e sem duplicações', evidence: 'SYNTHETIC QA pressupostos;operação sujeita e ligada ao acto,não incumprimento contratual judicial', conditions: Object.fromEntries( publicBaseConditions.map(([key]) => [key, 'yes']), ), }); const draft = () => ({ ...structuredClone(frozen), context_opportunity: 'opportunity:339', project_title: 'SYNTHETIC QA — G7A / Base de actos públicos', }); void test('P090 bases distinguish indemnity/other compensation from incidence,tax and judicial contract-breach exclusion', () => { for (const treatment of publicBaseTreatments) { const input = row(treatment.id), ok = evaluatePublicBase(input, 'MZN'); assert.equal(ok.status, 'determined'); assert.equal( ok.baseAmount, treatment.id === 'public_authority_indemnity' ? '1500.25' : '1250.30', ); assert.equal(ok.vat, null); assert.equal(ok.rate, null); for (const [key] of publicBaseConditions) for (const value of ['', 'unknown', 'no']) { const r = evaluatePublicBase( { ...input, conditions: { ...input.conditions, [key]: value }, }, 'MZN', ); assert.equal( r.status, value === 'no' ? 'not_applicable' : 'indeterminate', ); assert.equal(r.baseAmount, null); assert.equal(r.vat, null); } for (const patch of [ { authority: '' }, { actRef: '' }, { compositionRef: '' }, { operationNature: '' }, { documentDate: '2026-02-30' }, { documentRef: '' }, { period: '2025-12' }, { currency: 'USD' }, ]) assert.equal( evaluatePublicBase({ ...input, ...patch }, 'MZN').baseAmount, null, ); } assert.match( evaluatePublicBase( { ...row(), conditions: { ...row().conditions, notJudicialContractBreach: 'no', }, }, 'MZN', ).reason, /15\(6\)\(a\)/, ); }); void test('money,in-kind,mixed compute exact net components;unknown differs from explicit zero and hidden values are retained', () => { const input = row(); for (const [patch, expected] of [ [{ compensationForm: 'money', moneyAmount: '0' }, '0.00'], [ { compensationForm: 'non_money', moneyAmount: '', nonMoneyValue: '250.20', }, '250.20', ], [ { compensationForm: 'mixed', moneyAmount: '0.000001', nonMoneyValue: '0.000002', }, '0.000003', ], [ { compensationForm: 'mixed', moneyAmount: '999999999999999.999999', nonMoneyValue: '999999999999999.999999', }, '1999999999999999.999998', ], ]) { const r = evaluatePublicBase({ ...input, ...patch }, 'MZN'); assert.equal(r.baseAmount, expected); assert.equal(r.vat, null); } for (const patch of [ { compensationForm: '' }, { moneyAmount: '' }, { moneyAmount: '-1' }, { moneyAmount: 'NaN' }, { moneyAmount: '1.0000001' }, { compensationForm: 'mixed', nonMoneyValue: '' }, { compensationForm: 'non_money', valuationRef: '' }, ]) assert.equal( evaluatePublicBase({ ...input, ...patch }, 'MZN').baseAmount, null, ); const switched = { ...input, compensationForm: 'non_money' }; assert.equal(switched.moneyAmount, '1500.25'); assert.equal(evaluatePublicBase(switched, 'MZN').baseAmount, '250.20'); assert.equal( evaluatePublicBase({ ...switched, compensationForm: 'mixed' }, 'MZN') .baseAmount, '1750.45', ); }); void test('save/recovery/report isolate P090 from78delivered branches and partial offers,while keeping exact versions and contextual invalidation', () => { const d = draft(), prior = JSON.parse(d.modelo_a_snapshot); assert.deepEqual(publicBaseBook(d), { rows: [] }); assert.deepEqual(publicBaseReportRows(d), []); let book = recordPublicBases(d, { rows: publicBaseTreatments.map((rule) => ({ ...row(rule.id), conditions: {}, })), }); book = recordPublicBases(d, { ...book, rows: publicBaseTreatments.map((rule) => ({ ...row(rule.id), conditions: { ...row(rule.id).conditions, notJudicialContractBreach: 'no', }, })), }); book = recordPublicBases(d, { ...book, rows: publicBaseTreatments.map((rule) => row(rule.id)), }); assert.equal(book.history.length, 2); assert.ok( book.history.every((h) => h.rows.every((r) => r.baseAmount === null && r.vat === null), ), ); assert.ok(publicBaseCurrent(d, book)); for (const field of [ 'actRef', 'documentRef', 'compositionRef', 'compensationForm', 'valuationRef', 'moneyAmount', ]) assert.ok( !publicBaseCurrent(d, { ...book, rows: book.rows.map((r) => ({ ...r, [field]: 'changed' })), }), ); for (const patch of [ { context_opportunity: 'opportunity:340' }, { currency: 'USD' }, { selection_labels: { province_id: 'Maputo' } }, ]) assert.ok(!publicBaseCurrent({ ...d, ...patch }, book)); d.modelo_a_snapshot = savePublicBaseBook(d, book); assert.deepEqual(publicBaseBook(JSON.parse(JSON.stringify(d))), book); const next = JSON.parse(d.modelo_a_snapshot); const { publicAuthorityBases: _publicAuthorityBases, ...untouched } = next; assert.deepEqual(untouched, prior); for (const [scope, previous] of Object.entries(prior.importExemptions)) assert.ok( importExemptionCurrent( { ...d, context_opportunity: scope }, previous, ), ); assert.equal( next.importExemptions['opportunity:338'].result.rows[1].importVat, '400.00', ); assert.equal( next.importExemptions['opportunity:336'].result.rows[0].serviceVat, '0.00', ); assert.equal( next.books['opportunity:329'].result.periods[0].fields['11'], null, ); const report = JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), version: 'QA G7A', }), ); for (const token of [ 'Base P090', '1500.25', '1250.30', 'IVA: Indeterminado', 'opportunity:339', 'Manica', '2026-12', 'acto A', '15(2)(d)', 'composição15(5)/(6)', 'campo11', ]) assert.ok(report.includes(token), token); assert.deepEqual( publicBaseReportRows({ ...d, context_opportunity: 'opportunity:340' }), [], ); if (process.env.IVA_G7A_CALCULATED) fs.writeFileSync(process.env.IVA_G7A_CALCULATED, JSON.stringify(d)); }); void test('malformed public-base rows/store cannot replace originals;duplicate identifiers cannot create calculations', () => { const d = draft(), original = d.modelo_a_snapshot; for (const patch of [ { moneyAmount: 4 }, { conditions: [] }, { valuationRef: null }, ]) assert.throws( () => savePublicBaseBook(d, { rows: [{ ...row(), ...patch }] }), /originais preservados/, ); assert.equal(d.modelo_a_snapshot, original); assert.throws( () => recordPublicBases(d, { rows: [row(), row()] }), /distintos/, ); assert.throws(() => recordPublicBases(d, { rows: [] }), /distintos/); const bad = { ...d, modelo_a_snapshot: JSON.stringify({ ...JSON.parse(original), publicAuthorityBases: [], }), }; assert.throws(() => publicBaseBook(bad), /originais preservados/); assert.equal(d.modelo_a_snapshot, original); });