Files
Investidor-V2/tests/frontend/iva-noncash-base.test.mjs
T

38 lines
7.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {newNoncashBase,switchNoncashComposition,noncashBaseTreatments,noncashBaseConditions,evaluateNoncashBase,recordNoncashBases,saveNoncashBaseBook,noncashBaseBook,noncashBaseCurrent,noncashBaseReportRows} from '../../resources/js/lib/iva-noncash-base.ts';
import {fuelBaseCurrent} from '../../resources/js/lib/iva-fuel-base.ts';
import {actSaleCurrent} from '../../resources/js/lib/iva-act-sale-base.ts';
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
const frozen=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-g7e-preserved-inputs.json',import.meta.url),'utf8'));
const row=(treatment=noncashBaseTreatments[0].id)=>({...newNoncashBase('g7e-'+treatment,'MZN'),treatment,description:'SYNTHETIC QA operação A',period:'2026-12',exchangeDescription:'SYNTHETIC QA bens/serviços B dados em troca como contraprestação da operação A',agreementRef:'SYNTHETIC QA acordo A',documentRef:'SYNTHETIC QA G7E '+treatment,documentDate:'2026-12-12',cashAmount:'500.25',cashRef:'SYNTHETIC QA parte monetária recebida/a receber',normalValue:'2200.50',valuationRef:'SYNTHETIC QA fundamento A valor normal15(4)',valuationScope:'SYNTHETIC QA bens/serviços B,estádio retalho,dezembro2026/Manica,concorrência normal/fornecedor independente',compositionRef:'SYNTHETIC QA composição15(5)/(6),líquida de IVA,sem duplicar elementos',evidence:'SYNTHETIC QA pressupostos expressos,não documento real',conditions:Object.fromEntries(noncashBaseConditions.map(([key])=>[key,'yes']))});
const draft=()=>({...structuredClone(frozen),context_opportunity:'opportunity:343',project_title:'SYNTHETIC QA — G7E / Bases de contraprestação'});
test('P100 own conditions,normal value basis/scope and counterpart references;unknown/no never become zero',()=>{
for(const rule of noncashBaseTreatments){const input=row(rule.id),ok=evaluateNoncashBase(input,'MZN');assert.equal(ok.status,'determined');assert.equal(ok.baseAmount,rule.id==='noncash_only'?'2200.50':'2700.75');assert.equal(ok.vat,null);assert.equal(ok.rate,null);
for(const[key]of noncashBaseConditions)for(const value of ['','unknown','no']){const r=evaluateNoncashBase({...input,conditions:{...input.conditions,[key]:value}},'MZN');assert.equal(r.status,value==='no'?'not_applicable':'indeterminate');assert.equal(r.baseAmount,null);assert.equal(r.vat,null);}
for(const patch of [{description:''},{exchangeDescription:''},{agreementRef:''},{documentRef:''},{documentDate:'2026-02-30'},{valuationRef:''},{valuationScope:''},{compositionRef:''},{evidence:''},{period:'2025-12'},{currency:'USD'},{treatment:'unknown'}])assert.equal(evaluateNoncashBase({...input,...patch},'MZN').baseAmount,null);
}
});
test('cash plus normal value once;entirely noncash requires explicit composition and preserves hidden cash without summing it',()=>{
const input=row('cash_and_noncash');for(const[patch,expected]of [[{cashAmount:'0',normalValue:'0'},'0.00'],[{cashAmount:'0.000001',normalValue:'1.000002'},'1.000003'],[{cashAmount:'999999999999999.999999',normalValue:'999999999999999.999999'},'1999999999999999.999998'],[{treatment:'noncash_only',cashAmount:'invalid',cashRef:''},'2200.50']])assert.equal(evaluateNoncashBase({...input,...patch},'MZN').baseAmount,expected);
for(const patch of [{cashAmount:''},{cashRef:''},{normalValue:''},{cashAmount:'-1'},{normalValue:'NaN'},{normalValue:'0.0000001'}])assert.equal(evaluateNoncashBase({...input,...patch},'MZN').baseAmount,null);
const switched=switchNoncashComposition(input,'noncash_only');assert.equal(switched.conditions.cashComposition,'');for(const field of ['cashAmount','cashRef','normalValue','exchangeDescription','agreementRef','valuationRef','valuationScope','documentRef'])assert.equal(switched[field],input[field]);assert.equal(evaluateNoncashBase(switched,'MZN').baseAmount,null);assert.equal(evaluateNoncashBase({...switched,conditions:{...switched.conditions,cashComposition:'yes'}},'MZN').baseAmount,'2200.50');
});
test('save/recovery/history/report preserve all82 delivered books including P095TC/P094scope and currentkeys',()=>{
const d=draft(),prior=JSON.parse(d.modelo_a_snapshot);assert.deepEqual(noncashBaseBook(d),{rows:[]});assert.deepEqual(noncashBaseReportRows(d),[]);
let book=recordNoncashBases(d,{rows:noncashBaseTreatments.map(rule=>({...row(rule.id),conditions:{}}))});book=recordNoncashBases(d,{...book,rows:noncashBaseTreatments.map(rule=>({...row(rule.id),conditions:{...row(rule.id).conditions,exchangeIdentified:'no'}}))});book=recordNoncashBases(d,{...book,rows:noncashBaseTreatments.map(rule=>row(rule.id))});assert.equal(book.history.length,2);assert.ok(book.history.every(h=>h.rows.every(r=>r.baseAmount===null&&r.vat===null)));assert.ok(noncashBaseCurrent(d,book));
for(const field of ['treatment','cashAmount','cashRef','normalValue','exchangeDescription','agreementRef','valuationRef','valuationScope'])assert.ok(!noncashBaseCurrent(d,{...book,rows:book.rows.map(r=>({...r,[field]:'changed'}))}));for(const patch of [{context_opportunity:'opportunity:344'},{currency:'USD'},{selection_labels:{province_id:'Maputo'}}])assert.ok(!noncashBaseCurrent({...d,...patch},book));
d.modelo_a_snapshot=saveNoncashBaseBook(d,book);assert.deepEqual(noncashBaseBook(JSON.parse(JSON.stringify(d))),book);const next=JSON.parse(d.modelo_a_snapshot);const{noncashBases,...untouched}=next;assert.deepEqual(untouched,prior);for(const[scope,previous]of Object.entries(prior.regulatedFuelBases))assert.ok(fuelBaseCurrent({...d,context_opportunity:scope},previous));for(const[scope,previous]of Object.entries(prior.actSaleBases))assert.ok(actSaleCurrent({...d,context_opportunity:scope},previous));
assert.equal(next.regulatedFuelBases['opportunity:342'].result.rows[0].baseAmount,'1400.15');assert.equal(next.regulatedFuelBases['opportunity:342'].result.rows[1].baseAmount,'1500.25');assert.equal(next.actSaleBases['opportunity:341'].result.rows[1].baseAmount,'2200.50');assert.equal(next.publicAuthorityBases['opportunity:339'].result.rows[0].vat,null);assert.equal(next.importExemptions['opportunity:338'].result.rows[1].importVat,'400.00');assert.equal(next.books['opportunity:329'].result.periods[0].fields['11'],null);
const report=JSON.stringify(createProjectDossierReport(d,{selectedSections:new Set(['finance']),version:'QA G7E'}));for(const token of ['Base P100','2200.50','2700.75','IVA: Indeterminado','opportunity:343','Manica','2026-12','acordo A','15(3)/(4)','bens/serviços B','500.25','campo11'])assert.ok(report.includes(token),token);assert.deepEqual(noncashBaseReportRows({...d,context_opportunity:'opportunity:344'}),[]);
if(process.env.IVA_G7E_CALCULATED)fs.writeFileSync(process.env.IVA_G7E_CALCULATED,JSON.stringify(d));
});
test('corrupt noncash rows/store cannot overwrite originals;duplicate operation identifiers cannot be recorded',()=>{
const d=draft(),original=d.modelo_a_snapshot;for(const patch of [{cashAmount:4},{conditions:[]},{valuationRef:null}])assert.throws(()=>saveNoncashBaseBook(d,{rows:[{...row(),...patch}]}),/originais preservados/);assert.equal(d.modelo_a_snapshot,original);assert.throws(()=>recordNoncashBases(d,{rows:[row(),row()]}),/distintos/);assert.throws(()=>recordNoncashBases(d,{rows:[]}),/distintos/);assert.throws(()=>noncashBaseBook({...d,modelo_a_snapshot:JSON.stringify({...JSON.parse(original),noncashBases:[]})}),/originais preservados/);
});