Stammdaten gewinnen in Phase 1, Bestaetigung je Zeile statt pauschal
Deploy App / deploy (push) Successful in 1m10s
Deploy App / deploy (push) Successful in 1m10s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// «Ein Wert, ein Ort» -- durchgesetzt im Rechenkern, nicht nur in der Oberfläche
|
||||
// (SPEZIFIKATION 3.14.3).
|
||||
//
|
||||
// Der Bestand bei Planbeginn gehört in die Stammdaten. In der ersten Phase stand dafür bis
|
||||
// 0.39 zusätzlich ein Eingabefeld; eine dort gespeicherte Zahl überschattete die Stammdaten
|
||||
// still. Seit 0.40 ist das Feld read-only -- womit so ein Altwert unerreichbar WÄRE, wenn er
|
||||
// weiterhin gewönne. Deshalb entscheidet die Regel der Rechenkern.
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { computePlan, firstPhaseValues } from "@/lib/calculations";
|
||||
import type { PlanInput } from "@/lib/types";
|
||||
|
||||
function plan(elements: PlanInput["elements"]): PlanInput {
|
||||
return {
|
||||
id: "plan",
|
||||
name: "T",
|
||||
householdType: "SINGLE",
|
||||
inflationRateDefault: 0,
|
||||
initialCash: 0,
|
||||
startYear: 2026,
|
||||
persons: [{ id: "A", role: "PERSON_A", name: null, age: 40, retirementAge: 65 }],
|
||||
phases: [{ id: "p1", sequenceNumber: 1, name: "P1", durationYears: 10, cashTransition: { mode: "NONE" } }],
|
||||
elements,
|
||||
};
|
||||
}
|
||||
|
||||
function haus(phaseValues: Record<string, Record<string, unknown>>) {
|
||||
return [
|
||||
{
|
||||
id: "e1",
|
||||
category: "REAL_ESTATE" as never,
|
||||
name: "Haus",
|
||||
ownerRole: "HOUSEHOLD" as never,
|
||||
orderIndex: 1,
|
||||
baseData: { purchasePrice: 800000, mortgage: 500000 } as Record<string, number>,
|
||||
phaseValues: phaseValues as never,
|
||||
transitionValues: {},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
describe("Bestandsfelder in der ersten Phase", () => {
|
||||
it("nimmt den Bestand aus den Stammdaten", () => {
|
||||
const c = computePlan(plan(haus({})));
|
||||
expect(c.phases[0].elements[0].startValue).toBe(300000);
|
||||
});
|
||||
|
||||
it("lässt sich von einem Phasenwert NICHT überschatten", () => {
|
||||
// Genau der Fall aus der Testrunde: In 0.39 schrieb das Speichern der Zelle eine 0 --
|
||||
// seither stand das Haus mit Startwert 0 da, ohne dass man es noch korrigieren konnte.
|
||||
const c = computePlan(plan(haus({ p1: { confirmed: true, purchasePrice: 0, mortgage: 0 } })));
|
||||
expect(c.phases[0].elements[0].startValue).toBe(300000);
|
||||
});
|
||||
|
||||
it("fällt auf den Phasenwert zurück, solange die Stammdaten leer sind", () => {
|
||||
// Ohne diesen Rückfall wären Pläne aus der Zeit vor den Stammdaten schlagartig auf 0.
|
||||
const els = haus({ p1: { purchasePrice: 600000, mortgage: 400000 } });
|
||||
els[0].baseData = {};
|
||||
expect(computePlan(plan(els)).phases[0].elements[0].startValue).toBe(200000);
|
||||
});
|
||||
|
||||
it("lässt die ANNAHMEN in der ersten Phase überschreibbar", () => {
|
||||
// Eine Rendite gilt für einen Zeitraum, kein Anfangsbestand -- sie darf je Phase abweichen.
|
||||
const merged = firstPhaseValues(
|
||||
{ startValue: 100000, expectedReturn: 3 },
|
||||
{ expectedReturn: 7, startValue: 0 }
|
||||
);
|
||||
expect(merged.expectedReturn).toBe(7);
|
||||
expect(merged.startValue).toBe(100000);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user