470 lines
18 KiB
JavaScript
470 lines
18 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {
|
|
recordSales,
|
|
saveSalesBook,
|
|
} from '../../resources/js/lib/iva-operations.ts';
|
|
import {
|
|
recordAcquisitions,
|
|
saveAcquisitionBook,
|
|
acquisitionBook,
|
|
} from '../../resources/js/lib/iva-acquisitions.ts';
|
|
import {
|
|
closureBook,
|
|
closureSources,
|
|
newClosure,
|
|
recordClosure,
|
|
saveClosureBook,
|
|
adoptPreviousCredit,
|
|
newClosureCredit,
|
|
closureCurrent,
|
|
} from '../../resources/js/lib/iva-closure.ts';
|
|
import {
|
|
substitutionBook,
|
|
substitutionCurrent,
|
|
} from '../../resources/js/lib/iva-substitution.ts';
|
|
import {
|
|
refundBook,
|
|
refundSources,
|
|
newRefund,
|
|
recordRefund,
|
|
saveRefundBook,
|
|
refundCurrent,
|
|
refundReportRows,
|
|
} from '../../resources/js/lib/iva-refund.ts';
|
|
const seed = JSON.parse(
|
|
fs.readFileSync(
|
|
new URL('./fixtures/iva-l3d-preserved.json', import.meta.url),
|
|
'utf8',
|
|
),
|
|
),
|
|
older = JSON.parse(
|
|
fs.readFileSync(
|
|
new URL('./fixtures/iva-l3ab-preserved.json', import.meta.url),
|
|
'utf8',
|
|
),
|
|
);
|
|
function fixture() {
|
|
const d = structuredClone(seed),
|
|
base = JSON.parse(older.modelo_a_snapshot),
|
|
s = JSON.parse(d.modelo_a_snapshot);
|
|
for (const [k, v] of Object.entries(base))
|
|
if (k !== 'version') s[k] = { ...v, ...s[k] };
|
|
d.modelo_a_snapshot = JSON.stringify(s);
|
|
d.context_opportunity = 'opportunity:374';
|
|
const sales = structuredClone(s.salesOperations['opportunity:373']);
|
|
d.modelo_a_snapshot = saveSalesBook(d, recordSales(d, sales));
|
|
const b = structuredClone(s.books['opportunity:373']);
|
|
b.rows[0].net = '5001000';
|
|
b.rows[0].vat = '800160';
|
|
b.rows[0].gross = '5801160';
|
|
delete b.result;
|
|
delete b.history;
|
|
d.modelo_a_snapshot = saveAcquisitionBook(
|
|
d,
|
|
recordAcquisitions(d, b, '2026-10-25T13:00:00Z'),
|
|
);
|
|
const row = {
|
|
...newClosure(
|
|
'refund-Jan',
|
|
closureSources(d).find((s) => s.period === '2026-01'),
|
|
'SYNTHETIC QA entidade374',
|
|
),
|
|
firstDeclaration: 'yes',
|
|
filing: 'timely',
|
|
submissionDate: '2026-02-15',
|
|
filingRef: 'SYNTHETIC QA prazo declarado',
|
|
creditsComplete: 'yes',
|
|
interest: 'none',
|
|
interestRef: 'SYNTHETIC QA sem juros',
|
|
destination: 'refund',
|
|
refundAmount: '600000',
|
|
};
|
|
const ab = recordClosure(
|
|
d,
|
|
{ version: 1, rows: [row] },
|
|
'2026-10-25T13:01:00Z',
|
|
);
|
|
d.modelo_a_snapshot = saveClosureBook(d, ab);
|
|
assert.equal(
|
|
ab.result.rows[0].status,
|
|
'determined',
|
|
ab.result.rows[0].reason,
|
|
);
|
|
const input = {
|
|
...newRefund('refund1', refundSources(d)[0]),
|
|
ground: 'high_credit',
|
|
originPeriod: '2026-01',
|
|
entitlementDate: '2026-01-10',
|
|
groundRef:
|
|
'SYNTHETIC QA extractos/origem800000 e créditos mais antigos',
|
|
factsConfirmed: 'yes',
|
|
oldestFirst: 'yes',
|
|
requestReference: 'SYNTHETIC QA pedidoR1',
|
|
requestDate: '2026-02-15',
|
|
stage: 'submitted',
|
|
decision: 'partial',
|
|
decisionReference: 'SYNTHETIC QA decisãoD1',
|
|
decisionDate: '2026-03-01',
|
|
decisionIssuer: 'SYNTHETIC QA entidade emitente declarada',
|
|
approvedAmount: '550000',
|
|
receipts: [
|
|
{
|
|
id: 'receipt1',
|
|
reference: 'SYNTHETIC QA recebimentoR1a',
|
|
date: '2026-03-05',
|
|
amount: '200000',
|
|
},
|
|
{
|
|
id: 'receipt2',
|
|
reference: 'SYNTHETIC QA recebimentoR1b',
|
|
date: '2026-03-10',
|
|
amount: '250000',
|
|
},
|
|
],
|
|
};
|
|
return { d, b: { version: 1, rows: [input] } };
|
|
}
|
|
const n = (v) => v && `${v.numerator}/${v.denominator}`;
|
|
void test('25 is allocated once between26 and27;requested,approved,received and waiting remain distinct', () => {
|
|
const { d, b } = fixture(),
|
|
ab = closureBook(d).result.rows[0];
|
|
assert.equal(n(ab.fields['25']), '800000/1');
|
|
assert.equal(n(ab.fields['26']), '200000/1');
|
|
assert.equal(n(ab.fields['27']), '600000/1');
|
|
const r = recordRefund(d, b).result.rows[0];
|
|
assert.equal(r.status, 'determined', r.reason);
|
|
assert.equal(r.eligibility, 'compatible');
|
|
assert.equal(n(r.requested), '600000/1');
|
|
assert.equal(n(r.reported), '200000/1');
|
|
assert.equal(n(r.approved), '550000/1');
|
|
assert.equal(n(r.received), '450000/1');
|
|
assert.equal(n(r.awaitingReceipt), '100000/1');
|
|
assert.equal(n(r.notGranted), '50000/1');
|
|
});
|
|
void test('preparation,presented pending,approval and rejection do not automatically create receipt or release credit', () => {
|
|
const { d, b } = fixture();
|
|
for (const stage of ['preparation', 'submitted']) {
|
|
const v = structuredClone(b);
|
|
Object.assign(v.rows[0], { stage, decision: 'pending', receipts: [] });
|
|
const r = recordRefund(d, v).result.rows[0];
|
|
assert.equal(r.status, 'determined');
|
|
assert.equal(r.approved, null);
|
|
assert.equal(r.received, null);
|
|
}
|
|
const full = structuredClone(b);
|
|
Object.assign(full.rows[0], {
|
|
decision: 'approved',
|
|
approvedAmount: '600000',
|
|
receipts: [],
|
|
});
|
|
let r = recordRefund(d, full).result.rows[0];
|
|
assert.equal(n(r.received), '0/1');
|
|
assert.equal(n(r.awaitingReceipt), '600000/1');
|
|
const rejected = structuredClone(b);
|
|
Object.assign(rejected.rows[0], {
|
|
decision: 'rejected',
|
|
approvedAmount: '0',
|
|
receipts: [],
|
|
});
|
|
r = recordRefund(d, rejected).result.rows[0];
|
|
assert.equal(r.status, 'determined');
|
|
assert.equal(n(r.notGranted), '600000/1');
|
|
assert.equal(n(closureBook(d).result.rows[0].fields['26']), '200000/1');
|
|
});
|
|
void test('source,request and decision details are required;unknown never becomes entitlement or cash', () => {
|
|
const { d, b } = fixture();
|
|
for (const patch of [
|
|
{ source: null },
|
|
{ requestReference: '' },
|
|
{ requestDate: '' },
|
|
{ decisionReference: '' },
|
|
{ decisionDate: '2026-02-01' },
|
|
{ decisionIssuer: '' },
|
|
{ approvedAmount: '' },
|
|
{ stage: 'preparation' },
|
|
]) {
|
|
const v = structuredClone(b);
|
|
Object.assign(v.rows[0], patch);
|
|
assert.equal(
|
|
recordRefund(d, v).result.rows[0].status,
|
|
'indeterminate',
|
|
JSON.stringify(patch),
|
|
);
|
|
}
|
|
const forged = structuredClone(b);
|
|
forged.rows[0].source.requested = { numerator: '700000', denominator: '1' };
|
|
assert.equal(recordRefund(d, forged).result.rows[0].requested, null);
|
|
});
|
|
void test('a documented external decision is recorded without turning an unimplemented/unknown basis into a new approval gate', () => {
|
|
const { d, b } = fixture();
|
|
for (const patch of [
|
|
{ ground: '' },
|
|
{ factsConfirmed: '' },
|
|
{ oldestFirst: '' },
|
|
{ entitlementDate: '' },
|
|
{ groundRef: '' },
|
|
]) {
|
|
const v = structuredClone(b);
|
|
Object.assign(v.rows[0], patch);
|
|
const r = recordRefund(d, v).result.rows[0];
|
|
assert.equal(r.status, 'determined', r.reason);
|
|
assert.equal(r.eligibility, 'not_demonstrated');
|
|
assert.equal(n(r.approved), '550000/1');
|
|
assert.equal(n(r.received), '450000/1');
|
|
v.rows[0].decision = 'pending';
|
|
v.rows[0].receipts = [];
|
|
const pending = recordRefund(d, v).result.rows[0];
|
|
assert.equal(pending.status, 'indeterminate');
|
|
assert.equal(pending.approved, null);
|
|
}
|
|
});
|
|
void test('current four-month/high-credit conditions and ten-year limit are applied without obsolete50percent rule', () => {
|
|
const { d, b } = fixture();
|
|
const v = structuredClone(b);
|
|
Object.assign(v.rows[0], {
|
|
ground: 'four_months',
|
|
originPeriod: '2025-09',
|
|
entitlementDate: '2025-09-10',
|
|
});
|
|
assert.equal(recordRefund(d, v).result.rows[0].eligibility, 'compatible');
|
|
v.rows[0].originPeriod = '2025-10';
|
|
v.rows[0].entitlementDate = '2025-10-10';
|
|
assert.equal(recordRefund(d, v).result.rows[0].eligibility, 'incompatible');
|
|
v.rows[0].originPeriod = '2015-01';
|
|
v.rows[0].entitlementDate = '2015-01-10';
|
|
assert.equal(recordRefund(d, v).result.rows[0].eligibility, 'incompatible');
|
|
const cessation = structuredClone(b);
|
|
Object.assign(cessation.rows[0], {
|
|
ground: 'cessation',
|
|
cessationDate: '2026-01-31',
|
|
});
|
|
assert.equal(
|
|
recordRefund(d, cessation).result.rows[0].eligibility,
|
|
'compatible',
|
|
);
|
|
cessation.rows[0].cessationDate = '2026-03-01';
|
|
assert.equal(
|
|
recordRefund(d, cessation).result.rows[0].eligibility,
|
|
'incompatible',
|
|
);
|
|
});
|
|
void test('thresholds are strictly greater;fractional credit remains exact after allocation', () => {
|
|
for (const [vat, request, ground, expected] of [
|
|
['500160', '100000', 'high_credit', 'incompatible'],
|
|
['100160', '50000', 'four_months', 'incompatible'],
|
|
['500161', '100000', 'high_credit', 'compatible'],
|
|
]) {
|
|
const { d, b } = fixture(),
|
|
acq = acquisitionBook(d);
|
|
acq.rows[0].vat = vat;
|
|
acq.rows[0].gross = String(Number(acq.rows[0].net) + Number(vat));
|
|
d.modelo_a_snapshot = saveAcquisitionBook(
|
|
d,
|
|
recordAcquisitions(d, acq),
|
|
);
|
|
const ab = closureBook(d);
|
|
ab.rows[0].source = closureSources(d)
|
|
.filter((s) => s.period === '2026-01')
|
|
.at(-1);
|
|
ab.rows[0].refundAmount = request;
|
|
d.modelo_a_snapshot = saveClosureBook(d, recordClosure(d, ab));
|
|
Object.assign(b.rows[0], {
|
|
source: refundSources(d)[0],
|
|
ground,
|
|
originPeriod: '2025-09',
|
|
entitlementDate: '2025-09-10',
|
|
stage: 'preparation',
|
|
decision: 'pending',
|
|
receipts: [],
|
|
});
|
|
assert.equal(recordRefund(d, b).result.rows[0].eligibility, expected);
|
|
}
|
|
const { d } = fixture(),
|
|
acq = acquisitionBook(d);
|
|
acq.rows[0].vat = '800161';
|
|
acq.rows[0].gross = '5801161';
|
|
acq.rows[0].d.numerator = '1';
|
|
acq.rows[0].d.denominator = '3';
|
|
d.modelo_a_snapshot = saveAcquisitionBook(d, recordAcquisitions(d, acq));
|
|
const ab = closureBook(d);
|
|
ab.rows[0].source = closureSources(d)
|
|
.filter((s) => s.period === '2026-01')
|
|
.at(-1);
|
|
ab.rows[0].refundAmount = '200000';
|
|
const result = recordClosure(d, ab);
|
|
assert.equal(n(result.result.rows[0].fields['25']), '799681/3');
|
|
assert.equal(n(result.result.rows[0].fields['26']), '199681/3');
|
|
assert.equal(n(result.result.rows[0].fields['27']), '200000/1');
|
|
});
|
|
void test('request/receipt duplication,over-receipt and decisions beyond request are refused', () => {
|
|
const { d, b } = fixture();
|
|
const copy = structuredClone(b);
|
|
copy.rows.push({ ...structuredClone(copy.rows[0]), id: 'copy' });
|
|
assert.ok(
|
|
recordRefund(d, copy).result.rows.every((r) => r.requested === null),
|
|
);
|
|
for (const patch of [
|
|
{ approvedAmount: '600001' },
|
|
{ decision: 'approved', approvedAmount: '550000' },
|
|
{ decision: 'rejected', approvedAmount: '1' },
|
|
{ decision: 'pending' },
|
|
]) {
|
|
const v = structuredClone(b);
|
|
Object.assign(v.rows[0], patch);
|
|
assert.equal(recordRefund(d, v).result.rows[0].status, 'indeterminate');
|
|
}
|
|
const receipt = structuredClone(b);
|
|
receipt.rows[0].receipts.push({
|
|
...receipt.rows[0].receipts[0],
|
|
id: 'copy',
|
|
});
|
|
assert.equal(recordRefund(d, receipt).result.rows[0].received, null);
|
|
const over = structuredClone(b);
|
|
over.rows[0].receipts[0].amount = '400000';
|
|
assert.equal(recordRefund(d, over).result.rows[0].status, 'indeterminate');
|
|
});
|
|
void test('submitted refund locks the allocation even after current preparation is removed;histories are not erased', () => {
|
|
const { d, b } = fixture();
|
|
const book = recordRefund(d, b);
|
|
d.modelo_a_snapshot = saveRefundBook(d, book);
|
|
const ab = closureBook(d);
|
|
ab.rows[0].destination = 'report';
|
|
assert.match(recordClosure(d, ab).result.rows[0].reason, /Crédito ligado/);
|
|
const removed = recordRefund(d, { ...book, rows: [] });
|
|
d.modelo_a_snapshot = saveRefundBook(d, removed);
|
|
assert.match(recordClosure(d, ab).result.rows[0].reason, /Crédito ligado/);
|
|
assert.ok(removed.history.length);
|
|
});
|
|
void test('only residual26 travels to next month;old whole-credit carry requires explicit adoption', () => {
|
|
const { d, b } = fixture();
|
|
let ab = closureBook(d);
|
|
const full = structuredClone(ab);
|
|
full.rows[0].destination = 'report';
|
|
const before = recordClosure(d, full);
|
|
const feb = {
|
|
...newClosure(
|
|
'refund-Feb',
|
|
closureSources(d).find((s) => s.period === '2026-02'),
|
|
'SYNTHETIC QA entidade374',
|
|
),
|
|
firstDeclaration: 'yes',
|
|
filing: 'timely',
|
|
submissionDate: '2026-03-15',
|
|
filingRef: 'SYNTHETIC QA prazo',
|
|
creditsComplete: 'yes',
|
|
interest: 'none',
|
|
interestRef: 'SYNTHETIC QA sem juros',
|
|
destination: 'report',
|
|
credits: [
|
|
adoptPreviousCredit(
|
|
newClosureCredit('carry', 'previous'),
|
|
before.result.rows[0],
|
|
),
|
|
],
|
|
};
|
|
ab = recordClosure(d, { ...ab, rows: [...ab.rows, feb] });
|
|
assert.equal(ab.result.rows[1].status, 'indeterminate');
|
|
d.modelo_a_snapshot = saveClosureBook(d, ab);
|
|
assert.deepEqual(refundSources(d), []);
|
|
ab.rows[1].credits[0] = adoptPreviousCredit(
|
|
ab.rows[1].credits[0],
|
|
ab.result.rows[0],
|
|
);
|
|
ab = recordClosure(d, ab);
|
|
assert.equal(n(ab.result.rows[1].fields['19']), '200000/1');
|
|
assert.equal(n(ab.result.rows[1].fields['26']), '199920/1');
|
|
d.modelo_a_snapshot = saveClosureBook(d, ab);
|
|
assert.equal(recordRefund(d, b).result.rows[0].status, 'determined');
|
|
});
|
|
void test('effective carry already used in a later declaration cannot be reallocated retroactively for a refund', () => {
|
|
const { d } = fixture(),
|
|
acq = acquisitionBook(d);
|
|
acq.rows[0].origin = 'effective';
|
|
d.modelo_a_snapshot = saveAcquisitionBook(d, recordAcquisitions(d, acq));
|
|
let ab = closureBook(d);
|
|
Object.assign(ab.rows[0], {
|
|
origin: 'effective',
|
|
source: closureSources(d)
|
|
.filter((s) => s.period === '2026-01')
|
|
.at(-1),
|
|
destination: 'report',
|
|
});
|
|
ab = recordClosure(d, ab);
|
|
assert.equal(ab.result.rows[0].status, 'determined');
|
|
const feb = {
|
|
...structuredClone(ab.rows[0]),
|
|
id: 'actual-Feb',
|
|
period: '2026-02',
|
|
source: closureSources(d)
|
|
.filter((s) => s.period === '2026-02')
|
|
.at(-1),
|
|
submissionDate: '2026-03-15',
|
|
credits: [
|
|
adoptPreviousCredit(
|
|
newClosureCredit('actual-carry', 'previous'),
|
|
ab.result.rows[0],
|
|
),
|
|
],
|
|
};
|
|
ab = recordClosure(d, { ...ab, rows: [...ab.rows, feb] });
|
|
assert.equal(ab.result.rows[1].status, 'determined');
|
|
d.modelo_a_snapshot = saveClosureBook(d, ab);
|
|
ab.rows[0].destination = 'refund';
|
|
ab.rows[0].refundAmount = '600000';
|
|
const changed = recordClosure(d, ab);
|
|
assert.match(
|
|
changed.result.rows[0].reason,
|
|
/Reporte efectivo já utilizado/,
|
|
);
|
|
assert.equal(changed.result.rows[0].status, 'indeterminate');
|
|
});
|
|
void test('unsubmitted allocation may be changed explicitly,but old reported credit cannot fund the old request', () => {
|
|
const { d, b } = fixture();
|
|
b.rows[0].stage = 'preparation';
|
|
b.rows[0].decision = 'pending';
|
|
b.rows[0].receipts = [];
|
|
let book = recordRefund(d, b);
|
|
d.modelo_a_snapshot = saveRefundBook(d, book);
|
|
const ab = closureBook(d);
|
|
ab.rows[0].destination = 'report';
|
|
d.modelo_a_snapshot = saveClosureBook(d, recordClosure(d, ab));
|
|
assert.equal(refundCurrent(d, book), false);
|
|
assert.equal(recordRefund(d, book).result.rows[0].requested, null);
|
|
});
|
|
void test('save/recover preserves all prior L1/L2/AB/C maps and frozen report;recalculation appends history', () => {
|
|
const { d, b } = fixture(),
|
|
before = JSON.parse(d.modelo_a_snapshot);
|
|
let book = recordRefund(d, b);
|
|
d.modelo_a_snapshot = saveRefundBook(d, book);
|
|
const after = JSON.parse(d.modelo_a_snapshot);
|
|
for (const [k, v] of Object.entries(before))
|
|
assert.deepEqual(after[k], v, k);
|
|
assert.ok(refundCurrent(d, refundBook(d)));
|
|
const cDraft = { ...d, context_opportunity: 'opportunity:373' };
|
|
assert.ok(substitutionCurrent(cDraft, substitutionBook(cDraft)));
|
|
assert.ok(closureCurrent(cDraft, closureBook(cDraft)));
|
|
book.rows[0].requestReference = 'deliberate edit';
|
|
assert.equal(refundCurrent(d, book), false);
|
|
d.modelo_a_snapshot = saveRefundBook(d, book);
|
|
assert.doesNotMatch(
|
|
refundReportRows(d)
|
|
.map((r) => r.join(' '))
|
|
.join(' '),
|
|
/deliberate edit/,
|
|
);
|
|
const prior = structuredClone(book.result);
|
|
book = recordRefund(d, book);
|
|
assert.deepEqual(book.history.at(-1), prior);
|
|
});
|
|
void test('export synthetic frozen refund reconciliation for guardedAPI and actual component proof', () => {
|
|
const { d, b } = fixture();
|
|
const first = recordRefund(d, b, '2026-10-25T13:02:00Z'),
|
|
book = recordRefund(d, first, '2026-10-25T13:03:00Z');
|
|
d.modelo_a_snapshot = saveRefundBook(d, book);
|
|
assert.ok(refundCurrent(d, book));
|
|
if (process.env.IVA_L3D_CALCULATED)
|
|
fs.writeFileSync(process.env.IVA_L3D_CALCULATED, JSON.stringify(d));
|
|
});
|