money: rent detection matches whole words ("living with parents" is not the rent)
Some checks failed
Deploy production / deploy (push) Failing after 1m6s

The scenario move date came from the first Joint item matching /rent|huur/,
which since the "Groceries (living with parents)" item matched that one, so
the scenarios never moved out (no rent, the pre-move contribution forever).
This commit is contained in:
2026-10-26 01:20:32 +00:00
parent 807a6b3104
commit d5e2ec346b
2 changed files with 13 additions and 2 deletions

View File

@@ -26,6 +26,13 @@ const inputs = scenarioInputs({
{ name: 'Cargill salary', amountCents: 300000, cadence: 'monthly', accountId: 1 }, { name: 'Cargill salary', amountCents: 300000, cadence: 'monthly', accountId: 1 },
{ name: 'Gym', amountCents: -3000, cadence: 'monthly', accountId: 1 }, { name: 'Gym', amountCents: -3000, cadence: 'monthly', accountId: 1 },
{ name: 'Benefit', amountCents: 10000, cadence: 'monthly', accountId: 1, endsOn: '2026-12-31' }, { name: 'Benefit', amountCents: 10000, cadence: 'monthly', accountId: 1, endsOn: '2026-12-31' },
{
name: 'Groceries (living with parents)',
amountCents: -5000,
cadence: 'monthly',
accountId: 4,
endsOn: '2026-12-31'
},
{ {
name: 'Rent + utilities (estimate)', name: 'Rent + utilities (estimate)',
amountCents: -180000, amountCents: -180000,
@@ -51,7 +58,10 @@ describe('scenarioInputs', () => {
expect(inputs.investedCents).toBe(50000); expect(inputs.investedCents).toBe(50000);
expect(inputs.netSalaryCents).toBe(300000); expect(inputs.netSalaryCents).toBe(300000);
expect(inputs.personal.map((item) => item.name)).toEqual(['Gym', 'Benefit']); expect(inputs.personal.map((item) => item.name)).toEqual(['Gym', 'Benefit']);
expect(inputs.household.map((item) => item.name)).toEqual(['Rent + utilities (estimate)']); expect(inputs.household.map((item) => item.name)).toEqual([
'Groceries (living with parents)',
'Rent + utilities (estimate)'
]);
expect(inputs.moveDate).toBe('2027-03-01'); expect(inputs.moveDate).toBe('2027-03-01');
// Salary extras are modelled by the scenarios, other one-offs pass through. // Salary extras are modelled by the scenarios, other one-offs pass through.
expect(inputs.oneOffs.map((item) => item.description)).toEqual(['Side job']); expect(inputs.oneOffs.map((item) => item.description)).toEqual(['Side job']);

View File

@@ -350,7 +350,8 @@ export function scenarioInputs(input: {
const isJoint = (item: ScenarioRecurring) => const isJoint = (item: ScenarioRecurring) =>
item.accountId !== null && jointIds.has(item.accountId); item.accountId !== null && jointIds.has(item.accountId);
const household = recurring.filter((item) => isJoint(item) && item.amountCents < 0); const household = recurring.filter((item) => isJoint(item) && item.amountCents < 0);
const rent = household.find((item) => /rent|huur/i.test(item.name)); // Whole words: "Groceries (living with parents)" is not the rent.
const rent = household.find((item) => /\b(rent|huur)\b/i.test(item.name));
const oneOffs = [...input.forecasts, ...input.futureTransactions] const oneOffs = [...input.forecasts, ...input.futureTransactions]
.filter( .filter(
(item) => (item) =>