Modul-Review 4: Matrix -- Kapitalverwendung, Phasendauer, Bedienung
Deploy App / deploy (push) Successful in 1m10s
Deploy App / deploy (push) Successful in 1m10s
Kapitalverwendung (Punkt C) am richtigen Ort: - Prozent-Aufteilung des bezogenen Alterskapitals wandert vom Cash-Uebergang zum Bezugs-Entscheid der PK (nur bei Kapitalbezug) bzw. der Saeule 3a -- mit zwei Guthaben liess sie sich vorher gar nicht getrennt beantworten - Dialoge fuehren neu brutto -> Steuersatz -> netto -> Verteilung - BUGFIX: Der zugeteilte Betrag erhoehte still den internen Bestand, deshalb zeigten Ziel-Element und "Kapital verteilen" eine 0. Er laeuft jetzt ueber Carry.capitalIn als Zusatzeinlage der Folgephase und ist ueberall sichtbar - Saeule 3a ist am Pensions-Uebergang neu ein offener Entscheid Phasendauer (gemeldeter Fehler): - Die Folgephase gleicht eine geaenderte Dauer aus; Gesamtdauer bleibt gleich - Vorher kappte das Tool nur die bearbeitete Phase -> Phase 2 ueberspannte danach die Pensionierung und die Invariante aus Punkt 44 kippte - Rueckfrage vorher, Blockade wenn die Folgephase unter 1 Jahr fiele - neue reine Funktion planDurationChange Bedienung: - Element-Zeile und Phasenkopf: Stift (umbenennen, beim Element inkl. Zuordnung), Papierkorb, Expand -- alle immer sichtbar - PATCH /api/elements/<id> nimmt neu auch ownerRole - Hilfetexte via Portal (wurden in scrollenden Dialogen abgeschnitten) - Verteil-Dialoge: Zuordnung je Zeile, nach vom/ins Cash gruppiert, Vorbelegung mit dem EFFEKTIVEN Wert inkl. Vererbung (zeigte vorher 0) - Matrix: gleiche Spaltenbreiten + horizontales Scrollen, "Alle auf-/ zuklappen", Kategorie-Summe in der zugeklappten Zeile - Phasen-Detailansicht nutzt die neue Aufteilungs-Grafik - Uebersicht: "Leer starten" auch im leeren Zustand Nebenbei: dritte verstuemmelte Hex-Farbe (#7c3aed) repariert, Phasen-Panel nutzt den eigenen Bestaetigungs-Dialog statt window.confirm; mehrere veraltete Referenzen und die buildCarryData-Tabelle in der Spez nachgezogen. SPEZIFIKATION 0.33. 278 -> 288 Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,3 +48,66 @@ export function defaultOpenDuration(persons: { age: number }[], fromYear: number
|
||||
const oldestNow = persons.length > 0 ? Math.max(...persons.map((p) => p.age)) : 65;
|
||||
return Math.max(5, 90 - (oldestNow + fromYear));
|
||||
}
|
||||
|
||||
// --- Phasendauer ändern: die Folgephase gleicht aus --------------------------------------
|
||||
//
|
||||
// Wird eine Phase verlängert, muss die NÄCHSTE um denselben Betrag kürzer werden -- sonst
|
||||
// verschieben sich alle folgenden Phasengrenzen, und eine davon überspannt am Ende eine
|
||||
// Pensionierung. Genau das passierte bis 0.32: Die Kappung prüfte nur die BEARBEITETE Phase
|
||||
// («Phase 1 darf höchstens bis zur Pensionierung laufen»), nicht die Folgen für Phase 2.
|
||||
//
|
||||
// Dieselbe Mechanik wie beim Verschieben des Pensionsalters (lib/retirement.ts): Die
|
||||
// Gesamtdauer des Plans bleibt gleich, es wird nur Zeit umverteilt. Nur die LETZTE Phase hat
|
||||
// keine Nachfolgerin -- sie verlängert oder verkürzt den Plan tatsächlich.
|
||||
|
||||
export interface DurationChange {
|
||||
ok: boolean;
|
||||
// Die Folgephase, die den Ausgleich trägt (null bei der letzten Phase).
|
||||
neighbourId: string | null;
|
||||
neighbourName: string | null;
|
||||
neighbourNewDuration: number | null;
|
||||
delta: number; // Änderung der bearbeiteten Phase in Jahren
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export function planDurationChange(
|
||||
phases: { id: string; name: string; sequenceNumber: number; durationYears: number }[],
|
||||
phaseId: string,
|
||||
newDuration: number
|
||||
): DurationChange {
|
||||
const sorted = [...phases].sort((a, b) => a.sequenceNumber - b.sequenceNumber);
|
||||
const i = sorted.findIndex((p) => p.id === phaseId);
|
||||
const none: DurationChange = {
|
||||
ok: false, neighbourId: null, neighbourName: null, neighbourNewDuration: null, delta: 0, error: null,
|
||||
};
|
||||
if (i < 0) return { ...none, error: "Diese Lebensphase gibt es nicht." };
|
||||
|
||||
const delta = Math.round(newDuration) - sorted[i].durationYears;
|
||||
if (newDuration < 1) return { ...none, delta, error: "Eine Lebensphase muss mindestens ein Jahr dauern." };
|
||||
if (delta === 0) return { ...none, ok: true };
|
||||
|
||||
const next = sorted[i + 1];
|
||||
// Letzte Phase: kein Ausgleich nötig, der Plan wird einfach länger oder kürzer.
|
||||
if (!next) return { ...none, ok: true, delta };
|
||||
|
||||
const neighbourNewDuration = next.durationYears - delta;
|
||||
if (neighbourNewDuration < 1) {
|
||||
return {
|
||||
...none,
|
||||
delta,
|
||||
error:
|
||||
`«${next.name}» dauert nur ${next.durationYears} Jahr${next.durationYears === 1 ? "" : "e"} und müsste den ` +
|
||||
`Ausgleich tragen. Verlängere diese Phase um höchstens ${next.durationYears - 1} Jahr` +
|
||||
`${next.durationYears - 1 === 1 ? "" : "e"} – oder passe zuerst die Folgephase an.`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
neighbourId: next.id,
|
||||
neighbourName: next.name,
|
||||
neighbourNewDuration,
|
||||
delta,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user