Cash-Anfangswert (erste Lebensphase) editierbar
Deploy App / deploy (push) Successful in 1m44s

Neues Feld Plan.initialCash (additiv, Default 0). computePlan startet die erste Phase
mit diesem Cash-Bestand statt 0. In der Matrix ist die Cash-Zelle der ersten Phase
klickbar und oeffnet ein Popup zum Setzen des Anfangswerts (PATCH /api/plans/{id}).
Szenario-Kopie uebernimmt den Wert. Golden-Test ergaenzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 12:48:02 +02:00
parent 7222faa98c
commit 249debe2f4
9 changed files with 85 additions and 10 deletions
+18
View File
@@ -20,6 +20,7 @@ function plan(opts: {
age: number;
retirementAge: number;
inflation?: number;
initialCash?: number;
phases: { id: string; durationYears: number }[];
elements: ReturnType<typeof el>[];
household?: "SINGLE" | "COUPLE";
@@ -29,6 +30,7 @@ function plan(opts: {
name: "T",
householdType: opts.household ?? "SINGLE",
inflationRateDefault: opts.inflation ?? 2,
initialCash: opts.initialCash ?? 0,
persons: [{ id: "A", role: "PERSON_A", name: null, age: opts.age, retirementAge: opts.retirementAge }],
phases: opts.phases.map((p, i) => ({ id: p.id, sequenceNumber: i + 1, name: p.id, durationYears: p.durationYears, inflationRate: null })),
elements: opts.elements,
@@ -103,6 +105,22 @@ describe("V4 Golden Tests", () => {
expect(ph.cashNegative).toBe(true);
});
it("Cash-Anfangswert fliesst in die erste Phase ein", () => {
const p = plan({
age: 40,
retirementAge: 60,
initialCash: 50000,
phases: [{ id: "p1", durationYears: 3 }],
elements: [
el("INCOME", "PERSON_A", { p1: { amount: 100000, teuerungsausgleich: 0 } }),
el("EXPENSE", "HOUSEHOLD", { p1: { amount: 100000, teuerungsausgleich: 0 } }),
],
});
const ph = computePlan(p).phases[0];
expect(ph.cashStart).toBe(50000);
expect(ph.cashEnd).toBe(50000); // Quote 0, keine Raten -> Cash unveraendert
});
it("indexRate 0 -> Einkommen bleibt nominal flach", () => {
const p = plan({
age: 40,