import assert from 'node:assert/strict'; import test from 'node:test'; import fs from 'node:fs'; import { annexIEntries, annexIVersion, } from '../../resources/js/lib/iva-annex-i.ts'; import { operationTreatments, newSalesOperation, evaluateSalesOperation, continueAnnexIOperation, recordSales, saveSalesBook, salesBook, salesCurrent, } from '../../resources/js/lib/iva-operations.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; const rule = operationTreatments.find((t) => t.id === 'annexI_goods'); const seed = () => JSON.parse( fs.readFileSync( new URL('./fixtures/iva-pharma-inputs.json', import.meta.url), 'utf8', ), ); const operation = (entry, i = 0) => ({ ...newSalesOperation(`g2l-${i}`, '2026-09', 'MZN'), description: `SYNTHETIC QA ${entry.code} ${entry.id}`, establishment: 'SYNTHETIC QA estabelecimento Manica', amount: '100', basis: i % 2 ? 'included' : 'net', treatment: rule.id, annexIItem: entry.id, confirmed: rule.conditions.map((_, n) => n), evidence: 'SYNTHETIC QA: correspondência código/designação e qualificadores da posição expressamente pressupostos; não é classificação aduaneira ou certificação', }); function fixture() { const draft = seed(); draft.context_opportunity = 'opportunity:321'; draft.project_title = 'SYNTHETIC QA — G2L Anexo I'; const codes = [ '0306.36.10', '3102.10.00', '1007.10.00', '8501.61.00', '8701.95.00', '8201.50.00', '0702.00.00', '3808.91.00', '1101.00.00', '0402.21.10', ]; const rows = codes.map((code, i) => { const entry = annexIEntries.find((e) => e.code === code); let row = operation(entry, i); if (entry.relatedRequired) { row = continueAnnexIOperation(row, entry.relatedTreatments[0]); row.confirmed = operationTreatments .find((t) => t.id === row.treatment) .conditions.map((_, n) => n); } else if (entry.relatedTreatments) { row.annexIOnly = true; row.evidence += code === '1101.00.00' ? '; mistura de trigo com centeio, não farinha de trigo simples' : '; leite para utilização industrial, sem destino a lactente até um ano'; } return row; }); const book = recordSales(draft, { currency: 'MZN', rows, periods: [{ period: '2026-09', complete: true }], }); draft.modelo_a_snapshot = saveSalesBook(draft, book); return { draft, book }; } void test('AnexoI has 172 distinct documentary positions, own qualifiers, cross-page text and five contextual tractor entries', () => { assert.equal(annexIEntries.length, 172); assert.equal(new Set(annexIEntries.map((e) => e.code)).size, 172); assert.equal(new Set(annexIEntries.map((e) => e.id)).size, 172); const scissors = annexIEntries.find((e) => e.code === '8201.50.00'); assert.equal(scissors.pdfPage, 8); assert.equal(scissors.lastPdfPage, 9); assert.match(scissors.label, /uma das mãos/); assert.equal( annexIEntries.filter((e) => e.context === 'Outros tractores').length, 5, ); assert.equal( annexIEntries .find((e) => e.code === '8701.30.00') .label.includes('Outros tractores'), false, ); for (const [i, entry] of annexIEntries.entries()) { const row = { ...operation(entry, i), annexIOnly: true }, r = evaluateSalesOperation(row, 'MZN'); assert.equal(r.vat, entry.relatedRequired ? null : '0.00'); if (!entry.relatedRequired) { assert.equal(r.field, '07'); assert.equal(r.gross, '100.00'); } for (const token of [ entry.id, entry.code, entry.label, `PDF${entry.pdfPage}`, annexIVersion, ]) assert.ok(r.source.includes(token), token); } }); void test('P035 requires actual position and qualifiers; overlapping descriptions require explicit applicability, never silently field07', () => { const { draft, book } = fixture(), row = book.rows[0]; for (const missing of row.confirmed) assert.equal( evaluateSalesOperation( { ...row, confirmed: row.confirmed.filter((n) => n !== missing), }, 'MZN', ).vat, null, ); for (const patch of [ { annexIItem: undefined }, { annexIItem: '' }, { annexIItem: '0306.36.10' }, { annexIItem: 'annexIII-2022-001' }, { evidence: '' }, { establishment: '' }, { amount: '' }, { period: '2025-09' }, { sourceCurrency: 'USD' }, ]) assert.equal( evaluateSalesOperation({ ...row, ...patch }, 'MZN').vat, null, ); assert.equal(evaluateSalesOperation(row, 'USD').vat, null); const overlaps = annexIEntries.filter((e) => e.relatedTreatments); assert.equal(overlaps.length, 13); assert.equal(overlaps.filter((e) => e.relatedRequired).length, 3); for (const entry of overlaps) { const pending = operation(entry); assert.equal(evaluateSalesOperation(pending, 'MZN').vat, null); assert.equal( evaluateSalesOperation({ ...pending, annexIOnly: true }, 'MZN').vat, entry.relatedRequired ? null : '0.00', ); } const incomplete = recordSales(draft, { ...book, rows: [{ ...row, annexIItem: '' }], }); assert.equal(incomplete.result.periods[0].fields['07'], null); assert.deepEqual(incomplete.history.at(-1), book.result); }); void test('explicit continuation reuses existing treatment identity, preserves money/origin/annex and requires new conditions', () => { for (const entry of annexIEntries.filter((e) => e.relatedTreatments)) { for (const target of entry.relatedTreatments) { const before = operation(entry), after = continueAnnexIOperation(before, target), targetRule = operationTreatments.find((t) => t.id === target); assert.equal(after.treatment, target); assert.equal(after.annexIItem, entry.id); assert.deepEqual(after.confirmed, []); assert.ok(after.source.startsWith(before.source)); assert.ok(after.source.includes(entry.id)); for (const key of [ 'id', 'period', 'amount', 'basis', 'sourceCurrency', 'sourcePeriod', 'establishment', 'description', 'evidence', ]) assert.equal(after[key], before[key], key); assert.equal(evaluateSalesOperation(after, 'MZN').vat, null); const r = evaluateSalesOperation( { ...after, confirmed: targetRule.conditions.map((_, n) => n) }, 'MZN', ); assert.equal(r.field, '05'); assert.equal(r.vat, '0.00'); } } assert.throws(() => continueAnnexIOperation(operation(annexIEntries[0]), 'general'), ); const e = annexIEntries.find((v) => v.code === '0702.00.00'); assert.throws(() => continueAnnexIOperation( { ...operation(e), treatment: 'listed_fresh_chilled_tomato' }, 'listed_fresh_chilled_tomato', ), ); }); void test('G2L recovery/report preserve twelve current books including G2K and calendar, without recalculation', () => { const { draft, book } = fixture(), original = seed(), old = JSON.parse(original.modelo_a_snapshot).salesOperations; const recovered = JSON.parse(JSON.stringify(draft)), store = JSON.parse(recovered.modelo_a_snapshot).salesOperations; assert.equal(Object.keys(old).length, 12); for (const [id, value] of Object.entries(old)) { assert.deepEqual(store[id], value); assert.equal( salesCurrent({ ...recovered, context_opportunity: id }, value), true, id, ); } assert.equal(salesCurrent(recovered, salesBook(recovered)), true); assert.equal(book.result.periods[0].fields['07'], '800.00'); assert.equal(book.result.periods[0].fields['05'], '200.00'); const report = JSON.stringify( createProjectDossierReport(recovered, { selectedSections: new Set(['finance']), }), ); for (const token of [ '800.00', '200.00', 'opportunity:321', 'Manica', '2026-09', 'MZN', 'AnexoI/2022', 'Outros tractores', annexIVersion, ...book.rows.map((r) => r.annexIItem), ]) assert.ok(report.includes(token), token); for (const token of [ 'pharma_manufacturing_inputs', 'fundraising_public', 'production_forestry_opted', ]) assert.equal(report.includes(token), false); const changed = { ...book, rows: book.rows.map((r, i) => i === 8 ? { ...r, annexIOnly: false } : r, ), }; assert.equal(salesCurrent(draft, changed), false); assert.deepEqual(changed.result, book.result); assert.deepEqual(recovered.selection_labels, original.selection_labels); assert.equal(recovered.currency, original.currency); }); if (process.env.IVA_G2L_OUT) fs.writeFileSync( process.env.IVA_G2L_OUT, JSON.stringify(fixture().draft, null, 2), );