16 lines
5.7 KiB
JavaScript
16 lines
5.7 KiB
JavaScript
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
|
import {newOfferPreparation,emptyOfferRequest,saveOfferPreparationBook,offerPreparationBook,offerScenarios,offerPathReport} from '../../resources/js/lib/iva-offer-preparations.ts';
|
|
import {emptyOfferWorkflow,recordOfferWorkflow,offerWorkflowApplied,offerWrittenRequest} from '../../resources/js/lib/iva-offer-workflow.ts';
|
|
const frozen=JSON.parse(fs.readFileSync('tests/frontend/fixtures/iva-returnees.json','utf8')),draft={...frozen,context_opportunity:'opportunity:364',project_title:'SYNTHETIC QA — Pedidos ofertas / Manica'},prior=JSON.parse(frozen.modelo_a_snapshot);
|
|
const attachment={id:'00000000-0000-4000-8000-000000000001',draftId:'00000000-0000-4000-8000-000000000002',name:'SYNTHETIC-QA-despacho.txt',sha256:'a'.repeat(64),scan:'pending',url:'/api/v1/simulation-drafts/00000000-0000-4000-8000-000000000002/offer-documents/00000000-0000-4000-8000-000000000001'};
|
|
function initial(branch){return{...newOfferPreparation(branch,branch,'MZN'),operation:'acquisition',description:'SYNTHETIC QA bensA',period:'2026-10',amount:'1000',beneficiary:'SYNTHETIC QA entidade',purpose:branch==='P084'?'SYNTHETIC QA interesse público/fins sociais':'SYNTHETIC QA atenuar cheias',evidence:'SYNTHETIC QA justificação',nationalInstitution:'yes',publicSocialInstitution:'yes',goodsSuitable:'yes',publicInterestUse:'yes',mitigation:'yes',disaster:'SYNTHETIC QA cheias',humanitarianPurpose:'SYNTHETIC QA assistência humanitária',normalVat:'160',normalVatSource:'SYNTHETIC QA hipótese',conditionalAssumption:'yes',request:emptyOfferRequest(),workflow:emptyOfferWorkflow()};}
|
|
const completed=[];
|
|
for(const branch of ['P084','P085'])test(branch+' pedido → apresentação externa → decisão anexa → formulário com despacho',()=>{
|
|
let row=recordOfferWorkflow(initial(branch),'request');assert.equal(offerWorkflowApplied(row).applied,false);assert.match(offerWrittenRequest(row,row.workflow),/apresentação ocorre fora/);row={...row,request:{...row.request,state:'presented',reference:'SYNTHETIC QA pedido1',presentedOn:'2026-10-01'}};row=recordOfferWorkflow(row,'presented');assert.equal(offerScenarios(row).applied,false);assert.equal(offerScenarios(row).conditionalVat,'0.00');
|
|
row={...row,request:{...row.request,state:'granted',decisionRef:'SYNTHETIC QA despacho1',decisionOn:'2026-10-03',goods:'SYNTHETIC QA apenas bensA',operation:'acquisition',periodFrom:'2026-10',periodTo:'2026-10',conditions:'SYNTHETIC QA só operaçãoA'},workflow:{...row.workflow,decisionIssuer:'SYNTHETIC QA MF/AT',decisionAttachment:attachment,scopeConfirmed:'yes'}};
|
|
row=recordOfferWorkflow(row,'decision');assert.equal(offerScenarios(row).applied,true);assert.throws(()=>recordOfferWorkflow({...row,description:'outros bens'},'form'),/explicitamente/);const outside=recordOfferWorkflow({...row,request:{...row.request,periodFrom:'2027-01',periodTo:'2027-01'}},'decision');assert.equal(offerWorkflowApplied(outside).applied,false);assert.equal(offerScenarios(row).appliedVat,'0.00');assert.equal(offerWorkflowApplied({...row,description:'outros bens'}).applied,false);assert.equal(offerWorkflowApplied({...row,period:'2026-11'}).applied,false);assert.equal(offerWorkflowApplied({...row,beneficiary:'outra entidade'}).applied,false);assert.equal(offerWorkflowApplied({...row,request:{...row.request,state:'denied'}}).applied,false);
|
|
row={...row,workflow:{...row.workflow,formName:'SYNTHETIC QA formulário aplicável',formSource:'SYNTHETIC QA correspondência documentada apenas operaçãoA',formContent:offerWrittenRequest(row,row.workflow)}};row=recordOfferWorkflow(row,'form');assert.equal(row.workflow.formDecisionId,attachment.id);assert.equal(row.workflow.formDecisionHash,attachment.sha256);assert.deepEqual(row.workflow.records.map(r=>r.stage),['request','presented','decision','form']);assert.match(offerPathReport(row),/Procedimento operacional fornecido pela Tempo/);assert.match(offerPathReport(row),/submissão fora/);assert.match(offerPathReport(row),/SYNTHETIC QA pedido1/);assert.match(offerPathReport(row),/2026-10-01/);completed.push(row);
|
|
});
|
|
test('decisão e formulário incompletos não bloqueiam guardar rascunho nem inventam concessão',()=>{const row=initial('P085');assert.throws(()=>recordOfferWorkflow({...row,request:{...row.request,state:'presented'}},'presented'),/referência/);assert.throws(()=>recordOfferWorkflow({...row,request:{...row.request,state:'granted'}},'decision'),/número/);const denied={...completed[0],request:{...completed[0].request,state:'denied'}};assert.throws(()=>recordOfferWorkflow(denied,'form'),/indeferimento/);for(const patch of [{decisionIssuer:''},{decisionAttachment:undefined},{scopeConfirmed:'no'}])assert.equal(offerWorkflowApplied({...completed[0],workflow:{...completed[0].workflow,...patch}}).applied,false);const value=saveOfferPreparationBook(draft,{rows:[row]});assert.equal(offerPreparationBook({...draft,modelo_a_snapshot:value}).rows[0].workflow.records.length,0);});
|
|
test('127 fechos e P058 parcial conservados;histórico e ambos percursos recuperáveis',()=>{const old=prior.offerPreparations??{};const value=saveOfferPreparationBook(draft,{rows:completed});draft.modelo_a_snapshot=value;const next=JSON.parse(value);assert.deepEqual(Object.fromEntries(Object.entries(next).filter(([k])=>k!=='offerPreparations')),Object.fromEntries(Object.entries(prior).filter(([k])=>k!=='offerPreparations')));for(const[k,v]of Object.entries(old))assert.deepEqual(next.offerPreparations[k],v);assert.equal(offerPreparationBook(draft).rows.length,2);assert.deepEqual(next.returneeImports,prior.returneeImports);if(process.env.IVA_OFFER_WORKFLOW_FIXTURE)fs.writeFileSync('tests/frontend/fixtures/iva-offer-workflow.json',JSON.stringify(draft));});
|