Files
Investidor-V2/tests/frontend/iva-currency-events.test.mjs
T

41 lines
6.8 KiB
JavaScript

import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
import {newCurrencyEvent,currencyEventTreatments,evaluateCurrencyEvent,recordCurrencyEvents,saveCurrencyEventBook,currencyEventBook,currencyEventCurrent,currencyEventReportRows,switchCurrencyEvent} from '../../resources/js/lib/iva-currency-events.ts';
const frozen=JSON.parse(fs.readFileSync('tests/frontend/fixtures/iva-currency-events-preserved.json','utf8'));
const draft={...frozen,currency:'MZN',context_opportunity:'opportunity:357',project_title:'SYNTHETIC QA — Moeda e eventos / Manica'};
function row(t){return{...newCurrencyEvent(t,'MZN'),treatment:t,description:'SYNTHETIC QA '+t,period:'2026-12',origin:'projected',operationRef:'SYNTHETIC QA operação existente',documentRef:'SYNTHETIC QA documento/pressuposto',documentDate:'2026-12-12',scope:'SYNTHETIC QA conjunto/parte/operação/período',evidence:'SYNTHETIC QA pressupostos expressos',eventDate:'2026-12-10',eventRef:'SYNTHETIC QA evento específico/artigo7,excepções próprias conferidas',otherDate:t==='consignment_deadline'?'2026-06-13':t==='contract_effects'?'2026-12-01':'2026-12-12',reviewDate:'2026-12-31',factsConfirmed:'yes',invoiceRequired:'yes',invoiceState:'issued',invoiceDate:'2026-12-12',invoiceRef:'SYNTHETIC QA factura',legalDeadline:'2026-12-17',deadlineRef:'SYNTHETIC QA prazo/disposição/calendário identificados,não regra vigente presumida',paymentState:t==='advance_payment'?'received':'none',paymentDate:'2026-12-09',paymentRef:'SYNTHETIC QA recebimento identificado',amount:'1000.00',paymentAmount:'200.00',sourceCurrency:'USD',fxRate:'64.5',fxDate:'2026-12-10',fxSource:'SYNTHETIC QA taxa/exemplar',fxRuleRef:'SYNTHETIC QA pressuposto da taxa/data,não base fiscal',fxDirection:'mzn_per_unit'};}
for(const rule of currencyEventTreatments)test(rule.branch+' '+rule.id+' own event and noVAT/base',()=>{
const r=row(rule.id),v=evaluateCurrencyEvent(r);assert.equal(v.status,rule.branch==='P104'?'conditional':'determined');assert.equal(v.baseAmount,null);assert.equal(v.vat,null);assert.equal(v.rate,null);
if(rule.branch==='P104')assert.equal(v.scenarioAmount,'64500.00');else{assert.equal(v.dueEvents.at(-1).date,['import_clearance','import_auction'].includes(rule.id)?'2026-12-10':'2026-12-12');assert.equal(v.eventDate,rule.id==='advance_payment'?null:rule.id==='consignment_deadline'?'2026-12-10':'2026-12-10');}
for(const f of ['operationRef','documentRef','scope','evidence'])assert.equal(evaluateCurrencyEvent({...r,[f]:''}).status,'indeterminate');assert.equal(evaluateCurrencyEvent({...r,factsConfirmed:''}).status,'indeterminate');assert.equal(evaluateCurrencyEvent({...r,factsConfirmed:'no'}).status,'not_applicable');
});
test('P131/P132 invoice intime/late/absent,partial payment and no duplicate remainder',()=>{
const r=row('goods_available');let v=evaluateCurrencyEvent({...r,paymentState:'received'});assert.deepEqual(v.dueEvents.map(x=>[x.date,x.amount]),[['2026-12-09','200.00'],['2026-12-12','800.00']]);
v=evaluateCurrencyEvent({...r,invoiceDate:'2026-12-20'});assert.equal(v.dueEvents[0].date,'2026-12-17');
v=evaluateCurrencyEvent({...r,invoiceState:'not_issued'});assert.equal(v.dueEvents[0].date,'2026-12-17');
v=evaluateCurrencyEvent({...r,invoiceState:'not_issued',reviewDate:'2026-12-11',paymentState:'received'});assert.equal(v.dueEvents.length,1);assert.equal(v.remainingPending,true);
v=evaluateCurrencyEvent({...r,paymentState:'received',paymentDate:'2026-12-19',invoiceDate:'2026-12-20'});assert.deepEqual(v.dueEvents.map(x=>[x.date,x.amount]),[['2026-12-17','1000.00']]);
v=evaluateCurrencyEvent({...r,paymentState:'received',paymentAmount:'1000'});assert.equal(v.dueEvents.length,1);assert.equal(v.dueEvents[0].amount,'1000.00');
for(const patch of [{paymentState:''},{legalDeadline:''},{deadlineRef:''},{invoiceState:''},{paymentState:'received',paymentAmount:'1001'},{paymentState:'received',amount:''}])assert.equal(evaluateCurrencyEvent({...r,...patch}).status,'indeterminate');
assert.equal(evaluateCurrencyEvent({...r,invoiceRequired:'no',amount:''}).dueEvents[0].amount,null);
assert.equal(evaluateCurrencyEvent({...r,eventDate:'2026-12-20',reviewDate:'2026-12-11',invoiceState:'not_issued',legalDeadline:'2026-12-28',paymentState:'received'}).dueEvents[0].date,'2026-12-09');
});
test('own events,consignmentterm,servicecharge,contractexceptions and dates',()=>{
assert.equal(evaluateCurrencyEvent({...row('consignment_deadline'),otherDate:''}).status,'indeterminate');
assert.equal(evaluateCurrencyEvent({...row('consignment_deadline'),invoiceRequired:'no'}).dueEvents[0].date,'2026-12-10');
assert.equal(evaluateCurrencyEvent({...row('service_early_charge'),otherDate:'2026-12-09'}).status,'indeterminate');
assert.equal(evaluateCurrencyEvent({...row('contract_effects'),otherDate:'2026-12-11'}).status,'indeterminate');
for(const field of ['reviewDate','eventDate','documentDate'])assert.equal(evaluateCurrencyEvent({...row('goods_available'),[field]:'2026-02-30'}).status,'indeterminate');
const r=row('own_goods'),sw=switchCurrencyEvent(r,'foreign_scenario');assert.equal(sw.eventDate,r.eventDate);assert.equal(sw.fxSource,r.fxSource);assert.equal(sw.factsConfirmed,'');
});
test('P104 conditionalconversion direction/exactrounding/missingparams never fiscalbase',()=>{
const r=row('foreign_scenario');assert.equal(evaluateCurrencyEvent({...r,fxDirection:'units_per_mzn',fxRate:'2',amount:'100'}).scenarioAmount,'50.00');
assert.equal(evaluateCurrencyEvent({...r,amount:'0.000001',fxRate:'1.5'}).scenarioAmount,'0.000002');
for(const patch of [{fxRate:'0'},{fxRate:'-1'},{fxSource:''},{fxDate:''},{fxRuleRef:''},{fxDirection:''},{sourceCurrency:'MZN'}])assert.equal(evaluateCurrencyEvent({...r,...patch}).status,'indeterminate');assert.equal(evaluateCurrencyEvent(r).baseAmount,null);
});
test('snapshot/history/report preserve every delivered book and contextual scope',()=>{
const rows=currencyEventTreatments.map(t=>row(t.id)),a=recordCurrencyEvents(draft,{rows}),next={...draft,modelo_a_snapshot:saveCurrencyEventBook(draft,a)},b=recordCurrencyEvents(next,a);next.modelo_a_snapshot=saveCurrencyEventBook(next,b);
assert.equal(b.history.length,1);assert.equal(currencyEventCurrent(next,b),true);assert.equal(currencyEventCurrent(next,{...b,rows:rows.slice(1)}),false);assert.equal(currencyEventReportRows(next).length,15);assert.deepEqual(currencyEventBook({...next,context_opportunity:'opportunity:358'}),{rows:[]});
const store=JSON.parse(next.modelo_a_snapshot);delete store.currencyEvents;assert.deepEqual(store,JSON.parse(frozen.modelo_a_snapshot));assert.throws(()=>recordCurrencyEvents(next,{rows:[rows[0],rows[0]]}));assert.throws(()=>currencyEventBook({...next,modelo_a_snapshot:JSON.stringify({...store,currencyEvents:[]})}));
if(process.env.IVA_CURRENCY_EVENTS_FIXTURE)fs.writeFileSync(process.env.IVA_CURRENCY_EVENTS_FIXTURE,JSON.stringify(next,null,2)+'\n');
});