feat: Sozialhilfe-Modul mit Nachforderungs-Tracker und Fristpruefung
Etappe 5. Bildet das laufende Verfahren beim Bezirk Oberfranken ab. Rechtsbehelfsfrist: § 187 Abs. 1, § 188 Abs. 2 und 3 BGB, danach § 64 Abs. 3 SGG - hier verschieben Wochenende und Feiertag das Fristende auf den naechsten Werktag. Das ist genau umgekehrt zu den Betreuerfristen, wo bewusst nicht verschoben wird, und deshalb liegt die Feiertagsliste getrennt. Zwei bayerische Sonderfaelle, die haeufig falsch gemacht werden: Mariae Himmelfahrt verschiebt NICHT (Art. 1 Abs. 1 S. 2 BayFTG - der Feiertag gilt nur in ueberwiegend katholischen Gemeinden, Bayreuth ist keine), und der Buss- und Bettag ist in Bayern seit 1995 kein Feiertag mehr. Beide erzeugen stattdessen einen ausdruecklichen Hinweis, damit man die Frist im Zweifel selbst nachrechnet. Der Rechenweg wird als Schrittliste ausgegeben. Heimkosten: Der Dashboard-Agent hatte einen fachlichen Widerspruch gefunden - der einrichtungseinheitliche Eigenanteil auf der Heimrechnung ist bereits um die Leistung der Pflegekasse gekuerzt. Wird sie zusaetzlich als Deckung erfasst, entsteht eine Doppelzaehlung von ueber tausend Euro im Monat. Das Modul rechnet jetzt ausdruecklich nach der Lesart EIGENANTEIL_NETTO, fuehrt die Pflegekassenleistung nur nachrichtlich mit und warnt, wenn sie doch belegt ist. Die Oberflaeche sagt auf einer eigenen Karte, was hier gegen was gerechnet wird. Die Schonvermoegens-Bewertung liefert Argumentationshilfen zum Uebernehmen, keine Automatik - die Einordnung obliegt dem Traeger und gegebenenfalls dem Sozialgericht. Das steht an jeder dieser Karten. Alle jaehrlich veraenderlichen Betraege stehen an einer Stelle mit Stand-Datum und Prueftermin. Die Bekleidungspauschale bewusst ohne Zahl: sie ist regional und steht im Bescheid. 46 Tests. Etappe: 5 Phase: Behoerde
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
# Schema-Wünsche aus Etappe 5 „Behörde“
|
||||
|
||||
Das Schema wurde nicht angefasst. Was beim Bauen des Sozialhilfemoduls
|
||||
gefehlt hat, steht hier — nach Dringlichkeit sortiert, jeweils mit dem
|
||||
Behelf, der jetzt an seiner Stelle steht.
|
||||
|
||||
---
|
||||
|
||||
## 1. `Heimkostenmonat`: Kostenseite und Deckungsseite überschneiden sich — wichtig
|
||||
|
||||
Dieselbe Sache wie Punkt 1 in `docs/schema-wuensche/dashboard.md`, hier aus
|
||||
Sicht des Moduls, das die Gegenüberstellung baut.
|
||||
|
||||
**Das Problem.** `pflegeEigenanteilCent` heißt „einrichtungseinheitlicher
|
||||
Eigenanteil". Der ist definitionsgemäß **schon um die Pauschale der
|
||||
Pflegekasse nach § 43 Abs. 2 SGB XI gekürzt**. Steht in derselben Zeile
|
||||
zusätzlich `pflegekasseCent` als Deckung, wird dasselbe Geld zweimal
|
||||
gezählt — die Deckungslücke fällt um die Pauschale zu klein aus, bei
|
||||
Pflegegrad 3 um 1.319 Euro im Monat.
|
||||
|
||||
**Was ich entschieden habe.** Dieses Modul rechnet in der Lesart
|
||||
`EIGENANTEIL_NETTO` (siehe Kopfkommentar in
|
||||
`src/lib/sozialhilfe/heimkosten.ts`):
|
||||
|
||||
```
|
||||
Bedarf = pflegeEigenanteil (netto, wie auf der Heimrechnung)
|
||||
+ unterkunftVerpflegung + investitionskosten
|
||||
+ ausbildungsumlage + zusatzleistungen
|
||||
+ barbetrag + bekleidungspauschale
|
||||
|
||||
Deckung = leistungszuschlag + rente + sonstigeEinkuenfte
|
||||
+ sozialhilfe + eigenmittel
|
||||
|
||||
Deckungslücke = Bedarf − Deckung
|
||||
```
|
||||
|
||||
`pflegekasseCent` zählt **nicht** als Deckung. Der Wert wird als
|
||||
`pflegekasseNachrichtlichCent` mitgeführt und angezeigt; ist er ungleich
|
||||
null, gibt `heimkostenAuswerten()` einen Hinweis aus, der die
|
||||
Doppelzählung erklärt. Das Formular belegt das Feld nicht mehr vor.
|
||||
|
||||
`leistungszuschlagCent` zählt dagegen **sehr wohl** als Deckung: Der
|
||||
Zuschlag nach § 43c SGB XI mindert den Eigenanteil erst danach und steht
|
||||
auf der Heimrechnung als eigene Abzugsposition.
|
||||
|
||||
Die Alternative — durchgängig den Bruttosatz erfassen — ist als Lesart
|
||||
`PFLEGESATZ_BRUTTO` implementiert und getestet: Bei konsistenter Erfassung
|
||||
kommen beide Lesarten auf dieselbe Deckungslücke. Benutzt wird sie in der
|
||||
Oberfläche nicht, weil das Schema keinen Ort hat, um die Wahl zu
|
||||
speichern.
|
||||
|
||||
**Wunsch, in dieser Reihenfolge:**
|
||||
|
||||
1. Den Kommentar am Feld schärfen, damit die Lesart im Schema steht und
|
||||
nicht nur hier:
|
||||
|
||||
```prisma
|
||||
/// NETTO: der einrichtungseinheitliche Eigenanteil, wie er auf der
|
||||
/// Heimrechnung steht - bereits um § 43 Abs. 2 SGB XI gekuerzt, noch
|
||||
/// nicht um den Leistungszuschlag. pflegekasseCent zaehlt deshalb NICHT
|
||||
/// als Deckung, sondern nur nachrichtlich.
|
||||
pflegeEigenanteilCent BigInt @default(0)
|
||||
```
|
||||
|
||||
2. Wenn beide Lesarten gebraucht werden, ein Feld dafür — sonst muss jedes
|
||||
Modul raten, was in der Zeile steht:
|
||||
|
||||
```prisma
|
||||
enum Kostenlesart {
|
||||
EIGENANTEIL_NETTO
|
||||
PFLEGESATZ_BRUTTO
|
||||
}
|
||||
|
||||
lesart Kostenlesart @default(EIGENANTEIL_NETTO)
|
||||
```
|
||||
|
||||
3. Alternativ ein `heimrechnungGesamtCent`, das schlicht den
|
||||
Rechnungsbetrag trägt; die Aufteilung wäre dann nur noch informativ und
|
||||
die Summe könnte gegen sie geprüft werden.
|
||||
|
||||
**Verabredung bis dahin**: Wer `Heimkostenmonat` schreibt — dieses Modul,
|
||||
das Dashboard, ein Import — trägt als `pflegeEigenanteilCent` den Netto-
|
||||
Eigenanteil ein und lässt `pflegekasseCent` auf 0.
|
||||
|
||||
---
|
||||
|
||||
## 2. `Nachforderung.checklistenSchluessel` — wichtig
|
||||
|
||||
```prisma
|
||||
/// Stabiler Schluessel aus src/lib/sozialhilfe/checkliste.ts.
|
||||
/// Verhindert Dubletten beim erneuten Uebernehmen der Standardunterlagen.
|
||||
checklistenSchluessel String?
|
||||
|
||||
@@unique([antragId, checklistenSchluessel])
|
||||
```
|
||||
|
||||
**Warum**: `ausCheckliste: Boolean` merkt sich nur *dass* eine Zeile aus der
|
||||
Checkliste kam, nicht *welche* Position. Um beim zweiten Aufruf des Panels
|
||||
nicht dieselbe Unterlage noch einmal anzulegen, vergleicht
|
||||
`nochNichtUebernommen()` derzeit über die **Bezeichnung** (kleingeschrieben,
|
||||
getrimmt). Das reicht, solange niemand die Bezeichnung ändert — tut er es,
|
||||
entsteht beim nächsten Übernehmen eine Dublette.
|
||||
|
||||
**Behelf**: Vergleich über die Bezeichnung in
|
||||
`src/lib/sozialhilfe/checkliste.ts` und in `checklisteUebernehmen()`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Rückkaufswert am Vertrag — wichtig
|
||||
|
||||
```prisma
|
||||
model Vertrag {
|
||||
// ...
|
||||
rueckkaufswertCent BigInt?
|
||||
rueckkaufswertStichtag DateTime? @db.Date
|
||||
}
|
||||
```
|
||||
|
||||
**Warum**: Die Bewertungsansicht stellt Vermögensposten und Verträge
|
||||
nebeneinander. Ein Vermögensposten trägt seinen Wert über `Wertstand`,
|
||||
ein Vertrag hat gar kein Wertfeld — nur `beitragCent`, und das ist die
|
||||
Prämie, nicht der Wert. Verträge erscheinen deshalb ohne Betrag, und die
|
||||
Summe „verwertbar“ ist unvollständig, solange nicht zu jeder Versicherung
|
||||
zusätzlich ein Vermögensposten angelegt wurde.
|
||||
|
||||
Für das Sozialhilfeverfahren ist genau dieser Wert der entscheidende: Der
|
||||
Träger fragt nach Rückkaufswerten, nicht nach Versicherungssummen.
|
||||
|
||||
**Behelf**: Die Bewertungsansicht zeigt nur Verträge, die überhaupt einen
|
||||
Wert haben können (`MIT_RUECKKAUFSWERT` aus
|
||||
`src/lib/vertraege/konstanten.ts`), und markiert sie mit „Wert noch nicht
|
||||
ermittelt“. Wer den Betrag braucht, legt zusätzlich einen
|
||||
`Vermoegensposten` mit `vertragId` und einem `Wertstand` an — dann wird der
|
||||
Vertrag in der Liste ausgeblendet, damit die Summe nicht doppelt zählt.
|
||||
|
||||
---
|
||||
|
||||
## 4. `Bescheid.rechtsbehelfsbelehrungVorhanden` — mittel
|
||||
|
||||
```prisma
|
||||
/// Ausdrueckliche Einschaetzung, nicht aus der Fristlaenge abgeleitet.
|
||||
rechtsbehelfsbelehrungVorhanden Boolean @default(true)
|
||||
rechtsbehelfsbelehrungBemerkung String?
|
||||
```
|
||||
|
||||
**Warum**: Ob die Jahresfrist des § 66 Abs. 2 SGG gilt, ist eine bewusste
|
||||
Einschätzung mit Begründung („die Belehrung nennt die falsche Behörde“).
|
||||
Derzeit wird sie aus `rechtsbehelfsfristMonate === 12` zurückgeschlossen —
|
||||
das trägt, verliert aber die Begründung, und die bräuchte man genau dann,
|
||||
wenn man sich im Widerspruchsverfahren darauf beruft.
|
||||
|
||||
**Behelf**: `belehrungZuMonaten()` in
|
||||
`src/lib/sozialhilfe/rechtsbehelf.ts`. Die Begründung gehört bis auf
|
||||
Weiteres in `notizenVerschluesselt`.
|
||||
|
||||
---
|
||||
|
||||
## 5. `Bescheid.widerspruchFristId` → `Frist` — mittel
|
||||
|
||||
```prisma
|
||||
widerspruchFristId String? @unique
|
||||
widerspruchFrist Frist? @relation(fields: [widerspruchFristId], references: [id], onDelete: SetNull)
|
||||
```
|
||||
|
||||
**Warum**: Die angelegte Frist „Widerspruch möglich bis“ wird derzeit über
|
||||
`Frist.systemSchluessel = "sozialhilfe-widerspruch-<bescheidId>"` gefunden.
|
||||
Das funktioniert (`@@unique([betreuteId, systemSchluessel])` trägt es), ist
|
||||
aber eine Verknüpfung über eine zusammengesetzte Zeichenkette. Ein echter
|
||||
Fremdschlüssel wäre sauberer und ließe die Frist beim Löschen des Bescheids
|
||||
mitziehen. Dasselbe gilt für
|
||||
`"sozialhilfe-nachforderung-<nachforderungId>"`.
|
||||
|
||||
**Behelf**: `systemSchluessel` mit festem Präfix, `upsert` statt `create`.
|
||||
|
||||
---
|
||||
|
||||
## 6. `Heimkostenmonat` — Feld für die tatsächliche Zahlung — mittel
|
||||
|
||||
```prisma
|
||||
/// Was tatsaechlich vom Konto ging - fuer den Abgleich mit dem Bescheid.
|
||||
gezahltCent BigInt?
|
||||
gezahltAm DateTime? @db.Date
|
||||
rechnungsnummer String?
|
||||
```
|
||||
|
||||
**Warum**: Die Gegenüberstellung rechnet Bedarf gegen Deckung. Was
|
||||
tatsächlich abgebucht wurde, steht nirgends — und genau die Differenz
|
||||
zwischen „laut Bescheid“ und „tatsächlich abgebucht“ ist der Anlass, beim
|
||||
Träger nachzufragen.
|
||||
|
||||
**Behelf**: `bemerkung`.
|
||||
|
||||
---
|
||||
|
||||
## 7. `Heimkostenmonat.abwesenheitsminderungCent` — klein
|
||||
|
||||
```prisma
|
||||
/// Tatsaechliche Minderung laut Heimrechnung, nicht die Schaetzung.
|
||||
abwesenheitsminderungCent BigInt @default(0)
|
||||
```
|
||||
|
||||
**Warum**: `abwesenheitstage` ist da, die Wirkung schätzt
|
||||
`abwesenheitSchaetzen()` nach dem Rahmenvertrag (drei Karenztage, danach
|
||||
25 % auf Pflegeanteil sowie Unterkunft und Verpflegung). Was die
|
||||
Einrichtung wirklich abgezogen hat, steht auf der Rechnung und ließe sich
|
||||
nicht festhalten.
|
||||
|
||||
**Behelf**: Die Schätzung wird ausdrücklich als Schätzung ausgewiesen und
|
||||
neben die erfasste Lücke gestellt, nicht in sie hineingerechnet.
|
||||
|
||||
---
|
||||
|
||||
## 8. `Leistung.wiederholungsfristMonat/-tag` — klein
|
||||
|
||||
```prisma
|
||||
/// Fuer jaehrlich zu wiederholende Antraege: Stichtag im Jahr.
|
||||
antragsschlussMonat Int?
|
||||
antragsschlussTag Int?
|
||||
```
|
||||
|
||||
**Warum**: `jaehrlichNeuBeantragen: Boolean` sagt, *dass* wiederholt werden
|
||||
muss, nicht *bis wann*. Beim Landespflegegeld ist der 31.12. eine
|
||||
Ausschlussfrist — daraus ließe sich automatisch eine Frist ableiten,
|
||||
statt sie von Hand anzulegen.
|
||||
|
||||
**Behelf**: `antragsschluss` als Text im Katalog
|
||||
(`src/lib/sozialhilfe/leistungskatalog.ts`) und ein Hinweis in der
|
||||
Oberfläche. Die Fristableitung übernimmt `pflichtfristenAbleiten()` mit
|
||||
`landespflegegeld-<jahr>` (siehe `docs/SCHNITTSTELLEN.md`).
|
||||
|
||||
---
|
||||
|
||||
## 9. `Nachforderung.notizenVerschluesselt` — klein
|
||||
|
||||
**Warum**: `erlaeuterung` und `begruendungNichtVorhanden` liegen im
|
||||
Klartext. Beides ist meist harmlos („Grundbuchauszug beim Amtsgericht
|
||||
angefordert“), kann aber Gesundheits- oder Vermögensangaben enthalten
|
||||
(„Rückkaufswert 12.480 Euro, Police verpfändet“). Wäre mindestens die
|
||||
Begründung verschlüsselt, wäre das konsequenter zum Rest des Schemas.
|
||||
|
||||
**Behelf**: keiner. Die Felder werden benutzt, wie sie sind. Falls sie
|
||||
verschlüsselt werden sollen, gehört `Nachforderung` in
|
||||
`VERSCHLUESSELTE_FELDER` in `src/lib/crypto/feld.ts`.
|
||||
@@ -9,7 +9,7 @@ import { oeffnen } from '@/lib/crypto/feld'
|
||||
import { db, nichtGeloescht } from '@/lib/db'
|
||||
import { alsIsoTag, heuteAlsTag } from '@/lib/fristen/datum'
|
||||
import { BESCHEID_ART_BESCHRIFTUNG } from '@/lib/sozialhilfe/bescheide'
|
||||
import { centZuEingabe } from '@/lib/sozialhilfe/betrag'
|
||||
import { betragFormatieren } from '@/lib/finanzen/betrag'
|
||||
import {
|
||||
fristAmpel,
|
||||
rechtsbehelfsfristBerechnen,
|
||||
@@ -122,7 +122,7 @@ export default async function BescheidSeite({
|
||||
zugegangenAm: bescheid.zugegangenAm ? alsIsoTag(bescheid.zugegangenAm) : '',
|
||||
zeitraumVon: bescheid.zeitraumVon ? alsIsoTag(bescheid.zeitraumVon) : '',
|
||||
zeitraumBis: bescheid.zeitraumBis ? alsIsoTag(bescheid.zeitraumBis) : '',
|
||||
betrag: centZuEingabe(bescheid.betragCent),
|
||||
betrag: bescheid.betragCent === null ? '' : betragFormatieren(bescheid.betragCent),
|
||||
rechtsbehelfsfristMonate: bescheid.rechtsbehelfsfristMonate,
|
||||
widerspruchEingelegtAm: bescheid.widerspruchEingelegtAm
|
||||
? alsIsoTag(bescheid.widerspruchEingelegtAm)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { HeimkostenFormular } from '@/components/sozialhilfe/heimkosten-formular'
|
||||
import { HeimkostenTabelle, type MonatsZeile } from '@/components/sozialhilfe/heimkosten-tabelle'
|
||||
import { centZuEingabe } from '@/lib/sozialhilfe/betrag'
|
||||
import { betragFormatieren } from '@/lib/finanzen/betrag'
|
||||
import { db, nichtGeloescht } from '@/lib/db'
|
||||
import { heuteAlsTag } from '@/lib/fristen/datum'
|
||||
import {
|
||||
@@ -17,6 +17,9 @@ import {
|
||||
import {
|
||||
heimkostenAuswerten,
|
||||
jahresverlaufBilden,
|
||||
KOSTENLESART_BESCHRIFTUNG,
|
||||
KOSTENLESART_ERKLAERUNG,
|
||||
KOSTENLESART_STANDARD,
|
||||
leistungszuschlagProzent,
|
||||
leistungszuschlagStufe,
|
||||
monatsname,
|
||||
@@ -101,12 +104,17 @@ export default async function HeimkostenSeite({
|
||||
// Vorschläge fürs Formular: Pauschale der Pflegekasse zum Pflegegrad
|
||||
// und der gesetzliche Mindest-Barbetrag.
|
||||
const pauschale = pflegekassePauschaleCent(betreute.pflegegrad)
|
||||
const vorschlagPflegekasse = pauschale
|
||||
? {
|
||||
betrag: centZuEingabe(pauschale),
|
||||
text: `Pflegegrad ${betreute.pflegegrad}: ${formatCent(pauschale)} monatlich (${pflegekasseRechtsgrundlage(betreute.pflegegrad)}, Stand ${KONSTANTEN_STAND}).`,
|
||||
}
|
||||
: null
|
||||
|
||||
// Bewusst nur ein Hinweis, kein Vorschlagswert zum Uebernehmen: Unter der
|
||||
// Lesart EIGENANTEIL_NETTO steckt die Pauschale schon im Eigenanteil.
|
||||
// Wer sie hier zusaetzlich eintraegt, zaehlt dasselbe Geld zweimal.
|
||||
const hinweisPflegekasse = pauschale
|
||||
? `Pflegegrad ${betreute.pflegegrad}: ${formatCent(pauschale)} monatlich ` +
|
||||
`(${pflegekasseRechtsgrundlage(betreute.pflegegrad)}, Stand ${KONSTANTEN_STAND}). ` +
|
||||
`Dieser Betrag ist im Eigenanteil oben bereits abgezogen — lass das Feld deshalb auf 0. ` +
|
||||
`Es dient nur der Erinnerung, was die Pflegekasse direkt an die Einrichtung zahlt.`
|
||||
: 'Pauschale nach § 43 SGB XI. Sie ist im Eigenanteil bereits abgezogen — lass das Feld ' +
|
||||
'auf 0. Hinterlege den Pflegegrad in den Stammdaten, dann steht hier der Betrag.'
|
||||
|
||||
const einzug = heimvertrag?.einzugAm ?? betreute.heimEinzugAm ?? null
|
||||
const verweildauer = einzug ? verweildauerMonate(einzug, heute) : null
|
||||
@@ -193,6 +201,57 @@ export default async function HeimkostenSeite({
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Was hier gegen was gerechnet wird</CardTitle>
|
||||
<CardDescription>
|
||||
Lesart: {KOSTENLESART_BESCHRIFTUNG[KOSTENLESART_STANDARD]}. Ohne diese Festlegung
|
||||
lässt sich die Rechnung nicht mit der Heimrechnung vergleichen.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 text-sm">
|
||||
<p>{KOSTENLESART_ERKLAERUNG[KOSTENLESART_STANDARD]}</p>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div className="rounded-md border p-3">
|
||||
<p className="font-semibold">Bedarf</p>
|
||||
<ul className="mt-1 list-inside list-disc text-muted-foreground">
|
||||
<li>einrichtungseinheitlicher Eigenanteil (bereits netto)</li>
|
||||
<li>Unterkunft und Verpflegung</li>
|
||||
<li>Investitionskosten</li>
|
||||
<li>Ausbildungsumlage</li>
|
||||
<li>Zusatzleistungen</li>
|
||||
<li>Barbetrag (§ 27b Abs. 2 SGB XII)</li>
|
||||
<li>Bekleidungspauschale</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="rounded-md border p-3">
|
||||
<p className="font-semibold">Deckung</p>
|
||||
<ul className="mt-1 list-inside list-disc text-muted-foreground">
|
||||
<li>Leistungszuschlag (§ 43c SGB XI)</li>
|
||||
<li>Rente</li>
|
||||
<li>sonstige Einkünfte</li>
|
||||
<li>Anteil der Sozialhilfe</li>
|
||||
<li>Eigenmittel</li>
|
||||
</ul>
|
||||
<p className="mt-2 text-muted-foreground">
|
||||
<span className="font-medium">Nicht dabei:</span> die Pauschale der Pflegekasse
|
||||
nach § 43 Abs. 2 SGB XI. Sie ist im Eigenanteil schon abgezogen und würde hier ein
|
||||
zweites Mal zählen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-muted-foreground">
|
||||
Barbetrag und Bekleidungspauschale stehen bewusst auf der Bedarfsseite: Sie müssen der
|
||||
betreuten Person tatsächlich verbleiben. Wer sie herauslässt, hält die Deckung für
|
||||
besser, als sie ist.
|
||||
</p>
|
||||
|
||||
<Rechtshinweis rechtsgrundlage="§ 43 Abs. 2 SGB XI, § 43c SGB XI, § 27b SGB XII" kurz />
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Jahresverlauf</CardTitle>
|
||||
@@ -283,20 +342,21 @@ export default async function HeimkostenSeite({
|
||||
<h2 className="text-lg font-semibold">Monat erfassen oder ändern</h2>
|
||||
<HeimkostenFormular
|
||||
jahre={jahre}
|
||||
vorschlagPflegekasse={vorschlagPflegekasse}
|
||||
hinweisPflegekasse={hinweisPflegekasse}
|
||||
vorschlagBarbetrag={{
|
||||
betrag: centZuEingabe(BARBETRAG_CENT),
|
||||
betrag: betragFormatieren(BARBETRAG_CENT),
|
||||
text: `Mindestens ${formatCent(BARBETRAG_CENT)} (27 % der Regelbedarfsstufe 1, § 27b Abs. 2 SGB XII, Stand ${KONSTANTEN_STAND}). Steht im Bescheid mehr, gilt der Bescheid.`,
|
||||
}}
|
||||
werte={{
|
||||
jahr,
|
||||
monat: naechsterOffenerMonat,
|
||||
pflegeEigenanteil: centZuEingabe(heimvertrag?.pflegeEigenanteilCent ?? null),
|
||||
unterkunftVerpflegung: centZuEingabe(heimvertrag?.unterkunftVerpflegungCent ?? null),
|
||||
investitionskosten: centZuEingabe(heimvertrag?.investitionskostenCent ?? null),
|
||||
ausbildungsumlage: centZuEingabe(heimvertrag?.ausbildungsumlageCent ?? null),
|
||||
pflegeEigenanteil: eingabefeld(heimvertrag?.pflegeEigenanteilCent ?? null),
|
||||
unterkunftVerpflegung: eingabefeld(heimvertrag?.unterkunftVerpflegungCent ?? null),
|
||||
investitionskosten: eingabefeld(heimvertrag?.investitionskostenCent ?? null),
|
||||
ausbildungsumlage: eingabefeld(heimvertrag?.ausbildungsumlageCent ?? null),
|
||||
zusatzleistungen: '',
|
||||
pflegekasse: pauschale ? centZuEingabe(pauschale) : '',
|
||||
// Absichtlich leer: siehe hinweisPflegekasse.
|
||||
pflegekasse: '',
|
||||
leistungszuschlagProzent:
|
||||
verweildauer !== null ? leistungszuschlagProzent(verweildauer) : 0,
|
||||
leistungszuschlag: '',
|
||||
@@ -304,7 +364,7 @@ export default async function HeimkostenSeite({
|
||||
sonstigeEinkuenfte: '',
|
||||
sozialhilfe: '',
|
||||
eigenmittel: '',
|
||||
barbetrag: centZuEingabe(BARBETRAG_CENT),
|
||||
barbetrag: betragFormatieren(BARBETRAG_CENT),
|
||||
bekleidungspauschale: '',
|
||||
abwesenheitstage: 0,
|
||||
bemerkung: '',
|
||||
@@ -316,3 +376,8 @@ export default async function HeimkostenSeite({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** Cent fuer ein Eingabefeld, null wird zu leer. */
|
||||
function eingabefeld(cent: bigint | null): string {
|
||||
return cent === null ? '' : betragFormatieren(cent)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import { Vermoegensliste, type ListenPosten } from '@/components/sozialhilfe/ver
|
||||
import { oeffnen } from '@/lib/crypto/feld'
|
||||
import { centZuZahl, db, nichtGeloescht } from '@/lib/db'
|
||||
import { alsIsoTag } from '@/lib/fristen/datum'
|
||||
import { VERMOEGENSART_BESCHRIFTUNG, VERMOEGENSRELEVANTE_VERTRAGSARTEN, VERTRAGSART_BESCHRIFTUNG } from '@/lib/sozialhilfe/arten'
|
||||
import { VERMOEGENS_ART_BESCHRIFTUNG } from '@/lib/finanzen/kategorien'
|
||||
import { MIT_RUECKKAUFSWERT, VERTRAG_ART_BESCHRIFTUNG } from '@/lib/vertraege/konstanten'
|
||||
import { BEWERTUNG_BESCHRIFTUNG } from '@/lib/sozialhilfe/schonvermoegen'
|
||||
import { freibetragVergleichen, uebersichtBilden } from '@/lib/sozialhilfe/vermoegensuebersicht'
|
||||
import { sozialhilfeKontext } from '@/lib/sozialhilfe/zugang'
|
||||
@@ -34,7 +35,9 @@ export default async function VermoegensbewertungSeite() {
|
||||
db.vertrag.findMany({
|
||||
where: {
|
||||
betreuteId,
|
||||
art: { in: [...VERMOEGENSRELEVANTE_VERTRAGSARTEN] },
|
||||
// Nur Vertraege, die ueberhaupt einen Wert darstellen koennen. Ein
|
||||
// Stromvertrag hat keinen Rueckkaufswert und wuerde die Liste zumuellen.
|
||||
art: { in: [...MIT_RUECKKAUFSWERT] },
|
||||
...nichtGeloescht,
|
||||
},
|
||||
orderBy: { bezeichnung: 'asc' },
|
||||
@@ -56,7 +59,7 @@ export default async function VermoegensbewertungSeite() {
|
||||
bezeichnung: p.bezeichnung,
|
||||
herkunft: 'VERMOEGEN' as const,
|
||||
art: p.art,
|
||||
artBeschriftung: VERMOEGENSART_BESCHRIFTUNG[p.art],
|
||||
artBeschriftung: VERMOEGENS_ART_BESCHRIFTUNG[p.art],
|
||||
bewertung: p.bewertungSozialhilfe,
|
||||
wertCent: stand ? centZuZahl(stand.wertCent) : null,
|
||||
wertStichtag: stand ? alsIsoTag(stand.stichtag) : null,
|
||||
@@ -73,7 +76,7 @@ export default async function VermoegensbewertungSeite() {
|
||||
bezeichnung: v.bezeichnung,
|
||||
herkunft: 'VERTRAG' as const,
|
||||
art: v.art,
|
||||
artBeschriftung: VERTRAGSART_BESCHRIFTUNG[v.art],
|
||||
artBeschriftung: VERTRAG_ART_BESCHRIFTUNG[v.art],
|
||||
bewertung: v.bewertungSozialhilfe,
|
||||
// Der Rückkaufswert steht am Vertrag nicht als Betrag; er wird
|
||||
// als Vermögensposten mit Wertstand geführt. Bis dahin: offen.
|
||||
|
||||
@@ -43,17 +43,21 @@ export type HeimkostenWerte = {
|
||||
export function HeimkostenFormular({
|
||||
werte,
|
||||
jahre,
|
||||
vorschlagPflegekasse,
|
||||
hinweisPflegekasse,
|
||||
vorschlagBarbetrag,
|
||||
}: {
|
||||
werte: HeimkostenWerte
|
||||
jahre: number[]
|
||||
/** Pauschale der Pflegekasse zum hinterlegten Pflegegrad, als "1319,00". */
|
||||
vorschlagPflegekasse: { betrag: string; text: string } | null
|
||||
/**
|
||||
* Erklaerung zum Feld "Leistung der Pflegekasse". Bewusst KEIN
|
||||
* Uebernehmen-Knopf: Unter der Lesart dieses Moduls ist der
|
||||
* Eigenanteil bereits um die Pauschale gekuerzt, das Feld gehoert
|
||||
* deshalb auf 0. Siehe src/lib/sozialhilfe/heimkosten.ts.
|
||||
*/
|
||||
hinweisPflegekasse: string
|
||||
vorschlagBarbetrag: { betrag: string; text: string }
|
||||
}) {
|
||||
const [zustand, aktion] = useActionState<Formularzustand, FormData>(heimkostenSpeichern, {})
|
||||
const [pflegekasse, setPflegekasse] = useState(werte.pflegekasse)
|
||||
const [barbetrag, setBarbetrag] = useState(werte.barbetrag)
|
||||
|
||||
return (
|
||||
@@ -100,7 +104,7 @@ export function HeimkostenFormular({
|
||||
id="pflegeEigenanteil"
|
||||
beschriftung="Einrichtungseinheitlicher Eigenanteil"
|
||||
fehler={zustand.felder?.pflegeEigenanteil}
|
||||
erklaerung="Der pflegebedingte Anteil (EEE). In jedem Pflegegrad gleich hoch. Nur auf ihn wirkt der Leistungszuschlag."
|
||||
erklaerung="Der pflegebedingte Anteil (EEE), genau wie er auf der Heimrechnung steht — also bereits abzüglich der Pauschale der Pflegekasse (§ 43 Abs. 2 SGB XI). In jedem Pflegegrad gleich hoch. Nur auf ihn wirkt der Leistungszuschlag."
|
||||
>
|
||||
<Input
|
||||
name="pflegeEigenanteil"
|
||||
@@ -163,31 +167,11 @@ export function HeimkostenFormular({
|
||||
<Feldgruppe titel="Deckung" beschreibung="Wer zahlt welchen Teil?">
|
||||
<Feld
|
||||
id="pflegekasse"
|
||||
beschriftung="Leistung der Pflegekasse"
|
||||
beschriftung="Leistung der Pflegekasse (nachrichtlich)"
|
||||
fehler={zustand.felder?.pflegekasse}
|
||||
erklaerung={
|
||||
vorschlagPflegekasse ? (
|
||||
<>
|
||||
{vorschlagPflegekasse.text}{' '}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPflegekasse(vorschlagPflegekasse.betrag)}
|
||||
className="font-medium text-primary underline-offset-4 hover:underline"
|
||||
>
|
||||
Wert übernehmen
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
'Pauschale nach § 43 SGB XI. Hinterlege den Pflegegrad in den Stammdaten, dann steht hier ein Vorschlag.'
|
||||
)
|
||||
}
|
||||
erklaerung={hinweisPflegekasse}
|
||||
>
|
||||
<Input
|
||||
name="pflegekasse"
|
||||
inputMode="decimal"
|
||||
value={pflegekasse}
|
||||
onChange={(e) => setPflegekasse(e.target.value)}
|
||||
/>
|
||||
<Input name="pflegekasse" inputMode="decimal" defaultValue={werte.pflegekasse} />
|
||||
</Feld>
|
||||
|
||||
<Feld
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import type { VermoegensArt, VertragArt } from '@prisma/client'
|
||||
|
||||
/**
|
||||
* Menschenlesbare Namen der Vermögens- und Vertragsarten.
|
||||
*
|
||||
* Sie stehen hier, weil die Bewertungsansicht sie braucht und die Module
|
||||
* "Vermögen & Kasse" und "Verträge" ihre eigenen Beschriftungen führen.
|
||||
* Sobald dort eine gemeinsame Quelle existiert, wandert diese Datei
|
||||
* dorthin - bis dahin lieber eine kleine Doppelung als ein Modul, das auf
|
||||
* ein anderes wartet.
|
||||
*/
|
||||
|
||||
export const VERMOEGENSART_BESCHRIFTUNG: Record<VermoegensArt, string> = {
|
||||
KONTO: 'Konto',
|
||||
IMMOBILIE: 'Immobilie',
|
||||
VERSICHERUNG: 'Versicherung',
|
||||
FAHRZEUG: 'Fahrzeug',
|
||||
WERTGEGENSTAND: 'Wertgegenstand',
|
||||
FORDERUNG: 'Forderung',
|
||||
VERBINDLICHKEIT: 'Verbindlichkeit',
|
||||
SONSTIGES: 'Sonstiges',
|
||||
}
|
||||
|
||||
export const VERTRAGSART_BESCHRIFTUNG: Record<VertragArt, string> = {
|
||||
LEBENSVERSICHERUNG: 'Lebensversicherung',
|
||||
STERBEGELDVERSICHERUNG: 'Sterbegeldversicherung',
|
||||
BESTATTUNGSVORSORGE: 'Bestattungsvorsorge',
|
||||
RENTENVERSICHERUNG_PRIVAT: 'Private Rentenversicherung',
|
||||
UNFALLVERSICHERUNG: 'Unfallversicherung',
|
||||
HAFTPFLICHT: 'Haftpflichtversicherung',
|
||||
HAUSRAT: 'Hausratversicherung',
|
||||
WOHNGEBAEUDE: 'Wohngebäudeversicherung',
|
||||
KRANKENZUSATZ: 'Krankenzusatzversicherung',
|
||||
PFLEGEZUSATZ: 'Pflegezusatzversicherung',
|
||||
RECHTSSCHUTZ: 'Rechtsschutzversicherung',
|
||||
STERBEKASSE: 'Sterbekasse',
|
||||
STROM: 'Stromvertrag',
|
||||
GAS: 'Gasvertrag',
|
||||
WASSER: 'Wasserversorgung',
|
||||
TELEFON_INTERNET: 'Telefon und Internet',
|
||||
RUNDFUNKBEITRAG: 'Rundfunkbeitrag',
|
||||
MITGLIEDSCHAFT: 'Mitgliedschaft',
|
||||
ABONNEMENT: 'Abonnement',
|
||||
SONSTIGES: 'Sonstiges',
|
||||
}
|
||||
|
||||
/**
|
||||
* Vertragsarten, die im Sozialhilfeverfahren überhaupt Vermögen darstellen
|
||||
* können. Ein Stromvertrag hat keinen Rückkaufswert - er gehört nicht in
|
||||
* die Bewertungsansicht und würde sie nur zumüllen.
|
||||
*/
|
||||
export const VERMOEGENSRELEVANTE_VERTRAGSARTEN: readonly VertragArt[] = [
|
||||
'LEBENSVERSICHERUNG',
|
||||
'STERBEGELDVERSICHERUNG',
|
||||
'BESTATTUNGSVORSORGE',
|
||||
'RENTENVERSICHERUNG_PRIVAT',
|
||||
'PFLEGEZUSATZ',
|
||||
'KRANKENZUSATZ',
|
||||
'STERBEKASSE',
|
||||
'UNFALLVERSICHERUNG',
|
||||
] as const
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Eingelesene Beträge in Cent umrechnen.
|
||||
*
|
||||
* Die Anwendung rechnet ausschließlich mit BigInt-Cent. Der Weg vom
|
||||
* Formularfeld dorthin ist die einzige Stelle, an der eine Zeichenkette in
|
||||
* eine Zahl wird - deshalb steht er hier und nicht verstreut in den
|
||||
* Server Actions.
|
||||
*
|
||||
* Bewusst NICHT über parseFloat: 1234,56 als Fließkomma und dann mal 100
|
||||
* ergibt 123455.99999999999. In der Rechnungslegung gegenüber dem Gericht
|
||||
* hat ein solcher Cent nichts verloren.
|
||||
*/
|
||||
|
||||
/** "1.234,56", "1234,56", "1234.56", "1234" -> 123456n. */
|
||||
export function betragZuCent(eingabe: string | null | undefined): bigint | null {
|
||||
if (eingabe === null || eingabe === undefined) return null
|
||||
|
||||
let text = String(eingabe).trim()
|
||||
if (text === '') return null
|
||||
|
||||
text = text.replace(/\s/g, '').replace(/€/g, '').replace(/EUR/gi, '')
|
||||
|
||||
let negativ = false
|
||||
if (text.startsWith('-')) {
|
||||
negativ = true
|
||||
text = text.slice(1)
|
||||
} else if (text.startsWith('+')) {
|
||||
text = text.slice(1)
|
||||
}
|
||||
|
||||
// Deutsche Schreibweise: Punkt trennt Tausender, Komma die Cent.
|
||||
// Englische Schreibweise mit Punkt als Dezimaltrenner wird ebenfalls
|
||||
// angenommen, solange sie eindeutig ist (genau ein Punkt, ein bis zwei
|
||||
// Nachkommastellen, kein Komma).
|
||||
if (text.includes(',')) {
|
||||
text = text.replace(/\./g, '').replace(',', '.')
|
||||
} else {
|
||||
const punkte = text.split('.').length - 1
|
||||
if (punkte > 1) {
|
||||
text = text.replace(/\./g, '')
|
||||
} else if (punkte === 1) {
|
||||
const nachkomma = text.split('.')[1] ?? ''
|
||||
// "1.234" ist ein Tausenderpunkt, "1.23" ein Dezimalpunkt.
|
||||
if (nachkomma.length === 3) text = text.replace('.', '')
|
||||
}
|
||||
}
|
||||
|
||||
const treffer = /^(\d+)(?:\.(\d{1,2}))?$/.exec(text)
|
||||
if (!treffer) return null
|
||||
|
||||
const euro = BigInt(treffer[1]!)
|
||||
const centText = (treffer[2] ?? '').padEnd(2, '0')
|
||||
const cent = BigInt(centText)
|
||||
|
||||
const gesamt = euro * 100n + cent
|
||||
return negativ ? -gesamt : gesamt
|
||||
}
|
||||
|
||||
/** Gegenrichtung: 123456n -> "1234,56" für die Vorbelegung von Feldern. */
|
||||
export function centZuEingabe(cent: bigint | null | undefined): string {
|
||||
if (cent === null || cent === undefined) return ''
|
||||
const negativ = cent < 0n
|
||||
const betrag = negativ ? -cent : cent
|
||||
const euro = betrag / 100n
|
||||
const rest = betrag % 100n
|
||||
return `${negativ ? '-' : ''}${euro},${rest.toString().padStart(2, '0')}`
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
import {
|
||||
LEISTUNGSZUSCHLAG_RECHTSGRUNDLAGE,
|
||||
LEISTUNGSZUSCHLAG_STAFFEL,
|
||||
LEISTUNGSZUSCHLAG_STAND,
|
||||
} from '@/lib/pflege/konstanten'
|
||||
import { anteilCent, stufeFuerMonate, verweildauerMonate } from '@/lib/pflege/leistungszuschlag'
|
||||
import {
|
||||
ABWESENHEIT_KARENZTAGE,
|
||||
ABWESENHEIT_MINDERUNG_PROZENT,
|
||||
ABWESENHEIT_PLATZFREIHALTUNG_TAGE,
|
||||
LEISTUNGSZUSCHLAG_STAFFEL,
|
||||
PFLEGEKASSE_RECHTSGRUNDLAGE,
|
||||
PFLEGEKASSE_VOLLSTATIONAER_CENT,
|
||||
type Pflegegrad,
|
||||
@@ -12,78 +17,106 @@ import {
|
||||
* Heimkosten-Gegenüberstellung: Was kostet der Monat, wer zahlt was, und
|
||||
* was bleibt offen?
|
||||
*
|
||||
* Die Heimrechnung besteht aus vier Bausteinen, von denen nur der erste
|
||||
* pflegebedingt ist:
|
||||
* =========================================================================
|
||||
* DIE LESART — bitte vor jeder Änderung lesen
|
||||
* =========================================================================
|
||||
*
|
||||
* 1. einrichtungseinheitlicher Eigenanteil (EEE) - der pflegebedingte
|
||||
* Anteil, in jedem Pflegegrad gleich hoch. Nur auf ihn wirkt der
|
||||
* Leistungszuschlag nach § 43c SGB XI.
|
||||
* 2. Unterkunft und Verpflegung - trägt die betreute Person selbst,
|
||||
* hilfsweise die Sozialhilfe.
|
||||
* 3. Investitionskosten - Gebäude, Instandhaltung. Laufen auch bei
|
||||
* Abwesenheit weiter.
|
||||
* 4. Ausbildungsumlage - Umlage zur Finanzierung der Pflegeausbildung.
|
||||
* Eine Heimrechnung rechnet in dieser Reihenfolge:
|
||||
*
|
||||
* Dazu kommen Zusatzleistungen (Friseur, besondere Komfortleistungen), die
|
||||
* der Träger in aller Regel nicht übernimmt.
|
||||
* Pflegesatz (pflegebedingter Aufwand, brutto)
|
||||
* − Leistung der Pflegekasse § 43 Abs. 2 SGB XI
|
||||
* = einrichtungseinheitlicher Eigenanteil (EEE)
|
||||
* − Leistungszuschlag § 43c SGB XI
|
||||
* = zu zahlender pflegebedingter Anteil
|
||||
* + Unterkunft und Verpflegung
|
||||
* + Investitionskosten
|
||||
* + Ausbildungsumlage
|
||||
* + Zusatzleistungen
|
||||
* = Rechnungsbetrag
|
||||
*
|
||||
* Der EEE ist damit DEFINITIONSGEMÄSS schon um die Pauschale der
|
||||
* Pflegekasse gekürzt. Wer ihn als Kosten ansetzt UND die Pauschale
|
||||
* zusätzlich als Deckung, zählt dasselbe Geld zweimal und weist eine
|
||||
* Überdeckung aus, die es nicht gibt. Genau darauf hat der Dashboard-Agent
|
||||
* hingewiesen (docs/schema-wuensche/dashboard.md, Punkt 1).
|
||||
*
|
||||
* ENTSCHEIDUNG DIESES MODULS: Lesart EIGENANTEIL_NETTO.
|
||||
*
|
||||
* `pflegeEigenanteilCent` ist der einrichtungseinheitliche Eigenanteil, so
|
||||
* wie er auf der Heimrechnung steht — bereits um § 43 Abs. 2 SGB XI
|
||||
* gekürzt, aber noch nicht um den Leistungszuschlag. Das entspricht dem
|
||||
* Feldnamen, dem Kommentar im Schema und dem, was man tatsächlich abtippt.
|
||||
*
|
||||
* Daraus folgt:
|
||||
* - `pflegekasseCent` wird NICHT als Deckung gezählt. Der Betrag steckt
|
||||
* schon im Eigenanteil. Er wird nachrichtlich mitgeführt und angezeigt,
|
||||
* damit man ihn nicht für verschwunden hält.
|
||||
* - `leistungszuschlagCent` wird SEHR WOHL als Deckung gezählt: Er
|
||||
* mindert den EEE erst danach und steht auf der Rechnung als eigene
|
||||
* Abzugsposition.
|
||||
*
|
||||
* Wer stattdessen den Bruttosatz erfassen will, ruft mit der Lesart
|
||||
* PFLEGESATZ_BRUTTO auf — dann zählt die Pauschale als Deckung. Bei
|
||||
* konsistenter Erfassung führen beide Lesarten zur selben Deckungslücke;
|
||||
* ein Test hält das fest. Was die Rechnung nicht verträgt, ist die
|
||||
* Mischung — und genau davor warnt `heimkostenAuswerten()`.
|
||||
*
|
||||
* Alle Beträge BigInt in Cent. Kein Fließkomma, nirgends.
|
||||
*/
|
||||
|
||||
export type Kostenlesart = 'EIGENANTEIL_NETTO' | 'PFLEGESATZ_BRUTTO'
|
||||
|
||||
/** Die Lesart, mit der dieses Modul rechnet, solange nichts anderes gesagt wird. */
|
||||
export const KOSTENLESART_STANDARD: Kostenlesart = 'EIGENANTEIL_NETTO'
|
||||
|
||||
export const KOSTENLESART_BESCHRIFTUNG: Record<Kostenlesart, string> = {
|
||||
EIGENANTEIL_NETTO: 'Eigenanteil laut Heimrechnung',
|
||||
PFLEGESATZ_BRUTTO: 'Pflegesatz brutto',
|
||||
}
|
||||
|
||||
export const KOSTENLESART_ERKLAERUNG: Record<Kostenlesart, string> = {
|
||||
EIGENANTEIL_NETTO:
|
||||
'Als Kosten steht der einrichtungseinheitliche Eigenanteil — er ist bereits um die ' +
|
||||
'Pauschale der Pflegekasse nach § 43 Abs. 2 SGB XI gekürzt. Deshalb zählt die Pauschale ' +
|
||||
'hier nicht noch einmal als Deckung, sie wird nur nachrichtlich ausgewiesen. Der ' +
|
||||
'Leistungszuschlag nach § 43c SGB XI zählt dagegen als Deckung, weil er den Eigenanteil ' +
|
||||
'erst danach mindert und auf der Rechnung als eigene Abzugsposition steht.',
|
||||
PFLEGESATZ_BRUTTO:
|
||||
'Als Kosten steht der volle pflegebedingte Aufwand vor Abzug der Pflegekassenleistung. ' +
|
||||
'Pauschale und Leistungszuschlag zählen dann beide als Deckung.',
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Leistungszuschlag, § 43c SGB XI
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Die Staffel steht im Pflegemodul (src/lib/pflege/konstanten.ts) und wird
|
||||
// hier nur benutzt. Zwei Kopien derselben Prozentsätze wären genau die
|
||||
// Sorte Fehler, die bei der nächsten Gesetzesänderung an einer Stelle
|
||||
// nachgezogen wird und an der anderen nicht.
|
||||
|
||||
/**
|
||||
* Prozentsatz des Leistungszuschlags nach der Dauer der
|
||||
* Leistungsinanspruchnahme.
|
||||
*
|
||||
* Gezählt werden VOLLENDETE Monate in vollstationärer Pflege. Nach zwölf
|
||||
* vollen Monaten - also im dreizehnten - greift die zweite Stufe, weil
|
||||
* § 43c SGB XI von "mehr als 12 Monaten" spricht.
|
||||
*/
|
||||
export { LEISTUNGSZUSCHLAG_STAFFEL, LEISTUNGSZUSCHLAG_STAND, LEISTUNGSZUSCHLAG_RECHTSGRUNDLAGE }
|
||||
export { verweildauerMonate }
|
||||
|
||||
/** Prozentsatz nach vollendeten Monaten in der Einrichtung. */
|
||||
export function leistungszuschlagProzent(vollendeteMonate: number): number {
|
||||
const monate = Math.max(0, Math.floor(vollendeteMonate))
|
||||
let prozent = LEISTUNGSZUSCHLAG_STAFFEL[0]!.prozent
|
||||
for (const stufe of LEISTUNGSZUSCHLAG_STAFFEL) {
|
||||
if (monate >= stufe.abVollendetenMonaten) prozent = stufe.prozent
|
||||
}
|
||||
return prozent
|
||||
return stufeFuerMonate(Math.max(0, Math.floor(vollendeteMonate))).prozent
|
||||
}
|
||||
|
||||
/** Beschriftung der Stufe, für die Anzeige neben der Zahl. */
|
||||
export function leistungszuschlagStufe(vollendeteMonate: number): string {
|
||||
const prozent = leistungszuschlagProzent(vollendeteMonate)
|
||||
return LEISTUNGSZUSCHLAG_STAFFEL.find((s) => s.prozent === prozent)?.beschriftung ?? ''
|
||||
return stufeFuerMonate(Math.max(0, Math.floor(vollendeteMonate))).bezeichnung
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Zuschlag in Cent - immer nur auf den pflegebedingten Eigenanteil.
|
||||
*
|
||||
* Gerundet wird kaufmännisch auf ganze Cent. Bei ganzen Prozentsätzen und
|
||||
* Cent-Beträgen ist das eine Rundung von höchstens einem Cent, aber sie
|
||||
* gehört ausgeschrieben, damit niemand später über einen Cent Differenz
|
||||
* zur Heimrechnung rätselt.
|
||||
* Der Zuschlag in Cent — immer nur auf den pflegebedingten Eigenanteil,
|
||||
* nie auf Unterkunft, Investitionskosten oder Ausbildungsumlage.
|
||||
*/
|
||||
export function leistungszuschlagCent(
|
||||
pflegeEigenanteilCent: bigint,
|
||||
vollendeteMonate: number,
|
||||
): bigint {
|
||||
const prozent = BigInt(leistungszuschlagProzent(vollendeteMonate))
|
||||
const roh = pflegeEigenanteilCent * prozent
|
||||
return (roh + 50n) / 100n
|
||||
}
|
||||
|
||||
/**
|
||||
* Vollendete Monate im Heim zwischen Einzug und Stichtag. Bricht die
|
||||
* Zählung nicht auf Tage herunter - § 43c SGB XI stellt auf Monate ab.
|
||||
*/
|
||||
export function verweildauerMonate(einzugAm: Date, stichtag: Date): number {
|
||||
const jahre = stichtag.getUTCFullYear() - einzugAm.getUTCFullYear()
|
||||
const monate = stichtag.getUTCMonth() - einzugAm.getUTCMonth()
|
||||
let gesamt = jahre * 12 + monate
|
||||
if (stichtag.getUTCDate() < einzugAm.getUTCDate()) gesamt -= 1
|
||||
return Math.max(0, gesamt)
|
||||
return anteilCent(pflegeEigenanteilCent, leistungszuschlagProzent(vollendeteMonate))
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -129,7 +162,7 @@ export type Abwesenheitsschaetzung = {
|
||||
*
|
||||
* Gerundet wird abwärts (BigInt-Division schneidet ab). Die geschätzte
|
||||
* Minderung fällt damit im Zweifel einen Cent zu klein und die
|
||||
* Deckungslücke einen Cent zu groß aus - die vorsichtigere Richtung.
|
||||
* Deckungslücke einen Cent zu groß aus — die vorsichtigere Richtung.
|
||||
*/
|
||||
export function abwesenheitSchaetzen(eingabe: {
|
||||
abwesenheitstage: number
|
||||
@@ -204,6 +237,7 @@ export type HeimkostenEingabe = {
|
||||
export type HeimkostenErgebnis = {
|
||||
jahr: number
|
||||
monat: number
|
||||
lesart: Kostenlesart
|
||||
|
||||
heimkostenCent: bigint
|
||||
/** Heimkosten plus Barbetrag und Bekleidungspauschale. */
|
||||
@@ -211,9 +245,16 @@ export type HeimkostenErgebnis = {
|
||||
deckungCent: bigint
|
||||
verbleibendCent: bigint
|
||||
|
||||
/**
|
||||
* Leistung der Pflegekasse, die unter der Lesart EIGENANTEIL_NETTO nicht
|
||||
* als Deckung zählt, weil sie schon im Eigenanteil steckt. Nur für die
|
||||
* Anzeige — sie wird nirgends aufaddiert.
|
||||
*/
|
||||
pflegekasseNachrichtlichCent: bigint
|
||||
|
||||
/**
|
||||
* Positiv = ungedeckt, negativ = Überdeckung. Für die Anzeige stehen
|
||||
* daneben deckungsluecke Cent und ueberdeckungCent, jeweils >= 0.
|
||||
* daneben deckungslueckeCent und ueberdeckungCent, jeweils >= 0.
|
||||
*/
|
||||
saldoCent: bigint
|
||||
deckungslueckeCent: bigint
|
||||
@@ -232,11 +273,16 @@ export type HeimkostenErgebnis = {
|
||||
*
|
||||
* Bedarfsbegriff: Zum Bedarf zählen nicht nur die Heimkosten, sondern auch
|
||||
* der Barbetrag nach § 27b Abs. 2 SGB XII und die Bekleidungspauschale.
|
||||
* Beides muss der betreuten Person tatsächlich verbleiben - wer es aus der
|
||||
* Beides muss der betreuten Person tatsächlich verbleiben — wer es aus der
|
||||
* Rechnung herauslässt, hält die Deckung für besser, als sie ist, und
|
||||
* plündert am Monatsende das Taschengeld.
|
||||
*
|
||||
* Zur Behandlung von `pflegekasseCent` siehe den Kopf dieser Datei.
|
||||
*/
|
||||
export function heimkostenAuswerten(eingabe: HeimkostenEingabe): HeimkostenErgebnis {
|
||||
export function heimkostenAuswerten(
|
||||
eingabe: HeimkostenEingabe,
|
||||
lesart: Kostenlesart = KOSTENLESART_STANDARD,
|
||||
): HeimkostenErgebnis {
|
||||
const heimkostenCent =
|
||||
eingabe.pflegeEigenanteilCent +
|
||||
eingabe.unterkunftVerpflegungCent +
|
||||
@@ -247,8 +293,12 @@ export function heimkostenAuswerten(eingabe: HeimkostenEingabe): HeimkostenErgeb
|
||||
const verbleibendCent = eingabe.barbetragCent + eingabe.bekleidungspauschaleCent
|
||||
const gesamtbedarfCent = heimkostenCent + verbleibendCent
|
||||
|
||||
const nettoLesart = lesart === 'EIGENANTEIL_NETTO'
|
||||
const pflegekasseAlsDeckungCent = nettoLesart ? 0n : eingabe.pflegekasseCent
|
||||
const pflegekasseNachrichtlichCent = nettoLesart ? eingabe.pflegekasseCent : 0n
|
||||
|
||||
const deckungCent =
|
||||
eingabe.pflegekasseCent +
|
||||
pflegekasseAlsDeckungCent +
|
||||
eingabe.leistungszuschlagCent +
|
||||
eingabe.renteCent +
|
||||
eingabe.sonstigeEinkuenfteCent +
|
||||
@@ -267,6 +317,15 @@ export function heimkostenAuswerten(eingabe: HeimkostenEingabe): HeimkostenErgeb
|
||||
const nachAbwesenheit = saldoCent - abwesenheit.geschaetzteMinderungCent
|
||||
|
||||
const hinweise: string[] = []
|
||||
|
||||
if (nettoLesart && eingabe.pflegekasseCent > 0n) {
|
||||
hinweise.push(
|
||||
'Hier steht eine Leistung der Pflegekasse als Deckung — der einrichtungseinheitliche ' +
|
||||
'Eigenanteil ist aber schon um sie gekürzt (§ 43 Abs. 2 SGB XI). Der Betrag wird ' +
|
||||
'deshalb nicht mitgezählt; sonst stünde dasselbe Geld zweimal in der Rechnung. Trag ' +
|
||||
'als Kosten den Eigenanteil von der Heimrechnung ein und lass dieses Feld auf 0.',
|
||||
)
|
||||
}
|
||||
if (eingabe.zusatzleistungenCent > 0n) {
|
||||
hinweise.push(
|
||||
'Zusatzleistungen (Friseur, Komfortleistungen) übernimmt der Träger in aller Regel ' +
|
||||
@@ -297,10 +356,12 @@ export function heimkostenAuswerten(eingabe: HeimkostenEingabe): HeimkostenErgeb
|
||||
return {
|
||||
jahr: eingabe.jahr,
|
||||
monat: eingabe.monat,
|
||||
lesart,
|
||||
heimkostenCent,
|
||||
gesamtbedarfCent,
|
||||
deckungCent,
|
||||
verbleibendCent,
|
||||
pflegekasseNachrichtlichCent,
|
||||
saldoCent,
|
||||
deckungslueckeCent: saldoCent > 0n ? saldoCent : 0n,
|
||||
ueberdeckungCent: saldoCent < 0n ? -saldoCent : 0n,
|
||||
@@ -317,7 +378,7 @@ export type Jahresverlauf = {
|
||||
summeBedarfCent: bigint
|
||||
summeDeckungCent: bigint
|
||||
summeDeckungslueckeCent: bigint
|
||||
/** Monat mit der größten Lücke - dort lohnt der Blick zuerst. */
|
||||
/** Monat mit der größten Lücke — dort lohnt der Blick zuerst. */
|
||||
groessteLuecke: HeimkostenErgebnis | null
|
||||
}
|
||||
|
||||
|
||||
@@ -103,37 +103,18 @@ export const PFLEGEKASSE_RECHTSGRUNDLAGE: Record<Pflegegrad, string> = {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Leistungszuschlag, § 43c SGB XI
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Der Leistungszuschlag mindert den *pflegebedingten* Eigenanteil
|
||||
* (einrichtungseinheitlicher Eigenanteil, EEE) - nicht Unterkunft und
|
||||
* Verpflegung, nicht die Investitionskosten und nicht die
|
||||
* Ausbildungsumlage. Wer ihn auf die ganze Heimrechnung anwendet, rechnet
|
||||
* die Deckungslücke zu klein.
|
||||
*
|
||||
* Die Staffel richtet sich nach der Dauer der Leistungsinanspruchnahme in
|
||||
* vollstationärer Pflege. Stand 01.01.2024 (angehoben durch das PUEG,
|
||||
* vorher 5/25/45/70 %).
|
||||
*
|
||||
* Lesart der Stufen: § 43c SGB XI spricht von "mehr als 12 Monaten". Die
|
||||
* höhere Stufe greift also, sobald die genannte Monatszahl *vollendet*
|
||||
* ist - nach 12 vollen Monaten, also im 13. Monat, gelten 30 %.
|
||||
*/
|
||||
export type Leistungszuschlagstufe = {
|
||||
/** Ab wie vielen vollendeten Monaten im Heim gilt diese Stufe? */
|
||||
abVollendetenMonaten: number
|
||||
prozent: number
|
||||
beschriftung: string
|
||||
}
|
||||
|
||||
export const LEISTUNGSZUSCHLAG_STAFFEL: readonly Leistungszuschlagstufe[] = [
|
||||
{ abVollendetenMonaten: 0, prozent: 15, beschriftung: 'bis 12 Monate' },
|
||||
{ abVollendetenMonaten: 12, prozent: 30, beschriftung: 'mehr als 12 Monate' },
|
||||
{ abVollendetenMonaten: 24, prozent: 50, beschriftung: 'mehr als 24 Monate' },
|
||||
{ abVollendetenMonaten: 36, prozent: 75, beschriftung: 'mehr als 36 Monate' },
|
||||
] as const
|
||||
|
||||
export const LEISTUNGSZUSCHLAG_STAND = '2024-01-01'
|
||||
//
|
||||
// STEHT NICHT HIER. Die Staffel (15 / 30 / 50 / 75 Prozent nach
|
||||
// Verweildauer, Stand 01.01.2024) gehoert dem Pflegemodul und liegt in
|
||||
// src/lib/pflege/konstanten.ts. Dieses Modul benutzt sie ueber
|
||||
// src/lib/sozialhilfe/heimkosten.ts, kopiert sie aber nicht - zwei Kopien
|
||||
// derselben Prozentsaetze werden bei der naechsten Gesetzesaenderung
|
||||
// zuverlaessig nur an einer Stelle nachgezogen.
|
||||
//
|
||||
// Merksatz zur Anwendung: Der Zuschlag mindert ausschliesslich den
|
||||
// pflegebedingten Eigenanteil (EEE) - nicht Unterkunft und Verpflegung,
|
||||
// nicht die Investitionskosten, nicht die Ausbildungsumlage. Wer ihn auf
|
||||
// die ganze Heimrechnung anwendet, rechnet die Deckungsluecke zu klein.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Abwesenheit (Krankenhaus, Reha, Urlaub)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from 'zod'
|
||||
import { betragZuCent } from '@/lib/sozialhilfe/betrag'
|
||||
import { betragParsenWennMoeglich } from '@/lib/finanzen/betrag'
|
||||
|
||||
/**
|
||||
* Eingabeprüfung für das Sozialhilfemodul.
|
||||
@@ -48,7 +48,7 @@ const optionalerBetrag = z
|
||||
.default('')
|
||||
.transform((wert, ctx) => {
|
||||
if (wert === '') return null
|
||||
const cent = betragZuCent(wert)
|
||||
const cent = betragParsenWennMoeglich(wert)
|
||||
if (cent === null) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
@@ -66,7 +66,7 @@ const betragOderNull = z
|
||||
.default('')
|
||||
.transform((wert, ctx) => {
|
||||
if (wert === '') return 0n
|
||||
const cent = betragZuCent(wert)
|
||||
const cent = betragParsenWennMoeglich(wert)
|
||||
if (cent === null) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
|
||||
+47
-48
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { alsIsoTag, tag } from '@/lib/fristen/datum'
|
||||
import { betragZuCent, centZuEingabe } from '@/lib/sozialhilfe/betrag'
|
||||
import { nochNichtUebernommen, STANDARDUNTERLAGEN } from '@/lib/sozialhilfe/checkliste'
|
||||
import { aufWerktagSchieben, bayerischerFeiertag, bussUndBettag, istWerktag } from '@/lib/sozialhilfe/feiertage'
|
||||
import {
|
||||
@@ -337,6 +336,12 @@ describe('Leistungszuschlag nach der Verweildauer', () => {
|
||||
// =============================================================================
|
||||
|
||||
describe('Heimkosten-Gegenüberstellung', () => {
|
||||
/**
|
||||
* Lesart EIGENANTEIL_NETTO: pflegeEigenanteilCent ist der Betrag von der
|
||||
* Heimrechnung und damit schon um die Pauschale der Pflegekasse gekürzt.
|
||||
* pflegekasseCent bleibt deshalb 0 — sonst stünde dasselbe Geld zweimal
|
||||
* in der Rechnung.
|
||||
*/
|
||||
const grundfall = {
|
||||
jahr: 2026,
|
||||
monat: 3,
|
||||
@@ -345,11 +350,11 @@ describe('Heimkosten-Gegenüberstellung', () => {
|
||||
investitionskostenCent: 45_000n,
|
||||
ausbildungsumlageCent: 6_000n,
|
||||
zusatzleistungenCent: 0n,
|
||||
pflegekasseCent: 131_900n,
|
||||
pflegekasseCent: 0n,
|
||||
leistungszuschlagCent: 36_000n,
|
||||
renteCent: 90_000n,
|
||||
renteCent: 130_000n,
|
||||
sonstigeEinkuenfteCent: 0n,
|
||||
sozialhilfeCent: 0n,
|
||||
sozialhilfeCent: 90_000n,
|
||||
eigenmittelCent: 0n,
|
||||
barbetragCent: 15_201n,
|
||||
bekleidungspauschaleCent: 0n,
|
||||
@@ -369,17 +374,48 @@ describe('Heimkosten-Gegenüberstellung', () => {
|
||||
it('weist die Deckungslücke aus', () => {
|
||||
const ergebnis = heimkostenAuswerten(grundfall)
|
||||
|
||||
expect(ergebnis.deckungCent).toBe(257_900n)
|
||||
expect(ergebnis.deckungslueckeCent).toBe(18_301n)
|
||||
expect(ergebnis.deckungCent).toBe(256_000n)
|
||||
expect(ergebnis.deckungslueckeCent).toBe(20_201n)
|
||||
expect(ergebnis.ueberdeckungCent).toBe(0n)
|
||||
expect(ergebnis.gedeckt).toBe(false)
|
||||
})
|
||||
|
||||
it('zählt die Pauschale der Pflegekasse nicht noch einmal als Deckung', () => {
|
||||
// Der einrichtungseinheitliche Eigenanteil ist definitionsgemäß schon
|
||||
// um sie gekürzt (§ 43 Abs. 2 SGB XI). Trägt man sie trotzdem ein,
|
||||
// bleibt die Lücke gleich - und die Anwendung sagt, warum.
|
||||
const mitDoppelzaehlung = heimkostenAuswerten({ ...grundfall, pflegekasseCent: 131_900n })
|
||||
|
||||
expect(mitDoppelzaehlung.deckungCent).toBe(256_000n)
|
||||
expect(mitDoppelzaehlung.deckungslueckeCent).toBe(20_201n)
|
||||
expect(mitDoppelzaehlung.pflegekasseNachrichtlichCent).toBe(131_900n)
|
||||
expect(mitDoppelzaehlung.hinweise.join(' ')).toContain('§ 43 Abs. 2 SGB XI')
|
||||
})
|
||||
|
||||
it('kommt bei der Brutto-Lesart zum selben Ergebnis', () => {
|
||||
// Wer den vollen Pflegesatz erfasst, muss die Pauschale als Deckung
|
||||
// gegenrechnen. Bei konsistenter Erfassung ist die Lücke dieselbe -
|
||||
// nur die beiden Seiten sind um denselben Betrag größer.
|
||||
const brutto = heimkostenAuswerten(
|
||||
{
|
||||
...grundfall,
|
||||
pflegeEigenanteilCent: 120_000n + 131_900n,
|
||||
pflegekasseCent: 131_900n,
|
||||
},
|
||||
'PFLEGESATZ_BRUTTO',
|
||||
)
|
||||
|
||||
expect(brutto.heimkostenCent).toBe(392_900n)
|
||||
expect(brutto.deckungCent).toBe(387_900n)
|
||||
expect(brutto.deckungslueckeCent).toBe(20_201n)
|
||||
expect(brutto.pflegekasseNachrichtlichCent).toBe(0n)
|
||||
})
|
||||
|
||||
it('erkennt eine Überdeckung und weist keine negative Lücke aus', () => {
|
||||
const ergebnis = heimkostenAuswerten({ ...grundfall, renteCent: 200_000n })
|
||||
|
||||
expect(ergebnis.deckungslueckeCent).toBe(0n)
|
||||
expect(ergebnis.ueberdeckungCent).toBe(91_699n)
|
||||
expect(ergebnis.ueberdeckungCent).toBe(49_799n)
|
||||
expect(ergebnis.gedeckt).toBe(true)
|
||||
})
|
||||
|
||||
@@ -388,7 +424,7 @@ describe('Heimkosten-Gegenüberstellung', () => {
|
||||
const kurz = heimkostenAuswerten({ ...grundfall, abwesenheitstage: 3 })
|
||||
expect(kurz.abwesenheit.minderungstage).toBe(0)
|
||||
expect(kurz.abwesenheit.geschaetzteMinderungCent).toBe(0n)
|
||||
expect(kurz.deckungslueckeNachAbwesenheitCent).toBe(18_301n)
|
||||
expect(kurz.deckungslueckeNachAbwesenheitCent).toBe(20_201n)
|
||||
})
|
||||
|
||||
it('schätzt die Minderung bei längerer Abwesenheit und verkleinert die Lücke', () => {
|
||||
@@ -399,10 +435,10 @@ describe('Heimkosten-Gegenüberstellung', () => {
|
||||
|
||||
expect(ergebnis.abwesenheit.minderungstage).toBe(7)
|
||||
expect(ergebnis.abwesenheit.geschaetzteMinderungCent).toBe(11_854n)
|
||||
expect(ergebnis.deckungslueckeNachAbwesenheitCent).toBe(6_447n)
|
||||
expect(ergebnis.deckungslueckeNachAbwesenheitCent).toBe(8_347n)
|
||||
// Die erfasste Lücke bleibt davon unberührt - maßgeblich ist die
|
||||
// Heimrechnung, die Schätzung steht nur daneben.
|
||||
expect(ergebnis.deckungslueckeCent).toBe(18_301n)
|
||||
expect(ergebnis.deckungslueckeCent).toBe(20_201n)
|
||||
})
|
||||
|
||||
it('lässt die Investitionskosten bei Abwesenheit außen vor', () => {
|
||||
@@ -447,7 +483,7 @@ describe('Heimkosten-Gegenüberstellung', () => {
|
||||
const verlauf = jahresverlaufBilden(2026, monate)
|
||||
|
||||
expect(verlauf.monate.map((m) => m.monat)).toEqual([1, 2, 3])
|
||||
expect(verlauf.summeDeckungslueckeCent).toBe(18_301n + 58_301n + 18_301n)
|
||||
expect(verlauf.summeDeckungslueckeCent).toBe(20_201n + 100_201n + 20_201n)
|
||||
expect(verlauf.groessteLuecke?.monat).toBe(2)
|
||||
})
|
||||
})
|
||||
@@ -599,40 +635,3 @@ describe('Katalog weiterer Leistungen', () => {
|
||||
expect(offen).toHaveLength(LEISTUNGSKATALOG.length - 1)
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Beträge
|
||||
// =============================================================================
|
||||
|
||||
describe('Beträge aus Formularfeldern', () => {
|
||||
it('liest die deutsche Schreibweise verlustfrei in Cent', () => {
|
||||
expect(betragZuCent('1.234,56')).toBe(123_456n)
|
||||
expect(betragZuCent('1234,56')).toBe(123_456n)
|
||||
expect(betragZuCent('1234')).toBe(123_400n)
|
||||
expect(betragZuCent('0,01')).toBe(1n)
|
||||
expect(betragZuCent('1.234.567,89')).toBe(123_456_789n)
|
||||
expect(betragZuCent('12,5')).toBe(1_250n)
|
||||
})
|
||||
|
||||
it('kommt mit Euro-Zeichen, Leerzeichen und Vorzeichen zurecht', () => {
|
||||
expect(betragZuCent(' 1.234,56 € ')).toBe(123_456n)
|
||||
expect(betragZuCent('-45,00')).toBe(-4_500n)
|
||||
})
|
||||
|
||||
it('behandelt Leeres als „keine Angabe“, nicht als null Euro', () => {
|
||||
expect(betragZuCent('')).toBeNull()
|
||||
expect(betragZuCent(null)).toBeNull()
|
||||
expect(betragZuCent(' ')).toBeNull()
|
||||
})
|
||||
|
||||
it('weist Unsinn zurück, statt still zu raten', () => {
|
||||
expect(betragZuCent('abc')).toBeNull()
|
||||
expect(betragZuCent('12,345')).toBeNull()
|
||||
})
|
||||
|
||||
it('rechnet für die Vorbelegung zurück', () => {
|
||||
expect(centZuEingabe(123_456n)).toBe('1234,56')
|
||||
expect(centZuEingabe(5n)).toBe('0,05')
|
||||
expect(centZuEingabe(null)).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user