Einkommen/Ausgaben: Basiswert direkt editierbar statt Uebersteuern-Feld
Deploy App / deploy (push) Successful in 57s

Das separate "Uebersteuern"-Feld (amountOverride) konnte 0 nicht von "nicht gesetzt"
unterscheiden und nahm faelschlich 0. Entfernt. Stattdessen ist der Basiswert (amount)
selbst editierbar: ab Phase 2 mit dem fortgeschriebenen Endwert der Vorphase vorbelegt,
aber bewusst aenderbar (Teilzeit/Beförderung/Jobwechsel). Solange nicht geaendert, wird
der Wert 1:1 aus der Vorphase fortgeschrieben (pd.amount ungesetzt -> carry.flowBasis).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 13:00:42 +02:00
parent 249debe2f4
commit 5076dcb68f
3 changed files with 17 additions and 22 deletions
+10 -15
View File
@@ -145,23 +145,18 @@ export function ElementPhaseFields({
onChange={(v) => setP({ teuerungsausgleich: v })} onChange={(v) => setP({ teuerungsausgleich: v })}
/> />
); );
if (carried) { // Basiswert (erstes Jahr der Phase). Ab Phase 2 mit dem fortgeschriebenen Endwert der
return ( // Vorphase vorbelegt, aber bewusst aenderbar (Teilzeit, Beförderung, Jobwechsel …).
<> const baseLabel = isIncome ? "Jahreseinkommen (CHF, erstes Jahr)" : "Jahresausgaben (CHF, erstes Jahr)";
<DerivedField label="Basiswert (fortgeschrieben)" value={context.derivedStart} help="Indexierter Wert aus der Vorphase (Jahr 1 dieser Phase)." /> const baseValue = typeof pd.amount === "number" ? pd.amount : carried ? context.derivedStart : 0;
<MoneyField
label="Uebersteuern (optional, CHF)"
help="Setzt den Basiswert dieser Phase neu (z. B. Einkommensknick bei Teilzeit/Fruehpension). Leer = fortgeschrieben."
value={num(pd.amountOverride)}
onChange={(v) => setP({ amountOverride: v })}
/>
{teuerung}
</>
);
}
return ( return (
<> <>
<MoneyField label={isIncome ? "Jahreseinkommen (CHF, erstes Jahr)" : "Jahresausgaben (CHF, erstes Jahr)"} value={num(pd.amount)} onChange={(v) => setP({ amount: v })} /> <MoneyField
label={baseLabel}
help={carried ? "Vorbelegt mit dem fortgeschriebenen Wert der Vorphase; hier bewusst aenderbar." : undefined}
value={baseValue}
onChange={(v) => setP({ amount: v })}
/>
{teuerung} {teuerung}
</> </>
); );
+7 -4
View File
@@ -231,11 +231,14 @@ export function computePlan(plan: PlanInput): PlanComputed {
case "INCOME": case "INCOME":
case "EXPENSE": { case "EXPENSE": {
const idx = num(pd.teuerungsausgleich, phaseInflation); const idx = num(pd.teuerungsausgleich, phaseInflation);
// Basiswert: Phase 1 = eingegebener Betrag; ab Phase 2 = fortgeschriebener Endwert
// der Vorphase, ausser der Nutzer hat ihn bewusst geaendert (pd.amount gesetzt).
ec.baseValue = carry.hasCarry ? Math.round(carry.flowBasis) : Math.round(num(pd.amount)); ec.baseValue = carry.hasCarry ? Math.round(carry.flowBasis) : Math.round(num(pd.amount));
let basis: number; const basis = !carry.hasCarry
if (!carry.hasCarry) basis = Math.round(num(pd.amount)); ? Math.round(num(pd.amount))
else if (typeof pd.amountOverride === "number") basis = Math.round(pd.amountOverride); : typeof pd.amount === "number"
else basis = ec.baseValue; ? Math.round(pd.amount)
: ec.baseValue;
(e.category === "INCOME" ? incomes : expenses).push({ basis, idx, ec }); (e.category === "INCOME" ? incomes : expenses).push({ basis, idx, ec });
break; break;
} }
-3
View File
@@ -56,8 +56,6 @@ export interface PhaseData {
// Phasenjahre (Jahr t = Basis x (1+idx)^(t-1)). Eigenes Feld je Element (Einkommen und // Phasenjahre (Jahr t = Basis x (1+idx)^(t-1)). Eigenes Feld je Element (Einkommen und
// Ausgaben unabhaengig). Default = Phaseninflation. // Ausgaben unabhaengig). Default = Phaseninflation.
teuerungsausgleich?: number; teuerungsausgleich?: number;
// INCOME / EXPENSE ab Phase 2: uebersteuert den fortgeschriebenen Basiswert dieser Phase.
amountOverride?: number;
// AHV // AHV
gapYears?: number; gapYears?: number;
// PENSION_FUND / PILLAR_3A / OTHER_ASSET // PENSION_FUND / PILLAR_3A / OTHER_ASSET
@@ -105,7 +103,6 @@ export const phaseDataSchema = z
.object({ .object({
amount: nonNeg.optional(), amount: nonNeg.optional(),
teuerungsausgleich: z.number().min(-20).max(50).optional(), teuerungsausgleich: z.number().min(-20).max(50).optional(),
amountOverride: nonNeg.optional(),
gapYears: z.number().int().min(0).optional(), gapYears: z.number().int().min(0).optional(),
currentValue: nonNeg.optional(), currentValue: nonNeg.optional(),
startValue: nonNeg.optional(), startValue: nonNeg.optional(),