Fix: sonstiges Vermoegen zieht Rate in Verzehrphasen ab statt sie zu addieren
Deploy App / deploy (push) Successful in 1m3s
Deploy App / deploy (push) Successful in 1m3s
Vorlauf berechnet das Quoten-Vorzeichen (Einkommen inkl. Renten minus Ausgaben) vor der Element-Schleife; in Verzehrphasen (Quote < 0) wird die Jahresrate beim sonstigen Vermoegen als Bezug (negativ) statt als Sparbeitrag verrechnet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+35
-4
@@ -187,13 +187,42 @@ export function computePlan(plan: PlanInput): PlanComputed {
|
||||
}
|
||||
|
||||
// --- Elemente dieser Phase berechnen ---
|
||||
const orderedElements = [...plan.elements].sort((a, b) => a.orderIndex - b.orderIndex);
|
||||
|
||||
// --- Vorlauf: Quoten-Vorzeichen bestimmen (Einkommen inkl. Renten minus Ausgaben) ---
|
||||
// Wird VOR der Element-Schleife gebraucht, damit sonstiges Vermoegen in Verzehrphasen
|
||||
// die Rate abzieht (Bezug) statt sie zu addieren (Sparen).
|
||||
let preIncome = 0;
|
||||
let preExpense = 0;
|
||||
for (const e of orderedElements) {
|
||||
const carry = carries.get(e.id)!;
|
||||
if (carry.status !== "ACTIVE") continue;
|
||||
const pd = e.phaseValues[phase.id] ?? {};
|
||||
const owner = e.ownerRole && e.ownerRole !== "HOUSEHOLD" ? personByRole(persons, e.ownerRole) : null;
|
||||
const ownerWorking = owner ? workingByPerson.get(owner.id) ?? false : anyWorking;
|
||||
switch (e.category) {
|
||||
case "INCOME":
|
||||
preIncome += Math.round(num(pd.amount));
|
||||
break;
|
||||
case "EXPENSE":
|
||||
preExpense += Math.round(num(pd.amount));
|
||||
break;
|
||||
case "AHV":
|
||||
if (owner && !ownerWorking) preIncome += ahvFinal.get(owner.id) ?? 0;
|
||||
break;
|
||||
case "PENSION_FUND":
|
||||
if (!ownerWorking && carry.pkPensionAnnual > 0) preIncome += carry.pkPensionAnnual;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const isConsumptionPhase = preIncome - preExpense < 0;
|
||||
|
||||
const elementsComputed: ElementPhaseComputed[] = [];
|
||||
let incomeTotal = 0;
|
||||
let expenseTotal = 0;
|
||||
let quotaAllocated = 0;
|
||||
let capitalUsed = 0;
|
||||
|
||||
const orderedElements = [...plan.elements].sort((a, b) => a.orderIndex - b.orderIndex);
|
||||
for (const e of orderedElements) {
|
||||
const carry = carries.get(e.id)!;
|
||||
const pd = e.phaseValues[phase.id] ?? {};
|
||||
@@ -312,11 +341,13 @@ export function computePlan(plan: PlanInput): PlanComputed {
|
||||
ec.startValue = start;
|
||||
ec.capitalUse = topUp;
|
||||
capitalUsed += topUp;
|
||||
// In Erwerbsphasen Sparbeitrag, in Verzehrphasen Bezugsrate -- beides zaehlt gegen
|
||||
// die Quote (Vorzeichen ergibt sich aus der Phasenquote).
|
||||
// In Erwerbsphasen Sparbeitrag (wird eingezahlt/waechst), in Verzehrphasen
|
||||
// Bezugsrate (wird entnommen/mindert das Vermoegen). Beides zaehlt betragsmaessig
|
||||
// gegen die Quote.
|
||||
ec.quotaUse = contribution;
|
||||
quotaAllocated += contribution;
|
||||
ec.endValue = growAsset(start, r, contribution, phase.durationYears);
|
||||
const annual = isConsumptionPhase ? -contribution : contribution;
|
||||
ec.endValue = growAsset(start, r, annual, phase.durationYears);
|
||||
ec.summary = fmt(ec.endValue);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user