42 lines
7.0 KiB
JavaScript
42 lines
7.0 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {newPublicBase,publicBaseTreatments,publicBaseConditions,evaluatePublicBase,recordPublicBases,savePublicBaseBook,publicBaseBook,publicBaseCurrent,publicBaseReportRows} from '../../resources/js/lib/iva-public-authority-base.ts';
|
|
import {importExemptionCurrent} from '../../resources/js/lib/iva-import-exemptions.ts';
|
|
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
|
|
const frozen=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-g7a-preserved-inputs.json',import.meta.url),'utf8'));
|
|
const row=(treatment=publicBaseTreatments[0].id)=>({...newPublicBase('g7a-'+treatment,'MZN'),treatment,description:'SYNTHETIC QA compensação por acto público',operationNature:treatment==='public_authority_indemnity'?'goods':'services',period:'2026-12',authority:'SYNTHETIC QA autoridade pública',actRef:'SYNTHETIC QA acto A,operação própria',documentRef:'SYNTHETIC QA G7A '+treatment,documentDate:'2026-11-14',compensationForm:treatment==='public_authority_indemnity'?'money':'mixed',moneyAmount:treatment==='public_authority_indemnity'?'1500.25':'1000.10',nonMoneyValue:'250.20',valuationRef:'SYNTHETIC QA valor normal nos termos15(4),pressuposto explícito',compositionRef:'SYNTHETIC QA documento A,composição15(5)/(6),semIVA e sem duplicações',evidence:'SYNTHETIC QA pressupostos;operação sujeita e ligada ao acto,não incumprimento contratual judicial',conditions:Object.fromEntries(publicBaseConditions.map(([key])=>[key,'yes']))});
|
|
const draft=()=>({...structuredClone(frozen),context_opportunity:'opportunity:339',project_title:'SYNTHETIC QA — G7A / Base de actos públicos'});
|
|
|
|
test('P090 bases distinguish indemnity/other compensation from incidence,tax and judicial contract-breach exclusion',()=>{
|
|
for(const treatment of publicBaseTreatments){const input=row(treatment.id),ok=evaluatePublicBase(input,'MZN');assert.equal(ok.status,'determined');assert.equal(ok.baseAmount,treatment.id==='public_authority_indemnity'?'1500.25':'1250.30');assert.equal(ok.vat,null);assert.equal(ok.rate,null);
|
|
for(const [key] of publicBaseConditions)for(const value of ['','unknown','no']){const r=evaluatePublicBase({...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 [{authority:''},{actRef:''},{compositionRef:''},{operationNature:''},{documentDate:'2026-02-30'},{documentRef:''},{period:'2025-12'},{currency:'USD'}])assert.equal(evaluatePublicBase({...input,...patch},'MZN').baseAmount,null);
|
|
}
|
|
assert.match(evaluatePublicBase({...row(),conditions:{...row().conditions,notJudicialContractBreach:'no'}},'MZN').reason,/15\(6\)\(a\)/);
|
|
});
|
|
|
|
test('money,in-kind,mixed compute exact net components;unknown differs from explicit zero and hidden values are retained',()=>{
|
|
const input=row();
|
|
for(const [patch,expected] of [[{compensationForm:'money',moneyAmount:'0'},'0.00'],[{compensationForm:'non_money',moneyAmount:'',nonMoneyValue:'250.20'},'250.20'],[{compensationForm:'mixed',moneyAmount:'0.000001',nonMoneyValue:'0.000002'},'0.000003'],[{compensationForm:'mixed',moneyAmount:'999999999999999.999999',nonMoneyValue:'999999999999999.999999'},'1999999999999999.999998']]){const r=evaluatePublicBase({...input,...patch},'MZN');assert.equal(r.baseAmount,expected);assert.equal(r.vat,null);}
|
|
for(const patch of [{compensationForm:''},{moneyAmount:''},{moneyAmount:'-1'},{moneyAmount:'NaN'},{moneyAmount:'1.0000001'},{compensationForm:'mixed',nonMoneyValue:''},{compensationForm:'non_money',valuationRef:''}])assert.equal(evaluatePublicBase({...input,...patch},'MZN').baseAmount,null);
|
|
const switched={...input,compensationForm:'non_money'};assert.equal(switched.moneyAmount,'1500.25');assert.equal(evaluatePublicBase(switched,'MZN').baseAmount,'250.20');assert.equal(evaluatePublicBase({...switched,compensationForm:'mixed'},'MZN').baseAmount,'1750.45');
|
|
});
|
|
|
|
test('save/recovery/report isolate P090 from78delivered branches and partial offers,while keeping exact versions and contextual invalidation',()=>{
|
|
const d=draft(),prior=JSON.parse(d.modelo_a_snapshot);assert.deepEqual(publicBaseBook(d),{rows:[]});assert.deepEqual(publicBaseReportRows(d),[]);
|
|
let book=recordPublicBases(d,{rows:publicBaseTreatments.map(rule=>({...row(rule.id),conditions:{}}))});book=recordPublicBases(d,{...book,rows:publicBaseTreatments.map(rule=>({...row(rule.id),conditions:{...row(rule.id).conditions,notJudicialContractBreach:'no'}}))});book=recordPublicBases(d,{...book,rows:publicBaseTreatments.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(publicBaseCurrent(d,book));
|
|
for(const field of ['actRef','documentRef','compositionRef','compensationForm','valuationRef','moneyAmount'])assert.ok(!publicBaseCurrent(d,{...book,rows:book.rows.map(r=>({...r,[field]:'changed'}))}));for(const patch of [{context_opportunity:'opportunity:340'},{currency:'USD'},{selection_labels:{province_id:'Maputo'}}])assert.ok(!publicBaseCurrent({...d,...patch},book));
|
|
d.modelo_a_snapshot=savePublicBaseBook(d,book);assert.deepEqual(publicBaseBook(JSON.parse(JSON.stringify(d))),book);const next=JSON.parse(d.modelo_a_snapshot);const{publicAuthorityBases,...untouched}=next;assert.deepEqual(untouched,prior);for(const[scope,previous]of Object.entries(prior.importExemptions))assert.ok(importExemptionCurrent({...d,context_opportunity:scope},previous));
|
|
assert.equal(next.importExemptions['opportunity:338'].result.rows[1].importVat,'400.00');assert.equal(next.importExemptions['opportunity:336'].result.rows[0].serviceVat,'0.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 G7A'}));for(const token of ['Base P090','1500.25','1250.30','IVA: Indeterminado','opportunity:339','Manica','2026-12','acto A','15(2)(d)','composição15(5)/(6)','campo11'])assert.ok(report.includes(token),token);assert.deepEqual(publicBaseReportRows({...d,context_opportunity:'opportunity:340'}),[]);
|
|
if(process.env.IVA_G7A_CALCULATED)fs.writeFileSync(process.env.IVA_G7A_CALCULATED,JSON.stringify(d));
|
|
});
|
|
|
|
test('malformed public-base rows/store cannot replace originals;duplicate identifiers cannot create calculations',()=>{
|
|
const d=draft(),original=d.modelo_a_snapshot;
|
|
for(const patch of [{moneyAmount:4},{conditions:[]},{valuationRef:null}])assert.throws(()=>savePublicBaseBook(d,{rows:[{...row(),...patch}]}),/originais preservados/);
|
|
assert.equal(d.modelo_a_snapshot,original);assert.throws(()=>recordPublicBases(d,{rows:[row(),row()]}),/distintos/);assert.throws(()=>recordPublicBases(d,{rows:[]}),/distintos/);
|
|
const bad={...d,modelo_a_snapshot:JSON.stringify({...JSON.parse(original),publicAuthorityBases:[]})};assert.throws(()=>publicBaseBook(bad),/originais preservados/);assert.equal(d.modelo_a_snapshot,original);
|
|
});
|