Files
Investidor-V2/tests/frontend/iva-special-regimes.test.mjs
T

49 lines
5.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import { specialRegimeTreatments as rules, specialRegimeOptions, specialRegimesFor, specialRegimeIssue } from '../../resources/js/lib/iva-special-regimes.ts';
import { newSalesOperation, evaluateSalesOperation, recordSales, saveSalesBook, salesBook, salesCurrent } from '../../resources/js/lib/iva-operations.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const frozen=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-g4e-inputs.json',import.meta.url),'utf8'));
const regimes=['economic_zone','customs_warehouse','free_zone','duty_free_shop','transit','temporary_import'];
const row=(rule,i)=>({...newSalesOperation(`g5a-${i}`,'2026-12','MZN'),description:`SYNTHETIC QA — ${rule.label}`,establishment:'SYNTHETIC QA estabelecimento',amount:'100',basis:i%2?'included':'net',treatment:rule.id,specialRegime:regimes[i],confirmed:rule.conditions.map((_,n)=>n),evidence:'SYNTHETIC QA — pressuposto expresso de projecção: bens e operação identificados; regime e controlo/documento, destino, permanência no período, ausência de utilização/consumo final e ligação directa do serviço/transporte identificados. Cada linha tem preço próprio, sem duplicar bens. Sem certificação real.'});
function fixture(){
const draft={...structuredClone(frozen),context_opportunity:'opportunity:328',project_title:'SYNTHETIC QA — G5A / Regimes especiais'};
const book=recordSales(draft,{currency:'MZN',rows:rules.map(row),periods:[{period:'2026-12',complete:true}]});draft.modelo_a_snapshot=saveSalesBook(draft,book);return{draft,book};
}
test('three branches/six goods-service treatments require own conditions,no final use and identified regime',()=>{
assert.equal(rules.length,6);
for(const[i,rule]of rules.entries()){
const input=row(rule,i),result=evaluateSalesOperation(input,'MZN');assert.equal(result.field,'05');assert.equal(result.vat,'0.00');assert.equal(result.net,'100.00');assert.equal(result.gross,'100.00');assert.match(result.article,/19\(1\)\(b\)\(iv\)/);
for(const missing of input.confirmed)assert.equal(evaluateSalesOperation({...input,confirmed:input.confirmed.filter(n=>n!==missing)},'MZN').vat,null);
for(const patch of [{amount:''},{evidence:''},{sourceCurrency:'USD'},{period:'2027-01'},{basis:''},{description:''},{establishment:''}])assert.equal(evaluateSalesOperation({...input,...patch},'MZN').vat,null);
assert.match(rule.conditions.join(' '),/não têm utilização nem consumo finais/);
}
});
test('regimes from another paragraph or unknown are indeterminate;destination and service conditions remain distinct',()=>{
for(const[i,rule]of rules.entries()){
for(const[regime]of specialRegimeOptions){const result=evaluateSalesOperation({...row(rule,i),specialRegime:regime},'MZN');const allowed=specialRegimesFor(rule.id).some(([id])=>id===regime);assert.equal(result.vat,allowed?'0.00':null);if(!allowed){assert.equal(result.net,null);assert.equal(result.field,null);}}
for(const regime of [undefined,'',null,'other'])assert.equal(evaluateSalesOperation({...row(rule,i),specialRegime:regime},'MZN').vat,null);
}
assert.match(rules[0].conditions.join(' '),/loja franca por si não comprova/);
assert.equal(evaluateSalesOperation({...row(rules[0],0),specialRegime:'duty_free_shop',confirmed:[0,1,3]},'MZN').vat,null);
assert.equal(specialRegimeIssue('regime_internal_goods','duty_free_shop'),null);
assert.equal(specialRegimeIssue('general',undefined),null);assert.deepEqual(specialRegimesFor('general'),[]);
});
test('change of regime or ending eligibility preserves price,context/history and blocks presumptive totals',()=>{
const{draft,book}=fixture();assert.equal(book.result.periods[0].fields['05'],'600.00');
for(const patch of [{specialRegime:'transit',confirmed:[]},{specialRegime:'',confirmed:[]},{confirmed:[],evidence:'Regime terminado; rever enquadramento'}]){
const changed=recordSales(draft,{...book,rows:book.rows.map((r,i)=>i===0?{...r,...patch}:r)});
assert.equal(changed.rows[0].amount,'100');assert.equal(changed.rows[0].sourceCurrency,'MZN');assert.equal(changed.rows[0].period,'2026-12');assert.equal(changed.result.periods[0].fields['05'],null);assert.deepEqual(changed.history.at(-1),book.result);
const edited={...draft,modelo_a_snapshot:saveSalesBook(draft,{...book,rows:changed.rows})};assert.equal(salesCurrent(edited,salesBook(edited)),false);
}
});
test('snapshot/report retain regime,source and assumptions;all19 previous books are identical/current without recalculation',()=>{
const{draft,book}=fixture();assert.ok(salesCurrent(draft,book));assert.deepEqual(salesBook(JSON.parse(JSON.stringify(draft))),JSON.parse(JSON.stringify(book)));
const before=JSON.parse(frozen.modelo_a_snapshot).salesOperations,after=JSON.parse(draft.modelo_a_snapshot).salesOperations;assert.equal(Object.keys(before).length,19);
for(const[context,original]of Object.entries(before)){assert.deepEqual(after[context],original);assert.ok(salesCurrent({...draft,context_opportunity:context},after[context]));}
const report=JSON.stringify(createProjectDossierReport(draft,{selectedSections:new Set(['finance']),version:'QA G5A'}));
for(const token of ['opportunity:328','Manica','2026-12','600.00','14(1)(b)','14(1)(c)','14(1)(d)','19(1)(b)(iv)','Regime especial','Importação temporária','Loja franca','pressuposto expresso','QA G5A'])assert.ok(report.includes(token),token);
if(process.env.IVA_G5A_CALCULATED)fs.writeFileSync(process.env.IVA_G5A_CALCULATED,JSON.stringify(draft));
});