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

271 lines
9.4 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',
});
void 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/);
});
void 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');
});
void test('P085 humanitarian purpose/emergency/documents are distinct;missing inputs stay indeterminate and operational states may now be recorded under Tempo25/10', () => {
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.equal(
recordOfferRequest(base).requestRecords.at(-1).request.state,
'preparation',
);
assert.match(offerPathReport(base), /finalidade humanitária/);
assert.match(
offerPathReport(base),
/procedimento de emergência\/doação por corresponder/,
);
assert.equal(base.request, undefined);
});
void 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));
});