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

40 lines
7.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {newActSaleBase,switchActValuation,switchActKind,actSaleKinds,actSaleTreatments,actSaleConditions,evaluateActSale,recordActSaleBases,saveActSaleBook,actSaleBook,actSaleCurrent,actSaleReportRows} from '../../resources/js/lib/iva-act-sale-base.ts';
import {commissionBaseCurrent} from '../../resources/js/lib/iva-commission-base.ts';
import {publicBaseCurrent} 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-g7c-preserved-inputs.json',import.meta.url),'utf8'));
const row=(treatment=actSaleTreatments[0].id)=>({...newActSaleBase('g7c-'+treatment,'MZN'),treatment,actKind:treatment==='act_sale_amount'?'auction':'settlement',description:'SYNTHETIC QA bens transmitidos pelo acto identificado',period:'2026-12',actRef:'SYNTHETIC QA acto A / bens desta operação',documentRef:'SYNTHETIC QA G7C '+treatment,documentDate:'2026-11-14',actValue:'1500.25',normalValue:'2200.50',valuationRef:'SYNTHETIC QA fundamento A do valor escolhido',valuationScope:'SYNTHETIC QA bens A, operação A, dezembro2026 e condições declaradas',compositionRef:'SYNTHETIC QA composição15(5)/(6),valor líquido de IVA',evidence:'SYNTHETIC QA pressupostos expressos,não documento real',conditions:Object.fromEntries(actSaleConditions.map(([key])=>[key,'yes']))});
const draft=()=>({...structuredClone(frozen),context_opportunity:'opportunity:341',project_title:'SYNTHETIC QA — G7C / Bases de transmissão por acto'});
test('P094 each act and valuation requires own conditions and references; unknown/no never become zero or VAT',()=>{
for(const rule of actSaleTreatments)for(const kind of actSaleKinds){const input={...row(rule.id),actKind:kind.id},ok=evaluateActSale(input,'MZN');assert.equal(ok.status,'determined');assert.equal(ok.baseAmount,rule.id==='act_sale_amount'?'1500.25':'2200.50');assert.equal(ok.vat,null);assert.equal(ok.rate,null);
for(const[key]of actSaleConditions)for(const value of ['','unknown','no']){const r=evaluateActSale({...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:''},{actRef:''},{documentRef:''},{documentDate:'2026-02-30'},{valuationRef:''},{valuationScope:''},{compositionRef:''},{evidence:''},{period:'2025-12'},{currency:'USD'},{actKind:'unknown'},{treatment:'unknown'}])assert.equal(evaluateActSale({...input,...patch},'MZN').baseAmount,null);
}
});
test('selected act value or normal value only; no automatic minimum/fallback, exact decimals and retained edits on switch',()=>{
const input=row();for(const[patch,expected]of [[{actValue:'0'},'0.00'],[{actValue:'1.000002'},'1.000002'],[{actValue:'999999999999999.999999'},'999999999999999.999999'],[{normalValue:'invalid'},'1500.25'],[{treatment:'act_normal_value',actValue:'invalid'},'2200.50']])assert.equal(evaluateActSale({...input,...patch},'MZN').baseAmount,expected);
for(const patch of [{actValue:''},{actValue:'-1'},{actValue:'NaN'},{actValue:'0.0000001'},{treatment:'act_normal_value',normalValue:''}])assert.equal(evaluateActSale({...input,...patch},'MZN').baseAmount,null);
const switched=switchActValuation(input,'act_normal_value');assert.equal(switched.conditions.valuationApplies,'');for(const field of ['actValue','normalValue','actRef','valuationRef','valuationScope','documentRef'])assert.equal(switched[field],input[field]);assert.equal(evaluateActSale(switched,'MZN').baseAmount,null);assert.equal(evaluateActSale({...switched,conditions:{...switched.conditions,valuationApplies:'yes'}},'MZN').baseAmount,'2200.50');
const changed=switchActKind(input,'judicial_sale');assert.equal(changed.conditions.goodsByAct,'');assert.equal(changed.conditions.valuationApplies,'');assert.equal(changed.actValue,input.actValue);assert.equal(changed.documentRef,input.documentRef);assert.equal(evaluateActSale(changed,'MZN').baseAmount,null);
});
test('save/recovery/history/report preserve all80 delivered books and old currentkeys',()=>{
const d=draft(),prior=JSON.parse(d.modelo_a_snapshot);assert.deepEqual(actSaleBook(d),{rows:[]});assert.deepEqual(actSaleReportRows(d),[]);
let book=recordActSaleBases(d,{rows:actSaleTreatments.map(rule=>({...row(rule.id),conditions:{}}))});book=recordActSaleBases(d,{...book,rows:actSaleTreatments.map(rule=>({...row(rule.id),conditions:{...row(rule.id).conditions,goodsByAct:'no'}}))});book=recordActSaleBases(d,{...book,rows:actSaleTreatments.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(actSaleCurrent(d,book));
for(const field of ['treatment','actKind','actValue','normalValue','valuationRef','valuationScope','actRef'])assert.ok(!actSaleCurrent(d,{...book,rows:book.rows.map(r=>({...r,[field]:'changed'}))}));for(const patch of [{context_opportunity:'opportunity:342'},{currency:'USD'},{selection_labels:{province_id:'Maputo'}}])assert.ok(!actSaleCurrent({...d,...patch},book));
d.modelo_a_snapshot=saveActSaleBook(d,book);assert.deepEqual(actSaleBook(JSON.parse(JSON.stringify(d))),book);const next=JSON.parse(d.modelo_a_snapshot);const{actSaleBases,...untouched}=next;assert.deepEqual(untouched,prior);for(const[scope,previous]of Object.entries(prior.importExemptions))assert.ok(importExemptionCurrent({...d,context_opportunity:scope},previous));for(const[scope,previous]of Object.entries(prior.publicAuthorityBases))assert.ok(publicBaseCurrent({...d,context_opportunity:scope},previous));for(const[scope,previous]of Object.entries(prior.commissionBases))assert.ok(commissionBaseCurrent({...d,context_opportunity:scope},previous));
assert.equal(next.commissionBases['opportunity:340'].result.rows[0].baseAmount,'900.15');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 G7C'}));for(const token of ['Base P094','1500.25','2200.50','IVA: Indeterminado','opportunity:341','Manica','2026-12','acto A','15(2)(h)','fundamento A','dezembro2026','campo11'])assert.ok(report.includes(token),token);assert.deepEqual(actSaleReportRows({...d,context_opportunity:'opportunity:342'}),[]);
if(process.env.IVA_G7C_CALCULATED)fs.writeFileSync(process.env.IVA_G7C_CALCULATED,JSON.stringify(d));
});
test('corrupt rows/store cannot overwrite originals; duplicate operation identifiers cannot be recorded',()=>{
const d=draft(),original=d.modelo_a_snapshot;for(const patch of [{actValue:4},{conditions:[]},{valuationRef:null}])assert.throws(()=>saveActSaleBook(d,{rows:[{...row(),...patch}]}),/originais preservados/);assert.equal(d.modelo_a_snapshot,original);assert.throws(()=>recordActSaleBases(d,{rows:[row(),row()]}),/distintos/);assert.throws(()=>recordActSaleBases(d,{rows:[]}),/distintos/);assert.throws(()=>actSaleBook({...d,modelo_a_snapshot:JSON.stringify({...JSON.parse(original),actSaleBases:[]})}),/originais preservados/);
});