import assert from 'node:assert/strict'; import test from 'node:test'; import fs from 'node:fs'; import { operationTreatments, newSalesOperation, evaluateSalesOperation, recordSales, saveSalesBook, salesBook, salesCurrent, } from '../../resources/js/lib/iva-operations.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const ids = [ 'industrial_feed', 'industrial_feed_inputs', 'veterinary_goods', 'agricultural_services', ]; function seed() { return JSON.parse( fs.readFileSync( new URL('./fixtures/iva-publications.json', import.meta.url), 'utf8', ), ); } function fixture() { const draft = seed(); draft.context_opportunity = 'opportunity:314'; draft.project_title = 'SYNTHETIC QA — G2E social'; let book = { currency: 'MZN', rows: ids.map((id, i) => ({ ...newSalesOperation(`g2e-${i}`, '2026-06', 'MZN'), description: `SYNTHETIC QA ${id}`, establishment: 'SYNTHETIC QA equipamento Manica', amount: '100', basis: i % 2 ? 'included' : 'net', treatment: id, confirmed: operationTreatments .find((t) => t.id === id) .conditions.map((_, n) => n), evidence: 'SYNTHETIC QA — natureza, entidade, reconhecimento e condições cumulativas pressupostos documentados; sem certificação', })), periods: [{ period: '2026-06', complete: true }], }; book = recordSales(draft, book); draft.modelo_a_snapshot = saveSalesBook(draft, book); return { draft, book }; } void test('G2E four branches require their own operation and eligibility conditions', () => { const { book } = fixture(); for (const row of book.rows) { const rule = operationTreatments.find((t) => t.id === row.treatment), r = evaluateSalesOperation(row, 'MZN'); assert.equal( r.field, row.treatment === 'industrial_feed' ? '05' : '07', ); assert.equal(r.net, '100.00'); assert.equal(r.vat, '0.00'); assert.equal(r.gross, '100.00'); assert.match(r.article, /9\((12|15)\)/); assert.equal(rule.conditions.length, 3); for (const missing of row.confirmed) assert.equal( evaluateSalesOperation( { ...row, confirmed: row.confirmed.filter((n) => n !== missing), }, 'MZN', ).vat, null, ); assert.equal( evaluateSalesOperation({ ...row, evidence: '' }, 'MZN').vat, null, ); assert.equal( evaluateSalesOperation({ ...row, period: '2025-06' }, 'MZN').vat, null, ); assert.equal(evaluateSalesOperation(row, 'USD').vat, null); } assert.equal(book.result.periods[0].fields['07'], '300.00'); assert.equal(book.result.periods[0].fields['05'], '100.00'); assert.match(book.result.rows[0].reason, /com direito/); assert.ok( book.result.rows .slice(1) .every((r) => r.reason.includes('sem direito')), ); }); void test('new agro context round-trips and reports only its operations, preserving five accepted books without recalculation', () => { const { draft, book } = fixture(), original = seed(); const old = JSON.parse(original.modelo_a_snapshot).salesOperations; const recovered = JSON.parse(JSON.stringify(draft)), store = JSON.parse(recovered.modelo_a_snapshot).salesOperations; for (const id of [ 'opportunity:309', 'opportunity:310', 'opportunity:311', 'opportunity:312', 'opportunity:313', ]) { assert.deepEqual(store[id], old[id]); assert.equal( salesCurrent({ ...recovered, context_opportunity: id }, store[id]), true, ); } assert.equal(salesCurrent(recovered, salesBook(recovered)), true); const model = JSON.stringify( createProjectDossierReport(recovered, { selectedSections: new Set(['finance']), }), ); for (const token of [ ...ids, '300.00', 'opportunity:314', 'Manica', '2026-06', 'MZN', ]) assert.ok(model.includes(token), token); for (const token of [ 'financial_stamp', 'patient_transport', 'social_assistance_public', 'statutory_membership', 'author_rights', ]) assert.equal(model.includes(token), false); assert.equal(book.result.rows.length, 4); assert.equal(draft.currency, original.currency); assert.deepEqual(draft.selection_labels, original.selection_labels); }); if (process.env.IVA_G2E_OUT) fs.writeFileSync( process.env.IVA_G2E_OUT, JSON.stringify(fixture().draft, null, 2), );