56 lines
5.1 KiB
JavaScript
56 lines
5.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {mkdir,writeFile} from 'node:fs/promises';
|
|
import JSZip from 'jszip';
|
|
import {defaultCashflowDraftInputs,serializeCashflowDraftSnapshot,restoreCashflowDraftSnapshot,cashflowCurrency} from '../../resources/js/lib/monthly-cashflow.ts';
|
|
import {monthlyIvaInput,recoverMonthlyIvaRecord} from '../../resources/js/lib/monthly-iva.ts';
|
|
import {exportProjectDossierCsv,buildProjectDossierRows} from '../../resources/js/lib/project-dossier.ts';
|
|
import {createProjectDossierReport,generateProjectDossierDocx,createProjectDossierPrintHtml} from '../../resources/js/lib/project-dossier-report.ts';
|
|
import {closureFixture} from './fixtures/simulator-closure-fixture.mjs';
|
|
|
|
test('S1 saved USD stays USD in report and cannot be reused as MZN for IVA',()=>{
|
|
const inputs={...defaultCashflowDraftInputs(),monthlyRevenue:'123',monthlyTaxAssessed:'0'};
|
|
const snapshot=serializeCashflowDraftSnapshot('fixed',inputs,'USD');
|
|
const draft={currency:'MZN',cashflow_snapshot:snapshot};
|
|
const saved=restoreCashflowDraftSnapshot(snapshot);
|
|
assert.equal(saved.currency,'USD');assert.deepEqual(saved.inputs,inputs);
|
|
assert.equal(cashflowCurrency(saved,'MZN').matchesProject,false);
|
|
assert.throws(()=>monthlyIvaInput(draft,{start:'2026-01',basis:'net',declared:true,auto:false}),/continuam em USD/);
|
|
const rows=buildProjectDossierRows(draft).filter(r=>r[0]==='Tesouraria');
|
|
assert.match(rows.find(r=>r[1]==='Pressupostos e período')[2],/moeda USD/);
|
|
assert.match(rows.find(r=>r[1]==='Divergência de moeda')[2],/não foram convertidos/);
|
|
const restoredProject={...draft,currency:'USD'};
|
|
assert.equal(cashflowCurrency(restoreCashflowDraftSnapshot(restoredProject.cashflow_snapshot),restoredProject.currency).matchesProject,true);
|
|
assert.equal(restoredProject.cashflow_snapshot,snapshot);
|
|
});
|
|
test('S1 legacy amounts remain readable but require explicit origin currency before reuse',()=>{
|
|
const inputs={...defaultCashflowDraftInputs(),monthlyRevenue:'123'};
|
|
const legacy=serializeCashflowDraftSnapshot('fixed',inputs);const saved=restoreCashflowDraftSnapshot(legacy);
|
|
assert.equal(saved.version,1);assert.throws(()=>cashflowCurrency(saved,'MZN'),/por confirmar/);
|
|
const confirmed=restoreCashflowDraftSnapshot(serializeCashflowDraftSnapshot(saved.taxMode,saved.inputs,'USD'));
|
|
assert.deepEqual(confirmed.inputs,saved.inputs);assert.equal(confirmed.currency,'USD');
|
|
assert.equal(restoreCashflowDraftSnapshot(legacy).version,1);
|
|
});
|
|
test('S2 recovery is a same-ID authenticated GET without new admission and preserves denied records',async()=>{
|
|
const pending=closureFixture('queued');const completed=closureFixture();const calls=[];
|
|
const record={input:pending.input,execution:pending.execution};const before=JSON.stringify(record);
|
|
const request=async(url,options)=>{calls.push({url,options});return new Response(JSON.stringify({data:completed.execution}),{status:200});};
|
|
const recovered=await recoverMonthlyIvaRecord(record,request);
|
|
assert.equal(recovered.execution.id,pending.execution.id);assert.equal(recovered.execution.status,'completed');assert.deepEqual(recovered.input,pending.input);
|
|
assert.equal(calls.length,1);assert.equal(calls[0].options.credentials,'same-origin');assert.equal(calls[0].options.method,undefined);assert.match(calls[0].url,/simulations\/06566910/);
|
|
await assert.rejects(()=>recoverMonthlyIvaRecord(record,async()=>new Response('{}',{status:403})),/preservados/);
|
|
await assert.rejects(()=>recoverMonthlyIvaRecord(record,async()=>new Response(JSON.stringify({data:{...completed.execution,id:'00000000-0000-4000-8000-000000000000'}}),{status:200})),/preservados/);
|
|
assert.equal(JSON.stringify(record),before);
|
|
});
|
|
test('S3 final CSV Word and print source retain frozen monthly values context source and version',async()=>{
|
|
const {draft}=closureFixture();
|
|
const report=createProjectDossierReport(draft,{selectedSections:new Set(['sources','finance']),version:'SYNTHETIC QA S3'});
|
|
const csv=exportProjectDossierCsv(draft);const html=await createProjectDossierPrintHtml(report,[],false);
|
|
const docx=await generateProjectDossierDocx(report,[],true);const bytes=new Uint8Array(await docx.arrayBuffer());const word=await JSZip.loadAsync(bytes);const xml=await word.file('word/document.xml').async('string');
|
|
for(const text of [csv,html,xml]) for(const expected of ['160.0048','320.0096','1160.0348','MZN','2026-01','2026-04','Fonte sintética QA','IVA-GERAL-BASE-LIQUIDA','segunda oportunidade Manica','opportunity:309']) assert.ok(text.includes(expected),expected);
|
|
for(const text of [csv,html,xml]) assert.match(text,/IVA-GERAL-BASE-LIQUIDA[^\n<]{0,30}4/);
|
|
assert.match(html,/segunda oportunidade Manica/);assert.match(xml,/segunda oportunidade Manica/);
|
|
const out='outputs/simulator-closure-qa-20261024';await mkdir(out,{recursive:true});
|
|
await Promise.all([writeFile(`${out}/monthly-final.csv`,csv),writeFile(`${out}/monthly-final.docx`,bytes),writeFile(`${out}/monthly-final.html`,html),writeFile(`${out}/frozen-fixture.json`,JSON.stringify(draft,null,2))]);
|
|
});
|