38 lines
6.4 KiB
JavaScript
38 lines
6.4 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import fs from 'node:fs';
|
||
import {serializeBusinessPlanSnapshot} from '../../resources/js/lib/business-financial-plan.ts';
|
||
import {normalBook,newNormalBook,newNormalAdjustment,normalFinancialSource,calculateNormal,recordNormal,normalCurrent,saveNormalBook,normalReportRows,normalHtml} from '../../resources/js/lib/irpc-normal.ts';
|
||
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
|
||
import {irpcBook} from '../../resources/js/lib/irpc-withholdings.ts';
|
||
const plan=()=>({currency:'MZN',openingCash:'0',products:[{label:'Serviço',monthlyUnits:'10',unitPrice:'100',unitVariableCost:'30'}],monthlyCollections:'800',monthlyVariableCostPayments:'250',monthlyOperatingExpenses:'100',monthlyOperatingPayments:'80',monthlyPayrollExpense:'50',monthlyPayrollPayments:'40',assetInvestment:'0',inventory:'0',receivables:'0',payables:'0',equity:'0',shareholderLoans:'0',bankLoanProceeds:'0',grants:'0',assetDepreciation:'0',depreciationLifeMonths:12,monthlyInterestExpense:'10',monthlyInterestPayment:'5',monthlyPrincipalRepayment:'60',periods:12});
|
||
const draft=()=>({...JSON.parse(fs.readFileSync(new URL('./fixtures/irpc-mrfta-preserved.json',import.meta.url),'utf8')),fiscal_component:'irpc',business_plan_snapshot:serializeBusinessPlanSnapshot(plan())});
|
||
const row=(id='a')=>({...newNormalAdjustment(id),sourceCode:'operating_expenses',document:'QA aviso multa sintético',line:id,amount:'100',rule:'noncontractual_fine',included:'yes',reference:'QA pressuposto:multa não contratual incluída no custo operacional'});
|
||
const book=()=>({...newNormalBook(),year:'2026',mappingReference:'QA plano meses1–12=Jan–Dez2026',scope:'resident_general',scopeReference:'QA residente geral sem regime especial',rows:[row(),{...row('b'),sourceCode:'interest_expense',amount:'20',rule:'compensatory_interest',document:'QA liquidação juros sintética',reference:'QA pressuposto:juros compensatórios incluídos no custo financeiro'}]});
|
||
test('L6 reuses reconciled profit and expense sources,without cash repayment or received withholding becoming expense',()=>{
|
||
const d=draft(),s=normalFinancialSource(d),m=calculateNormal(d,book());assert.equal(s.accountingProfitBeforeTax,'6480.00');assert.equal(m.accountingProfit.numerator,'6480');assert.equal(m.additions.numerator,'120');assert.equal(m.partialAdjustedResult.numerator,'6600');assert.equal(m.taxableProfit,null);assert.equal(m.taxableBase,null);assert.equal(m.tax,null);assert.equal(m.origin,'projected');assert.match(m.pending.join(' '),/L6 parcial/);
|
||
const p=plan();p.monthlyPrincipalRepayment='0';p.monthlyInterestPayment='0';d.business_plan_snapshot=serializeBusinessPlanSnapshot(p);assert.deepEqual(calculateNormal(d,book()).partialAdjustedResult,m.partialAdjustedResult);
|
||
});
|
||
test('missing qualification affects its own adjustment;confirmed additions remain visible without a full adjusted total',()=>{
|
||
const b=book();b.rows[1].reference='';const m=calculateNormal(draft(),b);assert.equal(m.rows[0].status,'calculated');assert.equal(m.rows[1].adjustment,null);assert.equal(m.additions.numerator,'100');assert.equal(m.partialAdjustedResult,null);b.rows[1].rule='other';assert.equal(calculateNormal(draft(),b).rows[1].status,'outside_scope');
|
||
});
|
||
test('duplicate document lines and oversubscribed source costs cannot double count',()=>{
|
||
const b=book();b.rows.push({...b.rows[0],id:'duplicate'});let m=calculateNormal(draft(),b);assert.equal(m.rows[0].adjustment,null);assert.equal(m.rows[2].adjustment,null);b.rows=[{...row('one'),amount:'700'},{...row('two'),amount:'600'}];m=calculateNormal(draft(),b);assert.ok(m.rows.every(r=>r.adjustment===null));assert.match(m.pending.join(' '),/excedem/);
|
||
});
|
||
test('already excluded expenses,revenue sources,negative and overprecision amounts do not become additions',()=>{
|
||
for(const patch of [{included:'no'},{sourceCode:'revenue'},{amount:'-10'},{amount:'1.001'},{rule:''}]){const b=book();b.rows=[{...row(),...patch}];assert.equal(calculateNormal(draft(),b).rows[0].adjustment,null);}
|
||
});
|
||
test('year,mapping,currency,horizon and regime stay explicit;no global annual assessment inferred',()=>{
|
||
for(const patch of [{year:''},{year:'2025'},{mappingReference:''},{scope:'other'},{scopeReference:''}])assert.equal(calculateNormal(draft(),{...book(),...patch}).partialAdjustedResult,null);
|
||
for(const p of [{...plan(),currency:'USD'},{...plan(),periods:6}]){const d=draft();d.business_plan_snapshot=serializeBusinessPlanSnapshot(p);assert.equal(calculateNormal(d,book()).partialAdjustedResult,null);}
|
||
const d=draft();d.business_plan_snapshot='';assert.equal(calculateNormal(d,book()).accountingProfit,null);assert.equal(calculateNormal(d,{...book(),rows:[]}).partialAdjustedResult,null);
|
||
});
|
||
test('calculation save recovery report preserves installed books and invalidates history on financial or adjustment changes',()=>{
|
||
const d=draft(),before=JSON.parse(d.modelo_a_snapshot),b=recordNormal(d,book(),'2026-10-25T20:00:00Z');d.modelo_a_snapshot=saveNormalBook(d,b);const recovered=JSON.parse(JSON.stringify(d)),saved=normalBook(recovered);assert.equal(normalCurrent(recovered,saved),true);assert.deepEqual(JSON.parse(d.modelo_a_snapshot).irpcWithholdings,before.irpcWithholdings);assert.ok(irpcBook(d));assert.match(JSON.stringify(normalReportRows(recovered)),/6600/);assert.match(JSON.stringify(createProjectDossierReport(recovered,{selectedSections:new Set(['finance'])})),/6600/);assert.match(normalHtml(recovered),/Não é demonstração contabilística/);
|
||
const p=plan();p.monthlyOperatingExpenses='110';recovered.business_plan_snapshot=serializeBusinessPlanSnapshot(p);assert.equal(normalCurrent(recovered,saved),false);assert.throws(()=>normalHtml(recovered));const next=recordNormal(recovered,saved);assert.deepEqual(next.history[0],b.result);assert.equal(next.result.model.partialAdjustedResult.numerator,'6480');
|
||
fs.mkdirSync('outputs/irpc-l6',{recursive:true});fs.writeFileSync('outputs/irpc-l6/calculated.json',JSON.stringify(d));fs.writeFileSync('outputs/irpc-l6/preparation.html',normalHtml(d));
|
||
});
|
||
test('opportunities remain separate and malformed persisted data is preserved with explicit error',()=>{
|
||
const d=draft();d.modelo_a_snapshot=saveNormalBook(d,recordNormal(d,book()));d.context_opportunity='another';assert.equal(normalBook(d).rows.length,0);const b=book();b.rows[0].amount=100;assert.throws(()=>saveNormalBook(d,b));const old=d.modelo_a_snapshot;assert.throws(()=>saveNormalBook(d,{...book(),rows:[row(),row()]}));assert.equal(d.modelo_a_snapshot,old);
|
||
});
|