Files
Investidor-V2/tests/frontend/iva-offer-paths.test.mjs
T

35 lines
7.0 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import { offerPreparationBook,saveOfferPreparationBook,recordOfferRequest,emptyOfferRequest,offerScenarios,offerPathReport,recordOfferPreparations } from '../../resources/js/lib/iva-offer-preparations.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const frozen=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-g6e-inputs.json',import.meta.url),'utf8'));
const draft=()=>({...structuredClone(frozen),context_opportunity:'opportunity:334',project_title:'SYNTHETIC QA — Offer paths'});
const row84=()=>({...offerPreparationBook(draft()).rows[0],normalVat:'800',normalVatSource:'SYNTHETIC QA pressuposto expresso, não taxa inferida',conditionalAssumption:'yes'});
test('presented request never grants benefit;normal amount requires own source and conditional scenario explicit material assumptions',()=>{
const row={...row84(),request:{...emptyOfferRequest(),state:'presented',reference:'SYNTHETIC QA pedido',presentedOn:'2026-11-20'}};
assert.deepEqual(offerScenarios(row),{normalVat:'800',conditionalVat:'0.00',conditionalReason:offerScenarios(row).conditionalReason,applied:false});assert.match(offerScenarios(row).conditionalReason,/Não é benefício concedido/);
for(const patch of [{conditionalAssumption:''},{goodsSuitable:''},{goodsSuitable:'no'},{period:'2027-01'},{currency:'USD'}])assert.equal(offerScenarios({...row,...patch}).conditionalVat,null);
for(const patch of [{normalVat:''},{normalVatSource:''},{normalVat:'-10'},{normalVat:'desconhecido'}])assert.equal(offerScenarios({...row,...patch}).normalVat,null);
assert.match(offerPathReport(row),/Pedido Apresentado/);assert.match(offerPathReport(row),/apresentar pedido não concede isenção/);
});
test('P084 recorded decisions preserve goods/operation/period/conditions and previous decision when current inputs change',()=>{
let row={...row84(),request:{...emptyOfferRequest(),state:'granted',decisionRef:'SYNTHETIC QA decisão parcial',decisionOn:'2026-11-25',goods:'SYNTHETIC QA só bens A',operation:'import',periodFrom:'2026-12',periodTo:'2026-12',conditions:'SYNTHETIC QA exclusivamente entrega ao destinatário A'}};
row=recordOfferRequest(row);assert.equal(row.requestRecords.length,1);const accepted=structuredClone(row.requestRecords[0]);
row={...row,description:'Bens B posteriores',operation:'acquisition',period:'2027-01',request:{...row.request,state:'denied',decisionRef:'SYNTHETIC QA decisão B',goods:'Bens B',periodFrom:'2027-01',periodTo:'2027-01',operation:'acquisition',conditions:'SYNTHETIC QA apenas pedido B'}};row=recordOfferRequest(row);assert.deepEqual(row.requestRecords[0],accepted);assert.equal(row.requestRecords.length,2);assert.equal(offerScenarios(row).applied,false);assert.equal(offerScenarios(row).conditionalVat,null);assert.match(offerPathReport(row),/não estender decisão/);
for(const key of ['goods','operation','periodFrom','periodTo','conditions'])assert.throws(()=>recordOfferRequest({...row,request:{...row.request,[key]:''}}),/âmbito da decisão/);
const exact=recordOfferRequest({...row,request:{...row.request,periodFrom:'2027-01-10',periodTo:'2027-01-15'}});assert.equal(exact.requestRecords.at(-1).request.periodFrom,'2027-01-10');assert.equal(exact.requestRecords.at(-1).request.periodTo,'2027-01-15');assert.throws(()=>recordOfferRequest({...row,request:{...row.request,periodFrom:'2027-02-30',periodTo:'2027-03-01'}}),/âmbito da decisão/);
const literal=recordOfferRequest({...row,request:{...row.request,operation:'',operationScope:'SYNTHETIC QA aquisição e importação dos bens A',periodFrom:'',periodTo:'',periodScope:'SYNTHETIC QA desde a decisão até revogação, sem termo'}});assert.match(offerPathReport(literal),/até revogação, sem termo/);assert.equal(literal.requestRecords.at(-1).request.operationScope,'SYNTHETIC QA aquisição e importação dos bens A');
assert.equal(row.requestRecords[0].request.operation,'import');assert.equal(row.operation,'acquisition');
});
test('P085 humanitarian purpose/emergency/documents are distinct;missing inputs stay indeterminate and no P084 state is imposed',()=>{
const base={...offerPreparationBook(draft()).rows[1],period:'2026-12',beneficiary:'SYNTHETIC QA destinatário',purpose:'SYNTHETIC QA atenuar cheias',humanitarianPurpose:'SYNTHETIC QA água e alimentação para deslocados',availableDocuments:'SYNTHETIC QA lista de bens\nSYNTHETIC QA guia disponível',normalVat:'160',normalVatSource:'SYNTHETIC QA previsão explícita',conditionalAssumption:'yes'};
assert.equal(offerScenarios(base).conditionalVat,'0.00');assert.equal(offerScenarios({...base,humanitarianPurpose:''}).conditionalVat,null);assert.equal(offerScenarios({...base,mitigation:'no'}).conditionalVat,null);assert.throws(()=>recordOfferRequest(base),/P084/);assert.match(offerPathReport(base),/finalidade humanitária/);assert.match(offerPathReport(base),/procedimento de emergência\/doação por corresponder/);assert.equal(base.request,undefined);
});
test('save/recover/report retain old drafts/histories and all27fiscalbooks;normal and conditional are labelled and field11 stays unchanged',()=>{
const d=draft(),prior=JSON.parse(frozen.modelo_a_snapshot),old=offerPreparationBook(d);const priorDecision=recordOfferRequest({...row84(),request:{...emptyOfferRequest(),state:'granted',decisionRef:'SYNTHETIC QA decisão parcial anterior',goods:'SYNTHETIC QA apenas bens A',operation:'import',periodFrom:'2026-11',periodTo:'2026-11',conditions:'SYNTHETIC QA só a operação anterior A'}});const p84=recordOfferRequest({...priorDecision,request:{...emptyOfferRequest(),state:'presented',reference:'SYNTHETIC QA pedido em apreciação'}});const p85={...old.rows[1],period:'2026-12',beneficiary:'SYNTHETIC QA destinatário',purpose:'SYNTHETIC QA resposta humanitária',humanitarianPurpose:'SYNTHETIC QA assistência imediata às vítimas das cheias',availableDocuments:'SYNTHETIC QA bens e destinatário',normalVat:'160',normalVatSource:'SYNTHETIC QA previsão sem taxa inferida',conditionalAssumption:'yes'};
const book=recordOfferPreparations({...old,rows:[p84,p85]});assert.deepEqual(book.history.at(-1),old.saved);d.modelo_a_snapshot=saveOfferPreparationBook(d,book);assert.deepEqual(offerPreparationBook(JSON.parse(JSON.stringify(d))),book);const next=JSON.parse(d.modelo_a_snapshot);for(const key of ['books','salesOperations','importExemptions'])assert.deepEqual(next[key],prior[key]);assert.equal(next.books['opportunity:329'].result.periods[0].fields['11'],null);
const report=JSON.stringify(createProjectDossierReport(d,{selectedSections:new Set(['finance']),version:'QA offer paths'}));for(const token of ['Pedido Apresentado','Cenário normal','Cenário condicionado à isenção','hipótese','finalidade humanitária','benefício não aplicado','800','160','apresentar pedido não concede isenção','SYNTHETIC QA decisão parcial anterior','SYNTHETIC QA apenas bens A','2026-11'])assert.ok(report.includes(token),token);
if(process.env.IVA_OFFER_PATHS)fs.writeFileSync(process.env.IVA_OFFER_PATHS,JSON.stringify(d));
});