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

379 lines
14 KiB
JavaScript

import {
normalBook,
recordNormal,
saveNormalBook,
} from '../../resources/js/lib/irpc-normal.ts';
import { carryCase } from './helpers/irpc-carry-case.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { investmentCase } from './helpers/irpc-investment-case.mjs';
import { internationalCase } from './helpers/irpc-international-case.mjs';
import {
reuseAnnualAssessment,
prepareInvestmentCredit,
calculateAnnual,
recordAnnual,
saveAnnualBook,
annualBook,
annualCurrent,
annualHtml,
} from '../../resources/js/lib/irpc-annual-settlement.ts';
import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts';
void test('CBF15 city5percent and other provinces10percent deduct once after international and before PEC/PPC', () => {
const c = investmentCase(),
before = c.d.modelo_a_snapshot,
m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.nominal, {
numerator: '500',
denominator: '1',
});
assert.deepEqual(m.investmentCredit.afterCredit, {
numerator: '900',
denominator: '1',
});
assert.deepEqual(m.arithmeticBalance, {
numerator: '200',
denominator: '1',
});
assert.equal(c.d.modelo_a_snapshot, before);
c.b.investmentCredit.location = 'other';
const other = calculateAnnual(c.d, c.b);
assert.deepEqual(other.investmentCredit.deducted, {
numerator: '1000',
denominator: '1',
});
assert.deepEqual(other.arithmeticBalance, {
numerator: '-300',
denominator: '1',
});
assert.equal(other.investmentCredit.officialBalancesConsumed, false);
});
void test('CBF15 caps at remaining collection and separates unused credit from unrecovered PEC and PPC', () => {
const c = investmentCase();
c.b.investmentCredit.location = 'other';
Object.assign(c.b.investmentCredit.assets[0], {
amount: '40000',
proofAmount: '40000',
});
const m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.deducted, {
numerator: '1400',
denominator: '1',
});
assert.deepEqual(m.investmentCredit.unused, {
numerator: '2600',
denominator: '1',
});
assert.deepEqual(m.pecDeduction.deducted, {
numerator: '0',
denominator: '1',
});
assert.deepEqual(m.recoverable, { numerator: '500', denominator: '1' });
assert.equal(m.investmentCredit.carryCreated, false);
assert.equal(m.refundReceived, false);
});
void test('CBF15 requires actual project,source and first-exercise conditions without treating projected investment as realised', () => {
for (const patch of [
{ location: '' },
{ locationReference: '' },
{ cbfRequirements: '' },
{ recognitionReference: '' },
{ genericOnly: '' },
{ soleProject: '' },
{ noOtherBenefits: 'no' },
{ assessmentKey: 'stale' },
{ startDate: '2027-01-01' },
]) {
const c = investmentCase();
Object.assign(c.b.investmentCredit, patch);
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
}
const c = investmentCase();
c.b.investmentCredit.assets[0].realised = '';
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
});
void test('documented excluded,used,foreign or unrealised assets keep their inputs but receive zero credit', () => {
for (const patch of [
{ excluded15_6: 'yes' },
{ newTangible: 'no' },
{ domesticUse: 'no' },
{ realised: 'no' },
]) {
const c = investmentCase();
Object.assign(c.b.investmentCredit.assets[0], patch);
const m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.nominal, {
numerator: '0',
denominator: '1',
});
assert.deepEqual(m.arithmeticBalance, {
numerator: '700',
denominator: '1',
});
assert.equal(m.investmentCredit.rows[0].input.amount, '10000');
}
});
void test('source identity cannot be duplicated by a new id/date; supported parcels share one invoice capacity', () => {
const c = investmentCase(),
r = c.b.investmentCredit.assets[0];
c.b.investmentCredit.assets.push({ ...r, id: 'copy', date: '2026-05-02' });
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
const p = investmentCase(),
a = p.b.investmentCredit.assets[0];
a.amount = '6000';
p.b.investmentCredit.assets.push({ ...a, id: 'line2', parcel: 'machine2' });
assert.equal(calculateAnnual(p.d, p.b).arithmeticBalance, null);
a.amount = '4000';
assert.deepEqual(calculateAnnual(p.d, p.b).pending, []);
});
void test('CBF15 detects another map using the same project or actual investment,including split invoice capacity', () => {
const c = investmentCase(),
other = structuredClone(c.b);
other.investmentCredit.projectReference = 'OTHER-SYNTHETIC-PROJECT';
other.investmentCredit.assets[0].parcel = 'OTHER-LINE';
other.investmentCredit.assets[0].amount = '6000';
c.b.investmentCredit.assets[0].amount = '6000';
const root = JSON.parse(c.d.modelo_a_snapshot);
root.irpcAnnual = { ...root.irpcAnnual, other };
const d = { ...c.d, modelo_a_snapshot: JSON.stringify(root) };
assert.ok(
calculateAnnual(d, c.b).pending.some((e) =>
e.includes('ultrapassa o documento efectivo'),
),
);
});
void test('actual previous credit use is distinct from calculating or saving the same scenario again', () => {
const c = investmentCase();
c.b.investmentCredit.previousUse.amount = '100';
const m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.investmentCredit.deducted, {
numerator: '400',
denominator: '1',
});
assert.deepEqual(
calculateAnnual(c.d, c.b).investmentCredit,
m.investmentCredit,
);
assert.deepEqual(m.arithmeticBalance, {
numerator: '300',
denominator: '1',
});
});
void test('CBF15 calculation-save-recovery-HTML and dossier reports retain sources,history and legacy benefits summary', () => {
const c = investmentCase();
c.b.internationalCredits.benefits = {
state: 'known',
amount: '777',
reference:
'SYNTHETIC earlier deliberate summary retained,not reapplied',
};
const b = recordAnnual(c.d, c.b, '2026-11-10T19:00:00+02:00'),
d = JSON.parse(
JSON.stringify({
...c.d,
modelo_a_snapshot: saveAnnualBook(c.d, b),
}),
),
back = annualBook(d);
assert.equal(annualCurrent(d, back), true);
assert.deepEqual(
calculateAnnual(d, back).investmentCredit,
back.result.model.investmentCredit,
);
assert.equal(back.internationalCredits.benefits.amount, '777');
assert.deepEqual(back.result.model.arithmeticBalance, {
numerator: '200',
denominator: '1',
});
assert.match(annualHtml(d), /IRPC-CBF15\/3/);
assert.match(
JSON.stringify(
createProjectDossierReport(d, {
selectedSections: new Set(['finance']),
generatedAt: '2026-11-10T19:00:00+02:00',
}),
),
/IRPC-CBF15\/3/,
);
const old = internationalCase();
assert.equal(calculateAnnual(old.d, old.b).investmentCredit, undefined);
});
void test('absence of CBF15 cannot silently discard other positive benefits or unknown benefit inventory', () => {
const c = investmentCase();
c.b.investmentCredit.qualification.state = 'absent';
c.b.investmentCredit.qualification.eligible = '';
c.b.internationalCredits.benefits = {
state: 'known',
amount: '777',
reference: 'SYNTHETIC old unspecified positive benefit',
};
c.b.investmentCredit.noOtherBenefits = '';
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
c.b.investmentCredit.noOtherBenefits = 'yes';
assert.deepEqual(calculateAnnual(c.d, c.b).arithmeticBalance, {
numerator: '700',
denominator: '1',
});
assert.equal(c.b.internationalCredits.benefits.amount, '777');
});
void test('CBF15 uses a versioned L8 book while legacy books remain version1 and cannot silently carry the new feature', () => {
const c = investmentCase();
assert.equal(c.b.version, 2);
const old = internationalCase();
assert.equal(old.b.version, 1);
const invalid = structuredClone(c.b);
invalid.version = 1;
assert.throws(() => calculateAnnual(c.d, invalid));
});
void test('adding CBF15 retains the accepted legacy settlement result in history', () => {
const c = investmentCase(),
legacy = recordAnnual(
c.d,
internationalCase().b,
'2026-11-10T18:00:00+02:00',
),
before = structuredClone(legacy.result);
const book = {
...legacy,
version: 2,
investmentCredit: structuredClone(c.b.investmentCredit),
};
const next = recordAnnual(c.d, book, '2026-11-10T19:00:00+02:00'),
d = { ...c.d, modelo_a_snapshot: saveAnnualBook(c.d, next) };
assert.deepEqual(annualBook(d).history.at(-1), before);
assert.deepEqual(annualBook(d).result.model.arithmeticBalance, {
numerator: '200',
denominator: '1',
});
});
void test('first-year ongoing project uses documented investment-procedure start,not new-project exploitation start', () => {
const c = investmentCase();
Object.assign(c.b.investmentCredit, {
startKind: 'existing',
startDate: '2026-04-01',
startReference:
'SYNTHETIC procedures after project approval startedApril2026',
});
assert.deepEqual(calculateAnnual(c.d, c.b).pending, []);
c.b.investmentCredit.startDate = '2026-06-01';
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
});
void test('declared absence of CBF15 preserves the accepted positive prior-credit carry journey', () => {
const c = carryCase(),
before = calculateAnnual(c.d, c.b),
b = prepareInvestmentCredit(c.d, c.b);
Object.assign(b.investmentCredit, {
qualification: {
state: 'absent',
eligible: '',
from: '2026-01-01',
to: '2026-12-31',
reference: 'SYNTHETIC no CBF15 benefit',
periodReference: 'SYNTHETIC current fiscal period',
},
noOtherBenefits: 'yes',
noOtherBenefitsReference: 'SYNTHETIC no other own fiscal benefits',
});
const after = calculateAnnual(c.d, b);
assert.deepEqual(after.pending, []);
assert.deepEqual(after.arithmeticBalance, before.arithmeticBalance);
assert.deepEqual(after.creditCarry, before.creditCarry);
});
void test('documented residual project quota limits CBF15 without allocating income/costs by presumption', () => {
const c = investmentCase();
Object.assign(c.b.investmentCredit, {
soleProject: 'no',
projectQuota: {
amount: '200',
reference:
'SYNTHETIC project residual collecta200 after allocated economic/international credits',
},
});
const m = calculateAnnual(c.d, c.b);
assert.deepEqual(m.pending, []);
assert.deepEqual(m.investmentCredit.deducted, {
numerator: '200',
denominator: '1',
});
assert.deepEqual(m.arithmeticBalance, {
numerator: '500',
denominator: '1',
});
assert.deepEqual(m.investmentCredit.projectCeiling, {
numerator: '200',
denominator: '1',
});
assert.match(m.investmentCredit.source, /QuotaCBF15-project/);
c.b.investmentCredit.projectQuota.amount = '0';
assert.deepEqual(calculateAnnual(c.d, c.b).arithmeticBalance, {
numerator: '700',
denominator: '1',
});
});
void test('project quota requires support and cannot exceed actual collection remaining after credits', () => {
for (const quota of [
{ amount: '200', reference: '' },
{
amount: '1405',
reference: 'SYNTHETIC invalid residual quota above1400',
},
{ amount: '-1', reference: 'SYNTHETIC invalid' },
]) {
const c = investmentCase();
Object.assign(c.b.investmentCredit, {
soleProject: 'no',
projectQuota: quota,
});
assert.equal(calculateAnnual(c.d, c.b).arithmeticBalance, null);
}
});
void test('zero project residual quota preserves the accepted prior-credit journey without applying a competing benefit', () => {
const c = carryCase(),
before = calculateAnnual(c.d, c.b),
b = prepareInvestmentCredit(c.d, c.b),
template = investmentCase().b.investmentCredit;
b.investmentCredit = {
...template,
soleProject: 'no',
projectQuota: {
amount: '0',
reference:
'SYNTHETIC project residual collecta zero after attribution',
},
};
const after = calculateAnnual(c.d, b);
assert.deepEqual(after.pending, []);
assert.deepEqual(after.arithmeticBalance, before.arithmeticBalance);
});
void test('CBF15 does not assume compatibility with an existing positive deduction/benefit in the L6 base', () => {
const c = investmentCase(),
normal = normalBook(c.d);
normal.base.benefits = {
state: 'known',
amount: '100',
reference:
'SYNTHETIC positive base benefit requiring separate cumulation correspondence',
};
const d = {
...c.d,
modelo_a_snapshot: saveNormalBook(
c.d,
recordNormal(c.d, normal, '2026-11-10T19:10:00+02:00'),
),
},
b = reuseAnnualAssessment(d, c.b);
b.investmentCredit.assessmentKey = b.assessmentKey;
const m = calculateAnnual(d, b);
assert.equal(m.arithmeticBalance, null);
assert.ok(m.investmentCredit.pending.length > 0);
});