import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newOfferPreparation, offerPreparationBook, saveOfferPreparationBook, recordOfferPreparations, offerReusableData, reuseOfferData, offerPreparationReportRows, } from '../../resources/js/lib/iva-offer-preparations.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const frozen = JSON.parse( fs.readFileSync( new URL('./fixtures/iva-g5c-inputs.json', import.meta.url), 'utf8', ), ); const draft = () => structuredClone(frozen); void test('incomplete P084/P085 drafts save without authorizations,zeroVAT or a benefit result;prior26books remain exact', () => { const d = draft(), before = JSON.parse(d.modelo_a_snapshot), rows = ['P084', 'P085'].map((branch) => newOfferPreparation('gift-' + branch, branch, 'MZN'), ); d.modelo_a_snapshot = saveOfferPreparationBook(d, { rows }); const next = JSON.parse(d.modelo_a_snapshot); for (const key of Object.keys(before)) assert.deepEqual(next[key], before[key]); assert.deepEqual( offerPreparationBook(JSON.parse(JSON.stringify(d))).rows, rows, ); assert.equal(rows[1].operation, 'acquisition'); assert.equal( 'result' in next.offerPreparations[d.context_opportunity], false, ); for (const row of offerPreparationReportRows(d)) assert.match(row[2], /bénéfice|benefício não aplicado/); assert.equal( next.books['opportunity:329'].result.periods[0].fields['11'], null, ); }); void test('explicit reuse fills only empty fields,same opportunity;currency mismatch and P085 import rejected without mutation', () => { const d = draft(), sources = offerReusableData(d); assert.equal(sources.length, 6); const source = sources.find((x) => x.operation === 'import'), original = structuredClone(source), row = { ...newOfferPreparation('gift', 'P084', 'MZN'), description: 'Edição deliberada', beneficiary: 'Instituição QA', }; const next = reuseOfferData(row, source); assert.equal(next.description, row.description); assert.equal(next.beneficiary, row.beneficiary); assert.equal(next.documentRef, source.values.documentRef); assert.equal(next.operation, 'import'); assert.equal(next.reusedFrom.key, source.key); assert.deepEqual(source, original); assert.equal(row.documentRef, ''); assert.throws( () => reuseOfferData(newOfferPreparation('g', 'P085', 'MZN'), source), /P085/, ); assert.throws( () => reuseOfferData({ ...row, currency: 'USD' }, source), /Moeda/, ); assert.equal( offerReusableData({ ...d, context_opportunity: 'opportunity:does-not-exist', }).length, 0, ); }); void test('versions preserve deliberate edits and own branch conditions;report from saved/recovered draft does not extend benefit or field11', () => { const d = draft(); let p84 = reuseOfferData( newOfferPreparation('gift84', 'P084', 'MZN'), offerReusableData(d).find((x) => x.operation === 'import'), ); p84 = { ...p84, beneficiary: 'SYNTHETIC QA instituição', nationalInstitution: 'yes', publicSocialInstitution: 'yes', goodsSuitable: 'yes', publicInterestUse: 'yes', }; const p85 = { ...newOfferPreparation('gift85', 'P085', 'MZN'), description: 'SYNTHETIC QA bens para cheias', disaster: 'SYNTHETIC QA cheias', disasterKind: 'Cheias', mitigation: 'yes', }; let book = recordOfferPreparations({ rows: [p84, p85] }); book = recordOfferPreparations({ ...book, rows: [{ ...p84, purpose: 'Edição posterior' }, p85], }); assert.equal(book.history.length, 1); assert.equal(book.history[0].rows[0].purpose, ''); d.modelo_a_snapshot = saveOfferPreparationBook(d, book); assert.deepEqual(offerPreparationBook(JSON.parse(JSON.stringify(d))), book); const report = JSON.stringify( createProjectDossierReport(d, { selectedSections: new Set(['finance']), version: 'QA drafts', }), ); for (const token of [ 'P084', 'P085', 'benefício não aplicado', 'SYNTHETIC QA cheias', 'Edição posterior', '14(2)(a/b)', 'opportunity:334', ]) assert.ok(report.includes(token), token); assert.equal( offerPreparationBook({ ...d, context_opportunity: 'opportunity:333' }) .rows.length, 0, ); if (process.env.IVA_OFFERS_CALCULATED) fs.writeFileSync(process.env.IVA_OFFERS_CALCULATED, JSON.stringify(d)); }); void test('corrupt draft data cannot be replaced with empty book and P085 never accepts imported operation', () => { for (const offerPreparations of [ [], null, { 'opportunity:334': { rows: [{ id: 'broken' }] } }, ]) { const d = draft(), s = JSON.parse(d.modelo_a_snapshot); s.offerPreparations = offerPreparations; d.modelo_a_snapshot = JSON.stringify(s); assert.throws(() => saveOfferPreparationBook(d, { rows: [] })); } assert.throws( () => saveOfferPreparationBook(draft(), { rows: [ { ...newOfferPreparation('x', 'P085', 'MZN'), operation: 'import', }, ], }), /operação/, ); });