Files
Investidor-V2/tests/frontend/irpc-investment-carry.test.mjs
T
2026-11-10 16:17:48 +02:00

161 lines
6.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { investmentCase } from './helpers/irpc-investment-case.mjs';
import { investmentCarryCase } from './helpers/irpc-investment-carry-case.mjs';
import {
calculateAnnual,
recordAnnual,
saveAnnualBook,
annualBook,
annualCurrent,
annualHtml,
validateAnnual,
} from '../../resources/js/lib/irpc-annual-settlement.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
const f = (n) => ({ numerator: String(n), denominator: '1' });
void test('CBF15 carries only actual unused original credit:500 less100 used,without requiring a new investment', () => {
const c = investmentCarryCase(),
m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.carryNominal, f(500));
assert.deepEqual(m.investmentCredit.currentNominal, f(0));
assert.deepEqual(m.investmentCredit.available, f(400));
assert.deepEqual(m.investmentCredit.deducted, f(400));
assert.deepEqual(m.arithmeticBalance, f(300));
assert.equal(m.investmentCredit.officialBalancesConsumed, false);
assert.equal(m.investmentCredit.carryCreated, false);
assert.deepEqual(
calculateAnnual(c.d, c.b).investmentCredit,
m.investmentCredit,
);
});
void test('CBF15 combines distinct current and original assets once,with project quota and actual prior use', () => {
const c = investmentCarryCase(),
t = c.b.investmentCredit;
t.carryForward.currentState = 'known';
t.assets.push({
...investmentCase().b.investmentCredit.assets[0],
id: 'current',
document: 'CURRENT2026',
});
let m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.nominal, f(1000));
assert.deepEqual(m.investmentCredit.available, f(900));
assert.deepEqual(m.arithmeticBalance, f(-200));
t.soleProject = 'no';
t.projectQuota = {
amount: '200',
reference: 'SYNTHETIC residual project collecta200',
};
m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.deducted, f(200));
assert.deepEqual(m.investmentCredit.unused, f(700));
});
void test('CBF15 carry expires with the original project window; prior use and source investment remain visible', () => {
const c = investmentCarryCase();
c.b.investmentCredit.startDate = '2021-01-01';
const m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.carryNominal, f(500));
assert.deepEqual(m.investmentCredit.priorUse, f(100));
assert.deepEqual(m.investmentCredit.expired, f(400));
assert.deepEqual(m.investmentCredit.available, f(0));
assert.deepEqual(m.arithmeticBalance, f(700));
assert.equal(m.investmentCredit.input.assets[0].amount, '10000');
});
void test('CBF15 carry requires original exercise,rate,qualification and actual-use reconciliation', () => {
for (const patch of [
{ originNuit: '999999999' },
{ originProject: 'OTHER-PROJECT' },
{ originYear: '' },
{ originYear: '2026' },
{ originYear: '2021' },
{ originYear: '2024' },
{ originRate: '10' },
{ originReference: '' },
]) {
const c = investmentCarryCase();
Object.assign(c.b.investmentCredit.assets[0], patch);
assert.equal(
calculateAnnual(c.d, c.b).arithmeticBalance,
null,
JSON.stringify(patch),
);
}
for (const patch of [
{ useReconciled: '' },
{ reference: '' },
{ currentState: '' },
{ currentState: 'known' },
{ currentReference: '' },
]) {
const c = investmentCarryCase();
Object.assign(c.b.investmentCredit.carryForward, patch);
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
}
const c = investmentCarryCase();
c.b.investmentCredit.previousUse.amount = '501';
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
c.b.investmentCredit.previousUse.amount = '500';
assert.deepEqual(calculateAnnual(c.d, c.b).investmentCredit.deducted, f(0));
});
void test('CBF15 cannot duplicate historical investment through another id/date,another current row or another scope', () => {
const c = investmentCarryCase(),
t = c.b.investmentCredit;
t.assets.push({ ...t.assets[0], id: 'other', date: '2025-06-01' });
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
const d = investmentCarryCase(),
a = d.b.investmentCredit.assets[0];
d.b.investmentCredit.carryForward.currentState = 'known';
const current = { ...a, id: 'fake-current', date: '2026-01-01' };
delete current.originYear;
delete current.originNuit;
delete current.originProject;
delete current.originRate;
delete current.originReference;
d.b.investmentCredit.assets.push(current);
assert.equal(calculateAnnual(d.d, d.b).arithmeticBalance, null);
const e = investmentCarryCase(),
root = JSON.parse(e.d.modelo_a_snapshot);
root.irpcAnnual = { ...root.irpcAnnual, other: structuredClone(e.b) };
assert.equal(
calculateAnnual(
{ ...e.d, modelo_a_snapshot: JSON.stringify(root) },
e.b,
).arithmeticBalance,
null,
);
});
void test('version3 protects carry from older code; legacy books and prior result history are preserved', () => {
const c = investmentCarryCase();
assert.equal(c.b.version, 3);
assert.equal(c.b.investmentCredit.version, 2);
const broken = structuredClone(c.b);
broken.version = 2;
assert.throws(() => validateAnnual(broken));
const b = recordAnnual(c.d, c.b, '2026-11-10T16:00:00Z');
b.investmentCredit.previousUse.amount = '200';
const next = recordAnnual(c.d, b, '2026-11-10T16:01:00Z'),
d = { ...c.d, modelo_a_snapshot: saveAnnualBook(c.d, next) },
back = annualBook(d);
assert.equal(annualCurrent(d, back), true);
assert.deepEqual(back.history[0].model.investmentCredit.deducted, f(400));
assert.deepEqual(
calculateAnnual(d, back).investmentCredit,
back.result.model.investmentCredit,
);
assert.match(annualHtml(d), /TransporteCBF15/);
assert.match(annualHtml(d), /2025/);
assert.match(
JSON.stringify(
createProjectDossierReport(d, {
selectedSections: new Set(['finance']),
generatedAt: '2026-11-10T16:01:00Z',
}),
),
/TransporteCBF15/,
);
});