);
}
diff --git a/src/components/TransitionPanel.tsx b/src/components/TransitionPanel.tsx
index 87aaacd..eb974fa 100644
--- a/src/components/TransitionPanel.tsx
+++ b/src/components/TransitionPanel.tsx
@@ -3,7 +3,7 @@
import { useEffect, useState } from "react";
import { MoneyInput } from "@/components/FormField";
import { api } from "@/lib/api-client";
-import { formatChf } from "@/lib/format";
+import { floorToThousand, formatChf } from "@/lib/format";
import type { PhaseInput, TransitionDecision } from "@/lib/types";
import type { PhaseComputed } from "@/lib/calculations";
@@ -106,19 +106,21 @@ export function TransitionPanel({
);
}
- const totalAvailableCapital = items.reduce((sum, it) => {
- if (it.positionType === "SECURITY") {
+ const totalAvailableCapital = floorToThousand(
+ items.reduce((sum, it) => {
+ if (it.positionType === "SECURITY") {
+ if (it.decision === "CARRY_OVER") return sum;
+ const gain = Math.max(0, it.carryOverValue - it.originalValue);
+ const tax = gain * (it.saleTaxRate / 100);
+ return sum + (it.carryOverValue - tax);
+ }
if (it.decision === "CARRY_OVER") return sum;
- const gain = Math.max(0, it.carryOverValue - it.originalValue);
+ const salePrice = it.salePrice ?? 0;
+ const gain = Math.max(0, salePrice - it.originalValue);
const tax = gain * (it.saleTaxRate / 100);
- return sum + (it.carryOverValue - tax);
- }
- if (it.decision === "CARRY_OVER") return sum;
- const salePrice = it.salePrice ?? 0;
- const gain = Math.max(0, salePrice - it.originalValue);
- const tax = gain * (it.saleTaxRate / 100);
- return sum + (salePrice - tax);
- }, 0);
+ return sum + (salePrice - tax);
+ }, 0)
+ );
async function handleSave() {
setSaving(true);
@@ -181,7 +183,7 @@ export function TransitionPanel({
{it.positionType === "REAL_ESTATE" && it.decision === "SELL" ? (
setItems((prev) => prev.map((x, idx) => (idx === i ? { ...x, salePrice: v } : x)))
diff --git a/src/lib/format.ts b/src/lib/format.ts
index ee67b9a..89e0b0f 100644
--- a/src/lib/format.ts
+++ b/src/lib/format.ts
@@ -10,10 +10,12 @@ export function formatChf(value: number): string {
return sign + withSeparators;
}
-// Rundet auf ein Vielfaches von 1'000 -- Betraege unter 1'000 CHF sind fuer dieses
-// Planungstool nicht relevant.
-export function roundToThousand(value: number): number {
- return Math.round((value || 0) / 1000) * 1000;
+// Rundet ABwaerts auf ein Vielfaches von 1'000. Bewusst floor statt round: Betraege wie
+// z. B. eine verfuegbare Sparquote von 1'450 CHF liessen sich sonst nicht vollstaendig
+// auf Wertschriften verteilen (nur 1'000er-Schritte moeglich) -- durch Abrunden bleibt
+// der angezeigte/verplanbare Betrag immer tatsaechlich erreichbar.
+export function floorToThousand(value: number): number {
+ return Math.floor((value || 0) / 1000) * 1000;
}
export function parseChfInput(text: string): number {