diff --git a/src/components/ElementDetail.tsx b/src/components/ElementDetail.tsx index 78342b5..830a766 100644 --- a/src/components/ElementDetail.tsx +++ b/src/components/ElementDetail.tsx @@ -6,7 +6,12 @@ import { FieldLabel, MoneyField, NumberField, SelectField } from "@/components/F import { formatChf } from "@/lib/format"; import { api } from "@/lib/api-client"; import { CATEGORY_LABELS, num } from "@/lib/elements"; -import { PILLAR_3A_MAX_ANNUAL } from "@/lib/constants"; +import { + DEFAULT_CAPITAL_TAX_RATE, + DEFAULT_PK_CONVERSION_RATE, + DEFAULT_PROPERTY_GAINS_TAX_RATE, + PILLAR_3A_MAX_ANNUAL, +} from "@/lib/constants"; import type { ElementCategory, PhaseData, TransitionData } from "@/lib/elements"; export interface CellContext { @@ -336,12 +341,12 @@ export function ElementTransitionFields({ label="Umwandlungssatz (%)" help="Jaehrliche Rente = verrentetes Kapital x Umwandlungssatz." step={0.1} - value={num(td.conversionRate, 6)} + value={num(td.conversionRate, DEFAULT_PK_CONVERSION_RATE)} onChange={(v) => setT({ conversionRate: v })} /> )} {(mode === "CAPITAL" || mode === "COMBI") && ( - setT({ capitalTaxRate: v })} /> + setT({ capitalTaxRate: v })} /> )} {mode === "COMBI" && ( setT({ capitalTaxRate: v })} /> ); @@ -385,7 +390,7 @@ export function ElementTransitionFields({ {decision === "SELL" && ( <> setT({ salePrice: v })} /> - setT({ saleTaxRate: v })} /> + setT({ saleTaxRate: v })} /> )} diff --git a/src/lib/calculations.ts b/src/lib/calculations.ts index 160a302..2ea96f3 100644 --- a/src/lib/calculations.ts +++ b/src/lib/calculations.ts @@ -2,6 +2,9 @@ import { AHV_COUPLE_CAP_FACTOR, AHV_FULL_CONTRIBUTION_YEARS, AHV_MAX_ANNUAL_SINGLE, + DEFAULT_CAPITAL_TAX_RATE, + DEFAULT_PK_CONVERSION_RATE, + DEFAULT_PROPERTY_GAINS_TAX_RATE, } from "@/lib/constants"; import { num } from "@/lib/elements"; import type { ElementCategory } from "@/lib/elements"; @@ -459,18 +462,18 @@ export function computePlan(plan: PlanInput): PlanComputed { const value = ec.endValue; const mode = td.payoutMode ?? "PENSION"; if (mode === "CAPITAL") { - const net = Math.round(value * (1 - num(td.capitalTaxRate) / 100)); + const net = Math.round(value * (1 - num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE) / 100)); outgoing += net; carry.value = 0; carry.pkPensionAnnual = 0; } else if (mode === "PENSION") { - carry.pkPensionAnnual = Math.round((value * num(td.conversionRate)) / 100); + carry.pkPensionAnnual = Math.round((value * num(td.conversionRate, DEFAULT_PK_CONVERSION_RATE)) / 100); carry.value = 0; } else { const capital = Math.min(value, Math.round(num(td.capitalAmount))); - const net = Math.round(capital * (1 - num(td.capitalTaxRate) / 100)); + const net = Math.round(capital * (1 - num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE) / 100)); outgoing += net; - carry.pkPensionAnnual = Math.round(((value - capital) * num(td.conversionRate)) / 100); + carry.pkPensionAnnual = Math.round(((value - capital) * num(td.conversionRate, DEFAULT_PK_CONVERSION_RATE)) / 100); carry.value = 0; } } else { @@ -482,7 +485,7 @@ export function computePlan(plan: PlanInput): PlanComputed { } case "PILLAR_3A": { if (ownerRetiresNext) { - const net = Math.round(ec.endValue * (1 - num(td.capitalTaxRate) / 100)); + const net = Math.round(ec.endValue * (1 - num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE) / 100)); outgoing += net; carry.value = 0; } else { @@ -506,7 +509,7 @@ export function computePlan(plan: PlanInput): PlanComputed { const purchase = Math.round(num(e.phaseValues[phase.id]?.purchasePrice)); const salePrice = Math.round(num(td.salePrice)); const gain = Math.max(0, salePrice - purchase); - const tax = gain * (num(td.saleTaxRate) / 100); + const tax = gain * (num(td.saleTaxRate, DEFAULT_PROPERTY_GAINS_TAX_RATE) / 100); outgoing += Math.round(salePrice - carry.mortgage - tax); carry.status = "SOLD"; } diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 4656b2d..a1c0726 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -13,6 +13,12 @@ export const AHV_COUPLE_CAP_FACTOR = 1.5; // Beitragsjahr (Ausfalljahr) wird die Rente um 1/44 gekuerzt. export const AHV_FULL_CONTRIBUTION_YEARS = 44; -// Maximaler jaehrlicher Saeule-3a-Beitrag fuer PK-Versicherte (2026). Wird in -// 100er-Schritten erfasst (nicht 1'000er wie andere Betraege). +// Maximaler jaehrlicher Saeule-3a-Beitrag fuer PK-Versicherte (2026). export const PILLAR_3A_MAX_ANNUAL = 7258; + +// Default-Annahmen fuer Uebergangs-Ereignisse (pro Ereignis editierbar). Werden SOWOHL als +// UI-Vorschlag als auch in der Berechnung als Fallback verwendet -- damit ein nicht +// angetupfter Wert nicht faelschlich als 0 gerechnet wird. +export const DEFAULT_PK_CONVERSION_RATE = 6; // % (jaehrliche Rente = Kapital x Satz) +export const DEFAULT_CAPITAL_TAX_RATE = 8; // % Kapitalbezugssteuer (PK-/3a-Kapitalbezug) +export const DEFAULT_PROPERTY_GAINS_TAX_RATE = 20; // % Grundstueckgewinnsteuer