161 lines
6.5 KiB
JavaScript
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/,
|
|
);
|
|
});
|