import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newServiceNormal, switchServiceTreatment, serviceNormalTreatments, serviceNormalConditions, ownServiceConditions, evaluateServiceNormal, recordServiceNormals, saveServiceNormalBook, serviceNormalBook, serviceNormalCurrent, serviceNormalReportRows, } from '../../resources/js/lib/iva-service-normal.ts'; import { valueReviewCurrent } from '../../resources/js/lib/iva-value-review.ts'; import { exclusionCurrent } from '../../resources/js/lib/iva-exclusion-base.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const frozen = JSON.parse( fs.readFileSync( new URL('./fixtures/iva-g7i-preserved-inputs.json', import.meta.url), 'utf8', ), ); const row = (treatment = 'free_company_service') => ({ ...newServiceNormal('g7i-' + treatment, 'MZN'), treatment, description: 'SYNTHETIC QA serviço A', period: '2026-12', operationRef: 'SYNTHETIC QA operação A', purposeRef: 'SYNTHETIC QA finalidade/destinatário ou sector isento A', assetRef: 'SYNTHETIC QA bens/elementos A', deductionRef: 'SYNTHETIC QA referência dedução anterior parcial A', documentRef: 'SYNTHETIC QA G7I ' + treatment, documentDate: '2026-12-12', normalValue: { free_company_service: '500.25', private_company_asset_use: '700.50', exempt_sector_asset_use: '900.75', }[treatment], valuationRef: 'SYNTHETIC QA valor normal serviço A15(4)', valuationScope: 'SYNTHETIC QA serviço A,estádio/tempo/lugar/concorrência/fornecedor independente,dezembro2026Manica', compositionRef: 'SYNTHETIC QA composição15(4)/(5)/(6),sem próprioIVA', evidence: 'SYNTHETIC QA pressupostos expressos,não documento real', conditions: Object.fromEntries( [...serviceNormalConditions, ...ownServiceConditions(treatment)].map( ([key]) => [key, 'yes'], ), ), }); const draft = () => ({ ...structuredClone(frozen), context_opportunity: 'opportunity:347', project_title: 'SYNTHETIC QA — G7I / Valor normal de serviços', }); void test('P089 three treatments ownconditions and normalvalue references;prior deduction applies only to assetuse', () => { for (const t of serviceNormalTreatments) { const input = row(t.id); assert.equal( evaluateServiceNormal(input, 'MZN').baseAmount, input.normalValue, ); assert.equal(evaluateServiceNormal(input, 'MZN').vat, null); assert.equal(evaluateServiceNormal(input, 'MZN').rate, null); for (const [key] of [ ...serviceNormalConditions, ...ownServiceConditions(t.id), ]) for (const value of ['', 'unknown', 'no']) { const r = evaluateServiceNormal( { ...input, conditions: { ...input.conditions, [key]: value }, }, 'MZN', ); assert.equal( r.status, value === 'no' ? 'not_applicable' : 'indeterminate', ); assert.equal(r.baseAmount, null); } for (const patch of [ { description: '' }, { operationRef: '' }, { purposeRef: '' }, { documentRef: '' }, { documentDate: '2026-02-30' }, { valuationRef: '' }, { valuationScope: '' }, { compositionRef: '' }, { evidence: '' }, { period: '2025-12' }, { currency: 'USD' }, { treatment: '' }, { normalValue: '' }, ]) assert.equal( evaluateServiceNormal({ ...input, ...patch }, 'MZN').baseAmount, null, ); if (t.id !== 'free_company_service') for (const patch of [{ assetRef: '' }, { deductionRef: '' }]) assert.equal( evaluateServiceNormal({ ...input, ...patch }, 'MZN') .baseAmount, null, ); } const free = row(); assert.equal( evaluateServiceNormal( { ...free, assetRef: '', deductionRef: '', conditions: { ...free.conditions, priorDeduction: 'no' }, }, 'MZN', ).baseAmount, '500.25', ); }); void test('normalvalue only,no assetcost/substitution;exactdecimal/zero and switch preserves hiddenassetrefs but clears ownconditions', () => { const input = row('private_company_asset_use'); for (const normalValue of ['0', '1.000002', '999999999999999.999999']) assert.equal( evaluateServiceNormal({ ...input, normalValue }, 'MZN').baseAmount, normalValue === '0' ? '0.00' : normalValue, ); for (const normalValue of ['-1', 'NaN', '0.0000001']) assert.equal( evaluateServiceNormal({ ...input, normalValue }, 'MZN').baseAmount, null, ); const changed = switchServiceTreatment(input, 'free_company_service'); assert.equal(changed.conditions.freeByCompany, undefined); assert.equal(changed.conditions.priorDeduction, undefined); for (const field of [ 'assetRef', 'deductionRef', 'normalValue', 'valuationRef', 'valuationScope', 'purposeRef', ]) assert.equal(changed[field], input[field]); assert.equal(evaluateServiceNormal(changed, 'MZN').baseAmount, null); assert.equal( evaluateServiceNormal( { ...changed, conditions: { ...changed.conditions, freeByCompany: 'yes', nonBusinessPurpose: 'yes', priorDeduction: 'no', }, }, 'MZN', ).baseAmount, '700.50', ); }); void test('save/recovery/history/report preserve all86 delivered books/currentkeys including P103/P102/P101/P095', () => { const d = draft(), prior = JSON.parse(d.modelo_a_snapshot); assert.deepEqual(serviceNormalBook(d), { rows: [] }); assert.deepEqual(serviceNormalReportRows(d), []); let book = recordServiceNormals(d, { rows: serviceNormalTreatments.map((t) => ({ ...row(t.id), conditions: {}, })), }); book = recordServiceNormals(d, { ...book, rows: serviceNormalTreatments.map((t) => ({ ...row(t.id), conditions: { ...row(t.id).conditions, domesticOperation: 'no' }, })), }); book = recordServiceNormals(d, { ...book, rows: serviceNormalTreatments.map((t) => row(t.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(serviceNormalCurrent(d, book)); for (const field of [ 'treatment', 'normalValue', 'valuationScope', 'deductionRef', 'assetRef', 'purposeRef', ]) assert.ok( !serviceNormalCurrent(d, { ...book, rows: book.rows.map((r) => ({ ...r, [field]: 'changed' })), }), ); for (const patch of [ { context_opportunity: 'opportunity:348' }, { currency: 'USD' }, { selection_labels: { province_id: 'Maputo' } }, ]) assert.ok(!serviceNormalCurrent({ ...d, ...patch }, book)); d.modelo_a_snapshot = saveServiceNormalBook(d, book); assert.deepEqual(serviceNormalBook(JSON.parse(JSON.stringify(d))), book); const next = JSON.parse(d.modelo_a_snapshot); const { serviceNormals: _serviceNormals, ...untouched } = next; assert.deepEqual(untouched, prior); for (const [scope, previous] of Object.entries(prior.valueReviews)) assert.ok( valueReviewCurrent({ ...d, context_opportunity: scope }, previous), ); for (const [scope, previous] of Object.entries( prior.considerationExclusions, )) assert.ok( exclusionCurrent({ ...d, context_opportunity: scope }, previous), ); 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.regulatedFuelBases['opportunity:342'].result.rows[0].baseAmount, '1400.15', ); assert.equal( next.books['opportunity:329'].result.periods[0].fields['11'], null, ); const report = JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), version: 'QA G7I', }), ); for (const token of [ 'Base P089', '500.25', '700.50', '900.75', 'IVA: Indeterminado', 'opportunity:347', 'Manica', '2026-12', '15(2)(c)', '4(2)(a)', 'dedução anterior parcial A', 'campo11', ]) assert.ok(report.includes(token), token); assert.deepEqual( serviceNormalReportRows({ ...d, context_opportunity: 'opportunity:348', }), [], ); if (process.env.IVA_G7I_CALCULATED) fs.writeFileSync(process.env.IVA_G7I_CALCULATED, JSON.stringify(d)); }); void test('corrupt service rows/store cannot overwrite originals;duplicateoperationids cannotbe recorded', () => { const d = draft(), original = d.modelo_a_snapshot; for (const patch of [ { normalValue: 4 }, { conditions: [] }, { deductionRef: null }, ]) assert.throws( () => saveServiceNormalBook(d, { rows: [{ ...row(), ...patch }] }), /originais preservados/, ); assert.equal(d.modelo_a_snapshot, original); assert.throws( () => recordServiceNormals(d, { rows: [row(), row()] }), /distintos/, ); assert.throws(() => recordServiceNormals(d, { rows: [] }), /distintos/); assert.throws( () => serviceNormalBook({ ...d, modelo_a_snapshot: JSON.stringify({ ...JSON.parse(original), serviceNormals: [], }), }), /originais preservados/, ); });