Files
Investidor-V2/tests/frontend/iva-fx-selection.test.mjs
T

11 lines
4.8 KiB
JavaScript

import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
import {emptyFxSelection,selectFx,fxTempoSource} from '../../resources/js/lib/iva-fx-selection.ts';
import {newCurrencyEvent,evaluateCurrencyEvent,recordCurrencyEvents,saveCurrencyEventBook,currencyEventBook,currencyEventCurrent} from '../../resources/js/lib/iva-currency-events.ts';
const selection=()=>({...emptyFxSelection(),nature:'commercial',submissionDate:'2026-10-23',bulletinDate:'2026-10-23',bulletinRef:'SYNTHETIC QA boletimBM de referência,23/10/2026',source:'https://www.bancomoc.mz/pt/areas-de-actuacao/mercados/mercado-cambial/',sourceCurrency:'USD',direction:'mzn_per_unit',bulletinPerspective:'SYNTHETIC QA bancos perante público',relation:'same',buy:'63.27',sell:'64.54',mean:'63.91'});
for(const[nature,relation,column,rate]of[['purchase','same','buy','63.27'],['sale','same','sell','64.54'],['purchase','opposite','sell','64.54'],['sale','opposite','buy','63.27'],['commercial','','mean','63.91']])test(`P104 ${nature}/${relation||'médiaBM'} escolhe ${column} sem inverter cliente`,()=>{const result=selectFx({...selection(),nature,relation});assert.equal(result.column,column);assert.equal(result.rate,rate);assert.equal(result.date,'2026-10-23');});
test('P104 falta de boletim/data/perspectiva não autoriza taxa actual,média própria ou coluna oposta presumida',()=>{for(const patch of [{bulletinDate:'2026-10-22'},{mean:''},{source:'https://example.com/cambio'},{submissionDate:'2026-02-30'},{nature:''},{nature:'purchase',relation:''},{nature:'sale',bulletinPerspective:''}])assert.throws(()=>selectFx({...selection(),...patch}));assert.equal(selectFx({...selection(),source:'SYNTHETIC QA exemplar oficial arquivado',issuer:'Banco de Moçambique'}).column,'mean');const exception={...selection(),mode:'exception',exceptionRef:'SYNTHETIC QA disposição fiscal específica',exceptionScope:'SYNTHETIC QA apenas operaçãoA',exceptionDate:'2026-10-20',exceptionRate:'62.12345678'};assert.equal(selectFx(exception).rate,'62.12345678');assert.equal(selectFx(exception).date,'2026-10-20');assert.throws(()=>selectFx({...exception,exceptionRef:''}));});
const frozen=JSON.parse(fs.readFileSync('tests/frontend/fixtures/iva-offer-workflow.json','utf8')),prior=JSON.parse(frozen.modelo_a_snapshot),draft={...frozen,context_opportunity:'opportunity:365',project_title:'SYNTHETIC QA — P104 operacional / Manica'};
function row(){const s=selection(),applied=selectFx(s);return{...newCurrencyEvent('commercial','MZN'),treatment:'foreign_scenario',description:'SYNTHETIC QA operação comercial',period:'2026-10',origin:'effective',operationRef:'SYNTHETIC QA operação já declarada',documentRef:'SYNTHETIC QA factura',documentDate:'2026-10-23',scope:'SYNTHETIC QA operaçãoA',evidence:'SYNTHETIC QA factos',factsConfirmed:'yes',amount:'100.25',sourceCurrency:'USD',fxRate:applied.rate,fxDate:applied.date,fxSource:applied.source,fxRuleRef:fxTempoSource,fxDirection:s.direction,fxSelection:{...s,applied}};}
test('P104 original/convertido,direcção e taxa guardados;semIVA,nova dedução ou alteração automática',()=>{const r=row(),v=evaluateCurrencyEvent(r);assert.equal(v.status,'determined');assert.equal(v.scenarioAmount,'6406.9775');assert.equal(v.baseAmount,null);assert.equal(v.vat,null);const reverse={...r,fxDirection:'units_per_mzn',fxSelection:{...r.fxSelection,direction:'units_per_mzn'}};const applied=selectFx(reverse.fxSelection);reverse.fxSelection.applied=applied;reverse.fxSource=applied.source;assert.equal(evaluateCurrencyEvent(reverse).scenarioAmount,'1.568612');assert.equal(evaluateCurrencyEvent({...r,fxRate:'999'}).status,'indeterminate');assert.equal(evaluateCurrencyEvent({...r,fxSelection:{...r.fxSelection,submissionDate:'2026-10-24'}}).status,'indeterminate');});
test('P104 versões antigas permanecem condicionadas e127fechos/P058/ofertas permanecem iguais',()=>{const r=row(),legacy={...r};delete legacy.fxSelection;assert.equal(evaluateCurrencyEvent(legacy).status,'conditional');let b=recordCurrencyEvents(draft,{rows:[r]});const saved=structuredClone(b.result);const changed={...b,rows:[{...r,amount:'200'}]};assert.equal(currencyEventCurrent(draft,changed),false);assert.deepEqual(b.result,saved);b=recordCurrencyEvents(draft,changed);assert.deepEqual(b.history[0],saved);draft.modelo_a_snapshot=saveCurrencyEventBook(draft,b);assert.deepEqual(currencyEventBook(draft),b);const next=JSON.parse(draft.modelo_a_snapshot);assert.deepEqual(Object.fromEntries(Object.entries(prior).filter(([k])=>k!=='currencyEvents')),Object.fromEntries(Object.entries(next).filter(([k])=>k!=='currencyEvents')));for(const[k,v]of Object.entries(prior.currencyEvents??{}))assert.deepEqual(next.currencyEvents[k],v);if(process.env.IVA_FX_SELECTION_FIXTURE)fs.writeFileSync('tests/frontend/fixtures/iva-fx-selection.json',JSON.stringify(draft));});