import assert from 'node:assert/strict'; import test from 'node:test'; import { monthlyProjectedSales, forecastBusinessPlan, serializeBusinessPlanSnapshot, } from '../../resources/js/lib/business-financial-plan.ts'; import { monthlyIvaInput, monthlyIvaKey, monthlySalesFromDraft, readMonthlyIvaRecord, monthlyIvaCashTreatment, } from '../../resources/js/lib/monthly-iva.ts'; import { partitionSimulationDraft, restoreSimulationDraft, readArithmeticSnapshot, } from '../../resources/js/lib/simulation-form.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; function plan() { const fields = [ 'openingCash', 'monthlyCollections', 'monthlyVariableCostPayments', 'monthlyInventoryPurchases', 'monthlyOperatingExpenses', 'monthlyOperatingPayments', 'monthlyPayrollExpense', 'monthlyPayrollPayments', 'assetInvestment', 'inventory', 'receivables', 'payables', 'equity', 'shareholderLoans', 'bankLoanProceeds', 'grants', 'assetDepreciation', 'monthlyInterestExpense', 'monthlyInterestPayment', 'monthlyPrincipalRepayment', ]; return { ...Object.fromEntries(fields.map((key) => [key, '0'])), currency: 'MZN', periods: 4, depreciationLifeMonths: 60, products: [ { label: 'Produto QA', monthlyUnits: '1', unitPrice: '1000.03', unitVariableCost: '0', monthlyUnitsByPeriod: ['1', '2', '0', '3'], }, ], }; } const settings = { start: '2026-01', basis: 'net', declared: true, auto: true }; function draft(value = plan()) { return { currency: 'MZN', business_plan_snapshot: serializeBusinessPlanSnapshot(value), monthly_iva_settings: JSON.stringify(settings), }; } function snapshot(input) { return { contract_version: 1, scenario_kind: 'fiscal_rule_published', base: null, currency: 'MZN', indicative_total: null, legal_interpretation: false, formula_version: 'investmoz.tax.v1', context: { reference_date: '2026-01-01', currency: 'MZN', currency_fraction_digits: 2, scenario_id: '61000100-0000-4000-8000-000000000099', scenario_version: 1, engine_version: 'fiscal-published-v1', ruleset_version: 'IVA-GERAL-BASE-LIQUIDA:1', }, result: { status: 'indeterminate', value: null, unit: 'MZN', explanation: 'IVA mensal; não é imposto a pagar.', missing_inputs: ['monthly_sales'], source_ids: ['qa-source'], }, presentation: { value: null, rounding_applied: false }, fiscal_provenance: { rule: { rule_code: 'IVA-GERAL-BASE-LIQUIDA', rule_version: 1, valid_from: '2023-01-01', valid_until: null, source: { diploma: 'Fonte sintética QA', article: 'Teste' }, }, scope_status: 'user_declared', }, monthly_projection: { input, cash_treatment: monthlyIvaCashTreatment, rows: [ { date: '2026-01-01', sales_declared: '1000.03', net_sales: '1000.03', rate: '16', vat: '160.0048', gross_sales: '1160.0348', status: 'calculated', }, { date: '2026-02-01', sales_declared: '0', net_sales: '0', rate: '16', vat: '0', gross_sales: '0', status: 'calculated', }, { date: '2026-03-01', sales_declared: null, net_sales: null, rate: null, vat: null, gross_sales: null, status: 'missing_sales', }, ], }, }; } void test('monthly IVA reuses exactly the existing per-product sales projection without repeating entry', () => { const value = plan(); assert.deepEqual( monthlyProjectedSales(value), forecastBusinessPlan(value).rows.map((row) => row.revenue), ); assert.deepEqual(monthlySalesFromDraft(draft()).amounts, [ '1000.03', '2000.06', '0.00', '3000.09', ]); }); void test('a missing month remains unknown while an explicit zero and other months stay available', () => { const value = plan(); value.products[0].monthlyUnitsByPeriod = ['1', '', '0', '2']; assert.deepEqual(monthlyProjectedSales(value), [ '1000.03', null, '0.00', '2000.06', ]); const input = monthlyIvaInput(draft(value), settings); assert.equal(input.monthly_sales[1].amount, null); assert.equal(input.monthly_sales[2].amount, '0.00'); assert.equal('rate' in input, false); assert.equal('monthlyTaxAssessed' in input, false); }); void test('gross basis is preserved and old fiscal results become stale when sales, currency or basis change', () => { const value = draft(); const initial = monthlyIvaInput(value, settings); const frozen = JSON.stringify(initial); const gross = monthlyIvaInput(value, { ...settings, basis: 'included' }); assert.equal(gross.monthly_sales[0].amount, '1000.03'); assert.notEqual(monthlyIvaKey(gross), monthlyIvaKey(initial)); const changed = plan(); changed.products[0].monthlyUnitsByPeriod[0] = '2'; assert.notEqual( monthlyIvaKey(monthlyIvaInput(draft(changed), settings)), monthlyIvaKey(initial), ); assert.equal(JSON.stringify(initial), frozen); assert.throws( () => monthlyIvaInput(value, { ...settings, start: '2026-12' }), /cobertura/, ); }); void test('monthly recovery and finance report preserve exact values and mark stale history without recomputing VAT', () => { const value = plan(); value.products[0].monthlyUnitsByPeriod = ['1', '0', '', '2']; const original = draft(value); const input = monthlyIvaInput(original, settings); const result = snapshot(input); original.monthly_iva_snapshot = JSON.stringify({ input, execution: { id: '61000100-0000-4000-8000-000000000077', status: 'completed', version_no: 2, result_snapshot: result, }, }); const partition = partitionSimulationDraft(original); const recovered = restoreSimulationDraft( partition.economic_snapshot, partition.personal_snapshot, ); assert.equal(recovered.monthly_iva_snapshot, original.monthly_iva_snapshot); assert.equal( readMonthlyIvaRecord(recovered.monthly_iva_snapshot).execution .result_snapshot.monthly_projection.rows[0].vat, '160.0048', ); assert.equal(readArithmeticSnapshot(result).integrity, 'versioned'); let report = createProjectDossierReport(recovered, { selectedSections: new Set(['finance']), }); let text = JSON.stringify(report); assert.match(text, /160\.0048/); assert.match(text, /1160\.0348/); assert.match(text, /sem informação de vendas/); assert.match(text, /não é imposto a pagar/); value.products[0].monthlyUnitsByPeriod[0] = '2'; recovered.business_plan_snapshot = serializeBusinessPlanSnapshot(value); report = createProjectDossierReport(recovered, { selectedSections: new Set(['finance']), }); text = JSON.stringify(report); assert.match(text, /Histórico desactualizado/); assert.match(text, /160\.0048/); assert.match(monthlyIvaCashTreatment, /não é somado novamente/); assert.match(monthlyIvaCashTreatment, /nem deduzido como custo/); });