Fix: Uebergangs-Defaults (Steuer/Umwandlung) wurden in der Berechnung als 0 gerechnet
Deploy App / deploy (push) Successful in 54s
Deploy App / deploy (push) Successful in 54s
Kapitalbezugssteuer, Grundstueckgewinnsteuer und PK-Umwandlungssatz wurden im UI nur optisch vorbelegt (num(td.x, 8/20/6)), die Berechnung las aber num(td.x) mit Fallback 0. Ein nicht angetupftes Feld fuehrte so zu 0% Steuer bzw. 0 Rente. Defaults sind jetzt zentrale Konstanten (constants.ts) und werden in Berechnung UND UI als Fallback genutzt. Betrifft: PK-Kapital/-Kombi/-Rente, 3a-Bezug, Immobilienverkauf. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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") && (
|
||||
<NumberField label="Kapitalbezugssteuer (%)" step={0.5} value={num(td.capitalTaxRate, 8)} onChange={(v) => setT({ capitalTaxRate: v })} />
|
||||
<NumberField label="Kapitalbezugssteuer (%)" step={0.5} value={num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE)} onChange={(v) => setT({ capitalTaxRate: v })} />
|
||||
)}
|
||||
{mode === "COMBI" && (
|
||||
<MoneyField
|
||||
@@ -363,7 +368,7 @@ export function ElementTransitionFields({
|
||||
label="Kapitalbezugssteuer (%)"
|
||||
help="Die Saeule 3a wird bei Pensionierung vollstaendig bezogen."
|
||||
step={0.5}
|
||||
value={num(td.capitalTaxRate, 8)}
|
||||
value={num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE)}
|
||||
onChange={(v) => setT({ capitalTaxRate: v })}
|
||||
/>
|
||||
);
|
||||
@@ -385,7 +390,7 @@ export function ElementTransitionFields({
|
||||
{decision === "SELL" && (
|
||||
<>
|
||||
<MoneyField label="Verkaufspreis (CHF)" value={num(td.salePrice)} onChange={(v) => setT({ salePrice: v })} />
|
||||
<NumberField label="Grundstueckgewinnsteuer (%)" step={1} value={num(td.saleTaxRate, 20)} onChange={(v) => setT({ saleTaxRate: v })} />
|
||||
<NumberField label="Grundstueckgewinnsteuer (%)" step={1} value={num(td.saleTaxRate, DEFAULT_PROPERTY_GAINS_TAX_RATE)} onChange={(v) => setT({ saleTaxRate: v })} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user