feat: Stammdaten, Ersteinrichtung, Zweitfaktor und Protokollansicht
Damit ist Etappe 1 fachlich vollstaendig. Ersteinrichtung in drei Schritten, bewusst ausserhalb des Anwendungsrahmens: der setzt Benutzer, zweiten Faktor UND eine betreute Person voraus - beim allerersten Start gibt es nichts davon. Die Aktion fuer den ersten Zugang sperrt sich selbst, sobald ein Benutzer existiert. Zweiter Faktor: Das Geheimnis wird zuerst nur abgelegt, ohne totpAktiviertAm. Erst ein echter Code aus der App schaltet ihn scharf. Wer sich beim Abtippen vertut oder die falsche App nimmt, wuerde sich sonst dauerhaft aussperren. Erst danach gibt es die Wiederherstellungscodes - einmal angezeigt, danach nur noch als Hash. Betreuungsjahr (src/lib/stammdaten/betreuungsjahr.ts): laeuft ab dem Tag der Bestellung, nicht ab dem Kalenderjahr. Schrittweise vorwaerts gerechnet statt ueber eine Differenz, damit Schaltjahre und der 29. Februar von selbst stimmen. Daran haengen Jahresbericht, Rechnungslegung und die Ausschlussfrist der Aufwandspauschale. Aendert sich das Bestellungsdatum, werden die Pflichtfristen neu abgeleitet - ueber einen dynamischen Import, damit die Stammdaten auch dann speicherbar bleiben, wenn das Fristenmodul fehlt. Protokollansicht zeigt je Eintrag die geaenderten Felder als alt -> neu. Die Aenderungen liegen verschluesselt, weil dort Diagnosen und Kontostaende stehen koennen. Seed legt bewusst keine echten Personendaten an, nur den ersten Zugang. Mit SEED_DEMO=true kommt ein vollstaendiger Beispielfall dazu - Erika Musterfrau, COPD GOLD III, Pflegegrad 3, Heimeinzug Januar 2026, leerstehendes Haus, zwei Versicherungen, laufender Antrag beim Bezirk mit acht Nachforderungen. Nur ausserhalb der Produktion. Docker Compose ohne Reverse Proxy - der ist auf dem Zielserver vorhanden. Die Datenbank hat keine Portfreigabe und ist nur ueber das interne Netz erreichbar; die Anwendung horcht auf 127.0.0.1. Etappe: 1 Phase: Fundament
This commit is contained in:
@@ -0,0 +1,393 @@
|
||||
import type { GenehmigungStatus } from '@prisma/client'
|
||||
|
||||
/**
|
||||
* Die Ablaufkette für genehmigungspflichtige Vorgänge.
|
||||
*
|
||||
* Warum eine feste Kette? Weil die Reihenfolge im Betreuungsrecht keine
|
||||
* Geschmacksfrage ist. Die Genehmigung des Betreuungsgerichts muss VOR dem
|
||||
* Rechtsgeschäft vorliegen (§ 1858 BGB); ein ohne Genehmigung geschlossener
|
||||
* Vertrag ist schwebend unwirksam, und der Betreuer haftet persönlich, wenn
|
||||
* daraus ein Schaden entsteht. Eine Oberfläche, in der man den Vollzug
|
||||
* einfach anklicken kann, wäre also nicht nur unordentlich, sondern
|
||||
* gefährlich.
|
||||
*
|
||||
* Deshalb steht die Regel hier in der Fachlogik und wird zusätzlich in der
|
||||
* Server Action geprüft - nicht nur im UI. Das UI kann man umgehen.
|
||||
*/
|
||||
|
||||
export const GENEHMIGUNGSKETTE = [
|
||||
'GEPLANT',
|
||||
'MITGETEILT',
|
||||
'BEANTRAGT',
|
||||
'ANGEHOERT',
|
||||
'ERTEILT',
|
||||
'RECHTSKRAEFTIG',
|
||||
'VOLLZOGEN',
|
||||
] as const satisfies readonly GenehmigungStatus[]
|
||||
|
||||
export type Kettenstatus = (typeof GENEHMIGUNGSKETTE)[number]
|
||||
|
||||
/** Seitenausgang: Das Gericht hat die Genehmigung versagt. */
|
||||
export const SEITENAUSGANG: GenehmigungStatus = 'VERSAGT'
|
||||
|
||||
/**
|
||||
* Der stehende Warnhinweis auf jeder genehmigungspflichtigen Ansicht.
|
||||
* Ein Satz, der über allem steht, was hier passiert.
|
||||
*/
|
||||
export const GENEHMIGUNG_WARNUNG =
|
||||
'Die Genehmigung muss vor dem Rechtsgeschäft vorliegen (§ 1858 BGB). ' +
|
||||
'Bitte mit dem Rechtspfleger abstimmen.'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Beschriftungen und Stufen
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export type Stufe = {
|
||||
status: GenehmigungStatus
|
||||
beschriftung: string
|
||||
erklaerung: string
|
||||
/** Feld im Datensatz, in dem das Datum dieser Stufe steht. */
|
||||
datumsfeld:
|
||||
| 'mitteilungAm'
|
||||
| 'antragAm'
|
||||
| 'anhoerungAm'
|
||||
| 'beschlussAm'
|
||||
| 'rechtskraftAm'
|
||||
| 'vollzugAm'
|
||||
| null
|
||||
}
|
||||
|
||||
export const GENEHMIGUNG_STUFEN: Stufe[] = [
|
||||
{
|
||||
status: 'GEPLANT',
|
||||
beschriftung: 'Geplant',
|
||||
erklaerung:
|
||||
'Der Genehmigungsbedarf ist erkannt, beim Gericht ist noch nichts eingegangen. ' +
|
||||
'Bis hierher darf noch nichts unterschrieben werden.',
|
||||
datumsfeld: null,
|
||||
},
|
||||
{
|
||||
status: 'MITGETEILT',
|
||||
beschriftung: 'Dem Gericht mitgeteilt',
|
||||
erklaerung:
|
||||
'Die Absicht ist dem Betreuungsgericht angezeigt. Bei der Aufgabe von Wohnraum ist ' +
|
||||
'diese Mitteilung eigenständig vorgeschrieben (§ 1833 Abs. 1 BGB) und geht der ' +
|
||||
'Kündigung voraus.',
|
||||
datumsfeld: 'mitteilungAm',
|
||||
},
|
||||
{
|
||||
status: 'BEANTRAGT',
|
||||
beschriftung: 'Genehmigung beantragt',
|
||||
erklaerung:
|
||||
'Der Antrag liegt beim Gericht, mit Vertragsentwurf und Begründung. Ab hier läuft ' +
|
||||
'das Verfahren beim Rechtspfleger.',
|
||||
datumsfeld: 'antragAm',
|
||||
},
|
||||
{
|
||||
status: 'ANGEHOERT',
|
||||
beschriftung: 'Anhörung erfolgt',
|
||||
erklaerung:
|
||||
'Die betreute Person und gegebenenfalls ein Verfahrenspfleger wurden angehört. ' +
|
||||
'Ohne Anhörung ergeht kein Beschluss.',
|
||||
datumsfeld: 'anhoerungAm',
|
||||
},
|
||||
{
|
||||
status: 'ERTEILT',
|
||||
beschriftung: 'Beschluss erteilt',
|
||||
erklaerung:
|
||||
'Das Gericht hat die Genehmigung erteilt. Der Beschluss ist damit noch nicht ' +
|
||||
'rechtskräftig - die Beschwerdefrist läuft erst.',
|
||||
datumsfeld: 'beschlussAm',
|
||||
},
|
||||
{
|
||||
status: 'RECHTSKRAEFTIG',
|
||||
beschriftung: 'Rechtskräftig',
|
||||
erklaerung:
|
||||
'Die Beschwerdefrist ist abgelaufen. Jetzt eine Ausfertigung mit Rechtskraftvermerk ' +
|
||||
'anfordern - der Vertragspartner braucht genau dieses Papier (§ 1856 BGB).',
|
||||
datumsfeld: 'rechtskraftAm',
|
||||
},
|
||||
{
|
||||
status: 'VOLLZOGEN',
|
||||
beschriftung: 'Vollzogen',
|
||||
erklaerung:
|
||||
'Das Rechtsgeschäft ist ausgeführt. Erst möglich, wenn der Beschluss als Dokument ' +
|
||||
'hinterlegt ist - ohne Beleg gibt es gegenüber Gericht und Miterben keinen Nachweis.',
|
||||
datumsfeld: 'vollzugAm',
|
||||
},
|
||||
]
|
||||
|
||||
export const GENEHMIGUNG_STATUS_BESCHRIFTUNG: Record<GenehmigungStatus, string> = {
|
||||
GEPLANT: 'Geplant',
|
||||
MITGETEILT: 'Dem Gericht mitgeteilt',
|
||||
BEANTRAGT: 'Genehmigung beantragt',
|
||||
ANGEHOERT: 'Anhörung erfolgt',
|
||||
ERTEILT: 'Beschluss erteilt',
|
||||
VERSAGT: 'Versagt',
|
||||
RECHTSKRAEFTIG: 'Rechtskräftig',
|
||||
VOLLZOGEN: 'Vollzogen',
|
||||
}
|
||||
|
||||
/** Position in der Kette, -1 für den Seitenausgang VERSAGT. */
|
||||
export function stufeVon(status: GenehmigungStatus): number {
|
||||
return (GENEHMIGUNGSKETTE as readonly GenehmigungStatus[]).indexOf(status)
|
||||
}
|
||||
|
||||
export function istKettenstatus(status: GenehmigungStatus): status is Kettenstatus {
|
||||
return stufeVon(status) >= 0
|
||||
}
|
||||
|
||||
/** Der reguläre nächste Schritt, oder null am Ende der Kette. */
|
||||
export function naechsterStatus(status: GenehmigungStatus): GenehmigungStatus | null {
|
||||
const stufe = stufeVon(status)
|
||||
if (stufe < 0) return null
|
||||
return GENEHMIGUNGSKETTE[stufe + 1] ?? null
|
||||
}
|
||||
|
||||
/** Das Datumsfeld, das beim Erreichen eines Status gesetzt wird. */
|
||||
export function datumsfeldFuer(status: GenehmigungStatus): Stufe['datumsfeld'] {
|
||||
return GENEHMIGUNG_STUFEN.find((s) => s.status === status)?.datumsfeld ?? null
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Die Regel
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/** Das Nötigste, was zur Prüfung eines Statuswechsels bekannt sein muss. */
|
||||
export type PruefbareGenehmigung = {
|
||||
status: GenehmigungStatus
|
||||
beschlussDokumentId?: string | null
|
||||
}
|
||||
|
||||
export type Wechselpruefung = {
|
||||
erlaubt: boolean
|
||||
/** Warum nicht - im Klartext, direkt anzeigbar. */
|
||||
grund?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Darf die Genehmigung in diesen Status wechseln?
|
||||
*
|
||||
* Die Regeln:
|
||||
*
|
||||
* 1. Vorwärts immer nur eine Stufe. Wer von BEANTRAGT direkt auf VOLLZOGEN
|
||||
* springt, überspringt Anhörung, Beschluss und Rechtskraft - genau der
|
||||
* Fehler, den diese Kette verhindern soll.
|
||||
* 2. Eine Stufe zurück ist als Korrektur erlaubt (verklickt, Beschluss
|
||||
* doch noch nicht da).
|
||||
* 3. VERSAGT ist der Seitenausgang: erreichbar, solange beim Gericht etwas
|
||||
* anhängig und noch nichts rechtskräftig ist. Von dort führt der Weg
|
||||
* zurück auf GEPLANT - ein geänderter Vertrag kann neu vorgelegt werden.
|
||||
* 4. VOLLZOGEN ist endgültig. Ein ausgeführtes Rechtsgeschäft lässt sich
|
||||
* nicht per Auswahlfeld zurücknehmen.
|
||||
* 5. **VOLLZOGEN nur mit hinterlegtem Beschlussdokument.** Das ist die
|
||||
* Kernregel: Der Vollzug ohne Nachweis der Genehmigung ist genau der
|
||||
* Fall, in dem der Betreuer nach § 1858 BGB persönlich haftet. Diese
|
||||
* Prüfung steht hier UND in der Server Action.
|
||||
*/
|
||||
export function darfStatusWechseln(
|
||||
genehmigung: PruefbareGenehmigung,
|
||||
neuerStatus: GenehmigungStatus,
|
||||
): Wechselpruefung {
|
||||
const alt = genehmigung.status
|
||||
|
||||
if (alt === neuerStatus) {
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund: `Die Genehmigung steht bereits auf „${GENEHMIGUNG_STATUS_BESCHRIFTUNG[alt]}“.`,
|
||||
}
|
||||
}
|
||||
|
||||
if (alt === 'VOLLZOGEN') {
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
'Ein vollzogenes Rechtsgeschäft lässt sich hier nicht zurücknehmen. ' +
|
||||
'Wenn etwas nicht stimmt, gehört das ins Protokoll und ans Gericht.',
|
||||
}
|
||||
}
|
||||
|
||||
// Regel 5 zuerst: Sie gilt unabhaengig davon, aus welcher Stufe der
|
||||
// Wechsel kommt, und ist die Regel, an der es am haeufigsten scheitert.
|
||||
if (neuerStatus === 'VOLLZOGEN' && !genehmigung.beschlussDokumentId) {
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
'Ohne hinterlegten Genehmigungsbeschluss kann der Vollzug nicht eingetragen werden. ' +
|
||||
'Bitte zuerst den Beschluss als Dokument hochladen und mit dieser Genehmigung ' +
|
||||
'verknüpfen. ' +
|
||||
GENEHMIGUNG_WARNUNG,
|
||||
}
|
||||
}
|
||||
|
||||
if (neuerStatus === 'VERSAGT') {
|
||||
const versagbar: GenehmigungStatus[] = ['MITGETEILT', 'BEANTRAGT', 'ANGEHOERT', 'ERTEILT']
|
||||
if (!versagbar.includes(alt)) {
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
'Versagen kann das Gericht nur, solange etwas anhängig und noch nichts ' +
|
||||
'rechtskräftig ist.',
|
||||
}
|
||||
}
|
||||
return { erlaubt: true }
|
||||
}
|
||||
|
||||
if (alt === 'VERSAGT') {
|
||||
if (neuerStatus !== 'GEPLANT') {
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
'Nach einer Versagung fängt das Verfahren wieder bei „Geplant“ an. ' +
|
||||
'Ein geänderter Vertragsentwurf kann dem Gericht erneut vorgelegt werden.',
|
||||
}
|
||||
}
|
||||
return { erlaubt: true }
|
||||
}
|
||||
|
||||
const stufeAlt = stufeVon(alt)
|
||||
const stufeNeu = stufeVon(neuerStatus)
|
||||
if (stufeAlt < 0 || stufeNeu < 0) {
|
||||
return { erlaubt: false, grund: 'Dieser Statuswechsel ist nicht vorgesehen.' }
|
||||
}
|
||||
|
||||
const abstand = stufeNeu - stufeAlt
|
||||
if (abstand === 1) return { erlaubt: true }
|
||||
if (abstand === -1) return { erlaubt: true } // Korrektur
|
||||
|
||||
if (abstand > 1) {
|
||||
const uebersprungen = GENEHMIGUNGSKETTE.slice(stufeAlt + 1, stufeNeu)
|
||||
.map((s) => GENEHMIGUNG_STATUS_BESCHRIFTUNG[s])
|
||||
.join(', ')
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
`Dieser Schritt überspringt: ${uebersprungen}. Die Kette wird der Reihe nach ` +
|
||||
`durchlaufen. ` +
|
||||
GENEHMIGUNG_WARNUNG,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
erlaubt: false,
|
||||
grund:
|
||||
'Es lässt sich immer nur eine Stufe zurückgehen. Für größere Korrekturen bitte den ' +
|
||||
'Verlauf im Vorgang festhalten.',
|
||||
}
|
||||
}
|
||||
|
||||
/** Alle Status, in die von hier aus gewechselt werden darf - für das Auswahlfeld. */
|
||||
export function moeglicheStatusWechsel(genehmigung: PruefbareGenehmigung): GenehmigungStatus[] {
|
||||
const alle: GenehmigungStatus[] = [...GENEHMIGUNGSKETTE, SEITENAUSGANG]
|
||||
return alle.filter((s) => darfStatusWechseln(genehmigung, s).erlaubt)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rechtsgrundlagen
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export type Rechtsgrundlage = {
|
||||
/** Genau so, wie es im Feld Genehmigung.rechtsgrundlage steht. */
|
||||
wert: string
|
||||
kurz: string
|
||||
/** Was steckt dahinter - in normalen Worten. */
|
||||
erklaerung: string
|
||||
beispiele: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Die wählbaren Rechtsgrundlagen mit Klartext-Erklärung.
|
||||
*
|
||||
* Das Feld in der Datenbank ist bewusst Freitext, damit auch seltene
|
||||
* Tatbestände erfasst werden können. Diese Liste ist die Auswahlhilfe für
|
||||
* den Alltag - jede Zeile bekommt in der Oberfläche einen
|
||||
* <Rechtshinweis>, weil hier Paragraphen stehen.
|
||||
*
|
||||
* Die Zuordnung eines konkreten Geschäfts zu einer Vorschrift ist im
|
||||
* Zweifel Sache des Rechtspflegers, nicht dieser Liste.
|
||||
*/
|
||||
export const RECHTSGRUNDLAGEN: Rechtsgrundlage[] = [
|
||||
{
|
||||
wert: '§ 1850 BGB',
|
||||
kurz: 'Grundstücksgeschäfte',
|
||||
erklaerung:
|
||||
'Alles, was ein Grundstück betrifft: Verkauf, Kauf, Belastung mit Grundschuld oder ' +
|
||||
'Hypothek, Erbbaurecht - und schon die Verpflichtung dazu. Der Vertrag wird erst ' +
|
||||
'wirksam, wenn die rechtskräftige Genehmigung dem Vertragspartner vorgelegt wird.',
|
||||
beispiele: [
|
||||
'Verkauf des Hausgrundstücks',
|
||||
'Grundschuld für ein Darlehen nach § 91 SGB XII',
|
||||
'Bestellung eines Wohnrechts',
|
||||
],
|
||||
},
|
||||
{
|
||||
wert: '§ 1833 BGB',
|
||||
kurz: 'Aufgabe von Wohnraum',
|
||||
erklaerung:
|
||||
'Die Aufgabe der Wohnung der betreuten Person ist dem Gericht mitzuteilen und ' +
|
||||
'genehmigungsbedürftig. Die Mitteilung geht der Kündigung voraus - nicht umgekehrt. ' +
|
||||
'Diese Vorschrift gilt auch für befreite Betreuer.',
|
||||
beispiele: [
|
||||
'Kündigung der Mietwohnung nach dem Heimeinzug',
|
||||
'Vermietung der bisher selbst bewohnten Wohnung',
|
||||
'Auflösung des Haushalts',
|
||||
],
|
||||
},
|
||||
{
|
||||
wert: '§ 1854 BGB',
|
||||
kurz: 'Erbschaftsangelegenheiten und weitere Geschäfte',
|
||||
erklaerung:
|
||||
'Sammelvorschrift für Geschäfte, die für die betreute Person besonders folgenreich ' +
|
||||
'sind - allen voran das Erbrecht. Wer eine Erbschaft ausschlägt, gibt sie endgültig ' +
|
||||
'auf; das prüft das Gericht mit.',
|
||||
beispiele: [
|
||||
'Ausschlagung einer Erbschaft',
|
||||
'Erbauseinandersetzung mit Miterben',
|
||||
'Verzicht auf einen Pflichtteil',
|
||||
],
|
||||
},
|
||||
{
|
||||
wert: '§ 1851 BGB',
|
||||
kurz: 'Kreditaufnahme und Wertpapiergeschäfte',
|
||||
erklaerung:
|
||||
'Geld auf den Kredit der betreuten Person aufnehmen und Geschäfte mit Wertpapieren. ' +
|
||||
'Beides kann Vermögen schnell und dauerhaft mindern - deshalb schaut das Gericht ' +
|
||||
'darauf.',
|
||||
beispiele: [
|
||||
'Aufnahme eines Darlehens',
|
||||
'Verkauf eines Wertpapierdepots',
|
||||
'Übernahme einer Bürgschaft',
|
||||
],
|
||||
},
|
||||
{
|
||||
wert: '§ 1849 BGB',
|
||||
kurz: 'Verfügungen über angelegtes Geld und Forderungen',
|
||||
erklaerung:
|
||||
'Betrifft Guthaben, die mit Sperrvermerk angelegt sind, und Forderungen der ' +
|
||||
'betreuten Person: Abheben über den Freibetrag hinaus, Abtreten, Erlassen oder ' +
|
||||
'Kündigen einer Forderung.',
|
||||
beispiele: [
|
||||
'Auflösung eines gesperrten Sparguthabens',
|
||||
'Verzicht auf eine Forderung gegen einen Angehörigen',
|
||||
'Kündigung einer festverzinslichen Anlage über dem Freibetrag',
|
||||
],
|
||||
},
|
||||
{
|
||||
wert: '§ 1859 BGB',
|
||||
kurz: 'Befreite Betreuung - wann die Genehmigung entfällt',
|
||||
erklaerung:
|
||||
'Wer als Ehegatte oder als Verwandter in gerader Linie betreut, ist von einem Teil ' +
|
||||
'der Genehmigungserfordernisse und von den Anlagevorschriften befreit. Nicht befreit ' +
|
||||
'ist man von der Genehmigung für Grundstücksgeschäfte (§ 1850 BGB) und von der ' +
|
||||
'Aufgabe von Wohnraum (§ 1833 BGB). Der Umfang der Befreiung steht im ' +
|
||||
'Bestellungsbeschluss - dort nachlesen, nicht raten.',
|
||||
beispiele: [
|
||||
'Prüfung, ob für dieses Geschäft überhaupt eine Genehmigung nötig ist',
|
||||
'Rückfrage beim Rechtspfleger zum Umfang der Befreiung',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export function rechtsgrundlageFinden(wert: string): Rechtsgrundlage | undefined {
|
||||
return RECHTSGRUNDLAGEN.find((r) => r.wert === wert)
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import { differenceInCalendarDays } from 'date-fns'
|
||||
import { formatDatum } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
* Sachstandsanfrage.
|
||||
*
|
||||
* Der häufigste Grund, warum ein Vorgang liegen bleibt, ist nicht Faulheit,
|
||||
* sondern Warten: Der Antrag ist raus, und dann passiert monatelang nichts.
|
||||
* Nachfassen hilft - aber nur, wenn man dabei sagt, worauf man sich bezieht.
|
||||
* Deshalb erzeugt diese Funktion einen fertigen Text mit Aktenzeichen,
|
||||
* Gegenstelle und dem Datum des letzten Kontakts.
|
||||
*
|
||||
* Bewusst Freitext zum Kopieren und kein PDF: Ich schreibe die meisten
|
||||
* dieser Nachrichten per E-Mail oder aus einem Behördenportal heraus. Das
|
||||
* PDF-Anschreiben kommt in Etappe 7 dazu.
|
||||
*
|
||||
* Rein und ohne Datenbank, damit der Wortlaut im Test prüfbar bleibt.
|
||||
*/
|
||||
|
||||
export type SachstandsanfrageEingabe = {
|
||||
vorgangTitel: string
|
||||
/** Behörde oder Stelle, die am Zug ist. */
|
||||
gegenstelle: string | null
|
||||
/** Aktenzeichen, unter dem die Gegenstelle den Vorgang führt. */
|
||||
aktenzeichen: string | null
|
||||
/** Wann wurde zuletzt geschrieben oder gesprochen? */
|
||||
letzterKontaktAm: Date | null
|
||||
betreute: {
|
||||
vorname: string
|
||||
nachname: string
|
||||
geburtsdatum: Date | null
|
||||
}
|
||||
betreuer: {
|
||||
name: string
|
||||
/** Aktenzeichen des Betreuungsgerichts, belegt die Vertretungsmacht. */
|
||||
aktenzeichenGericht?: string | null
|
||||
betreuungsgericht?: string | null
|
||||
}
|
||||
/** Ansprechpartner bei der Gegenstelle, wenn bekannt. */
|
||||
ansprechpartner?: string | null
|
||||
/** Für den Test überschreibbar. */
|
||||
heute?: Date
|
||||
}
|
||||
|
||||
export type Sachstandsanfrage = {
|
||||
betreff: string
|
||||
/** Vollständiger Text zum Kopieren, inklusive Betreffzeile. */
|
||||
text: string
|
||||
/** Tage seit dem letzten Kontakt, null wenn keiner erfasst ist. */
|
||||
tageSeitKontakt: number | null
|
||||
}
|
||||
|
||||
export function sachstandsanfrageErzeugen(
|
||||
eingabe: SachstandsanfrageEingabe,
|
||||
): Sachstandsanfrage {
|
||||
const heute = eingabe.heute ?? new Date()
|
||||
const name = `${eingabe.betreute.vorname} ${eingabe.betreute.nachname}`.trim()
|
||||
|
||||
const tageSeitKontakt = eingabe.letzterKontaktAm
|
||||
? differenceInCalendarDays(heute, eingabe.letzterKontaktAm)
|
||||
: null
|
||||
|
||||
const betreff =
|
||||
[
|
||||
`Sachstandsanfrage: ${eingabe.vorgangTitel}`,
|
||||
`${name}${eingabe.betreute.geburtsdatum ? `, geb. ${formatDatum(eingabe.betreute.geburtsdatum)}` : ''}`,
|
||||
eingabe.aktenzeichen ? `Az. ${eingabe.aktenzeichen}` : null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' · ')
|
||||
|
||||
const anrede = eingabe.ansprechpartner
|
||||
? `Sehr geehrte(r) ${eingabe.ansprechpartner},`
|
||||
: 'Sehr geehrte Damen und Herren,'
|
||||
|
||||
const zeilen: string[] = []
|
||||
|
||||
if (eingabe.gegenstelle) zeilen.push(eingabe.gegenstelle, '')
|
||||
zeilen.push(formatDatum(heute), '')
|
||||
zeilen.push(`Betreff: ${betreff}`, '')
|
||||
zeilen.push(anrede, '')
|
||||
|
||||
// Kern: Wer schreibt, in welcher Eigenschaft, worum ging es zuletzt.
|
||||
const eigenschaft = eingabe.betreuer.aktenzeichenGericht
|
||||
? `als rechtlicher Betreuer von ${name} (Betreuungsgericht${
|
||||
eingabe.betreuer.betreuungsgericht ? ` ${eingabe.betreuer.betreuungsgericht}` : ''
|
||||
}, Az. ${eingabe.betreuer.aktenzeichenGericht})`
|
||||
: `als rechtlicher Betreuer von ${name}`
|
||||
|
||||
zeilen.push(
|
||||
`ich wende mich ${eigenschaft} in der oben genannten Angelegenheit ` +
|
||||
`„${eingabe.vorgangTitel}“ an Sie.`,
|
||||
)
|
||||
zeilen.push('')
|
||||
|
||||
if (eingabe.letzterKontaktAm && tageSeitKontakt !== null) {
|
||||
zeilen.push(
|
||||
`Zuletzt standen wir am ${formatDatum(eingabe.letzterKontaktAm)} in dieser Sache in ` +
|
||||
`Kontakt; das ist inzwischen ${tageSeitKontakt} Tage her. Eine Rückmeldung ist ` +
|
||||
`seitdem hier nicht eingegangen.`,
|
||||
)
|
||||
} else {
|
||||
zeilen.push(
|
||||
'Eine Rückmeldung in dieser Sache ist hier bisher nicht eingegangen.',
|
||||
)
|
||||
}
|
||||
zeilen.push('')
|
||||
|
||||
zeilen.push(
|
||||
'Ich bitte Sie um eine kurze Mitteilung zum Sachstand: ob die Unterlagen vollständig ' +
|
||||
'vorliegen, wer die Angelegenheit bearbeitet und bis wann mit einer Entscheidung zu ' +
|
||||
'rechnen ist.',
|
||||
)
|
||||
zeilen.push('')
|
||||
zeilen.push(
|
||||
'Sollten Unterlagen fehlen, reiche ich sie kurzfristig nach - bitte teilen Sie mir in ' +
|
||||
'diesem Fall mit, worum es genau geht.',
|
||||
)
|
||||
zeilen.push('')
|
||||
zeilen.push('Vielen Dank für Ihre Mühe.', '')
|
||||
zeilen.push('Mit freundlichen Grüßen', '', eingabe.betreuer.name, 'Rechtlicher Betreuer')
|
||||
|
||||
return {
|
||||
betreff,
|
||||
text: zeilen.join('\n'),
|
||||
tageSeitKontakt,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ab wann ist Nachfassen angebracht?
|
||||
*
|
||||
* Sechs Wochen sind die Erfahrungsgröße: kürzer wirkt drängelnd, länger
|
||||
* verschenkt Zeit. Die harte Grenze steht woanders - nach sechs Monaten
|
||||
* ohne Bescheid ist die Untätigkeitsklage nach § 88 SGG möglich.
|
||||
*/
|
||||
export const NACHFASSEN_AB_TAGEN = 42
|
||||
|
||||
export function nachfassenFaellig(
|
||||
letzterKontaktAm: Date | null,
|
||||
heute: Date = new Date(),
|
||||
): boolean {
|
||||
if (!letzterKontaktAm) return true
|
||||
return differenceInCalendarDays(heute, letzterKontaktAm) >= NACHFASSEN_AB_TAGEN
|
||||
}
|
||||
@@ -0,0 +1,785 @@
|
||||
import type { VorgangKategorie } from '@prisma/client'
|
||||
import { addDays } from 'date-fns'
|
||||
|
||||
/**
|
||||
* Vorgangs-Vorlagen.
|
||||
*
|
||||
* Warum Vorlagen? Die typischen Vorgänge einer rechtlichen Betreuung sind
|
||||
* immer dieselben Handgriffe in immer derselben Reihenfolge - und die
|
||||
* Reihenfolge ist der eigentliche Wert. Wer die Wohnung kündigt, bevor die
|
||||
* Genehmigung da ist, hat ein Problem, das sich nicht mehr reparieren
|
||||
* lässt. Deshalb steht in jeder Vorlage nicht nur, WAS zu tun ist, sondern
|
||||
* auch, in welcher Reihenfolge - und die genehmigungspflichtigen Schritte
|
||||
* stehen vor dem Rechtsgeschäft, nicht danach.
|
||||
*
|
||||
* Die Vorlage ist eine Starthilfe, kein Zwang: Aufgaben lassen sich nach
|
||||
* dem Anlegen ergänzen, streichen und umdatieren.
|
||||
*
|
||||
* Der Vertrag dieser Datei steht in docs/SCHNITTSTELLEN.md, Abschnitt 6.
|
||||
*/
|
||||
|
||||
export type Vorlagenaufgabe = {
|
||||
titel: string
|
||||
beschreibung?: string
|
||||
/** Tage ab Anlegen des Vorgangs, bis die Aufgabe fällig ist. */
|
||||
tageBisFaellig?: number
|
||||
}
|
||||
|
||||
export type Vorlagenfrist = {
|
||||
titel: string
|
||||
tageBisFaellig: number
|
||||
rechtsgrundlage?: string
|
||||
}
|
||||
|
||||
export type Vorgangsvorlage = {
|
||||
schluessel: string
|
||||
titel: string
|
||||
kategorie: VorgangKategorie
|
||||
beschreibung: string
|
||||
genehmigungspflichtig: boolean
|
||||
rechtsgrundlage?: string
|
||||
/** Vorbefüllte Aufgabenliste, in der Reihenfolge der Abarbeitung. */
|
||||
aufgaben: Vorlagenaufgabe[]
|
||||
/** Fristen, die mit angelegt werden. */
|
||||
fristen?: Vorlagenfrist[]
|
||||
}
|
||||
|
||||
export const VORLAGEN: Vorgangsvorlage[] = [
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'heimeinzug',
|
||||
titel: 'Einzug ins Pflegeheim',
|
||||
kategorie: 'HEIM_PFLEGE',
|
||||
beschreibung:
|
||||
'Alles, was nach dem Einzug in eine vollstationäre Einrichtung zu erledigen ist: ' +
|
||||
'Vertrag prüfen, Meldungen absetzen, Versicherungen und laufende Kosten anpassen.',
|
||||
genehmigungspflichtig: false,
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Heimvertrag prüfen und gegenzeichnen',
|
||||
beschreibung:
|
||||
'Entgeltbestandteile (Pflege, Unterkunft/Verpflegung, Investitionskosten, ' +
|
||||
'Ausbildungsumlage) einzeln aufschlüsseln lassen, Kündigungsfristen und die ' +
|
||||
'Regelung zum Sterbefall nachlesen. Erst danach unterschreiben.',
|
||||
tageBisFaellig: 7,
|
||||
},
|
||||
{
|
||||
titel: 'Ummeldung beim Einwohnermeldeamt',
|
||||
beschreibung:
|
||||
'Das Heim ist die neue Hauptwohnung. Die Meldefrist beträgt zwei Wochen ab Einzug.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Krankenkasse und Pflegekasse über den Einzug informieren',
|
||||
beschreibung:
|
||||
'Die Pflegekasse zahlt den Leistungsbetrag nach § 43 SGB XI erst ab Meldung an die ' +
|
||||
'Einrichtung. Bestätigung der Kasse zu den Akten nehmen.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Rentenversicherung: neue Anschrift und Zahlweg melden',
|
||||
beschreibung:
|
||||
'Anschrift und - falls sich das Konto ändert - die Bankverbindung melden. ' +
|
||||
'Betreuerausweis in Kopie beilegen.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Nachsendeauftrag bei der Post einrichten',
|
||||
beschreibung:
|
||||
'Läuft in der Regel 6 oder 12 Monate. Als Empfänger die eigene Anschrift wählen, ' +
|
||||
'nicht das Heim - Post gehört in die Akte.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Hausrat- und Haftpflichtversicherung anpassen',
|
||||
beschreibung:
|
||||
'Der Hausrat im Heimzimmer ist meist über die Einrichtung nicht gedeckt. ' +
|
||||
'Hausratsumme an den tatsächlichen Bestand anpassen, Privathaftpflicht behalten - ' +
|
||||
'sie ist im Heim wichtiger, nicht unwichtiger.',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
{
|
||||
titel: 'Rundfunkbeitrag: Befreiung oder Ummeldung beantragen',
|
||||
beschreibung:
|
||||
'Bei Bezug von Hilfe zur Pflege oder Grundsicherung ist eine Befreiung möglich; ' +
|
||||
'sonst wird die alte Wohnung abgemeldet und das Heimzimmer gilt in der Regel ' +
|
||||
'nicht als eigene Wohnung.',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
{
|
||||
titel: 'Verwahrgeldkonto im Heim einrichten und Höchstbetrag festlegen',
|
||||
beschreibung:
|
||||
'Barmittel für Friseur, Fußpflege und Einkäufe. Betrag klein halten und die ' +
|
||||
'Abrechnung des Heims monatlich anfordern - das Verwahrgeld gehört in die ' +
|
||||
'Rechnungslegung (§ 1865 BGB).',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Heimabrechnung und Verwahrgeldkonto zum ersten Mal prüfen',
|
||||
tageBisFaellig: 60,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'antrag-hilfe-zur-pflege',
|
||||
titel: 'Antrag auf Hilfe zur Pflege',
|
||||
kategorie: 'SOZIALHILFE',
|
||||
beschreibung:
|
||||
'Antrag auf Hilfe zur Pflege in einer stationären Einrichtung beim überörtlichen ' +
|
||||
'Sozialhilfeträger (in Oberfranken: der Bezirk). Reicht die Rente nicht für das ' +
|
||||
'Heimentgelt, springt die Sozialhilfe ein - aber erst ab Kenntnis des Trägers.',
|
||||
genehmigungspflichtig: false,
|
||||
rechtsgrundlage: '§§ 61 ff. SGB XII',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Antrag beim Bezirk stellen - formlos, aber sofort',
|
||||
beschreibung:
|
||||
'Sozialhilfe setzt ab Kenntnis des Trägers ein (§ 18 SGB XII). Deshalb zuerst ' +
|
||||
'formlos schriftlich beantragen und den Eingang dokumentieren; das Formular kann ' +
|
||||
'nachgereicht werden. Jeder Tag Verzögerung ist verlorenes Geld.',
|
||||
tageBisFaellig: 3,
|
||||
},
|
||||
{
|
||||
titel: 'Standardunterlagen zusammenstellen',
|
||||
beschreibung:
|
||||
'Betreuerausweis, Rentenbescheide, Kontoauszüge der letzten drei Monate aller ' +
|
||||
'Konten, Pflegegradbescheid, Heimvertrag und aktuelle Heimrechnung, Nachweise zu ' +
|
||||
'Versicherungen mit Rückkaufswert, Grundbuchauszug zum Hausgrundstück, ' +
|
||||
'Schwerbehindertenausweis.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Eingang des Antrags schriftlich bestätigen lassen',
|
||||
beschreibung:
|
||||
'Eingangsbestätigung mit Datum anfordern - sie ist der Beleg für den Beginn der ' +
|
||||
'Leistung und für die Bearbeitungsfristen nach § 88 SGG.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Sachbearbeiter und Aktenzeichen notieren',
|
||||
beschreibung:
|
||||
'Name, Durchwahl, E-Mail und Aktenzeichen im Vorgang und als Kontakt anlegen. ' +
|
||||
'Alles Weitere läuft über diese eine Person.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Nachforderungen abarbeiten',
|
||||
beschreibung:
|
||||
'Nachforderungen kommen fast immer. Jede einzeln abhaken und den Versand ' +
|
||||
'dokumentieren - fehlende Mitwirkung kann zur Versagung führen (§ 66 SGB I).',
|
||||
tageBisFaellig: 45,
|
||||
},
|
||||
{
|
||||
titel: 'Bescheid prüfen: Zeitraum, Einkommenseinsatz, Barbetrag',
|
||||
beschreibung:
|
||||
'Prüfen: ab wann wird geleistet, welches Einkommen wird angerechnet, ist der ' +
|
||||
'Barbetrag zur persönlichen Verfügung (§ 27b Abs. 2 SGB XII) enthalten, ist das ' +
|
||||
'Hausgrundstück als Schonvermögen oder als einzusetzendes Vermögen bewertet? ' +
|
||||
'Bei Zweifeln: Widerspruch innerhalb eines Monats.',
|
||||
tageBisFaellig: 90,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Sachstand beim Bezirk erfragen, wenn kein Bescheid vorliegt',
|
||||
tageBisFaellig: 42,
|
||||
},
|
||||
{
|
||||
titel: 'Untätigkeitsklage prüfen (6 Monate ohne Bescheid)',
|
||||
tageBisFaellig: 183,
|
||||
rechtsgrundlage: '§ 88 SGG',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'wohnungsaufloesung',
|
||||
titel: 'Wohnung auflösen und kündigen',
|
||||
kategorie: 'IMMOBILIE',
|
||||
beschreibung:
|
||||
'Die bisherige Wohnung wird aufgegeben. Achtung: Die Aufgabe von Wohnraum ist dem ' +
|
||||
'Betreuungsgericht mitzuteilen und genehmigungsbedürftig - die Mitteilung geht VOR ' +
|
||||
'der Kündigung raus, nicht danach.',
|
||||
genehmigungspflichtig: true,
|
||||
rechtsgrundlage: '§ 1833 BGB',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Mitteilung an das Betreuungsgericht - vor jeder Kündigung',
|
||||
beschreibung:
|
||||
'Die Absicht, den Wohnraum aufzugeben, ist dem Gericht unverzüglich mitzuteilen ' +
|
||||
'(§ 1833 Abs. 1 BGB). Mitteilen heißt: schriftlich, mit Begründung, warum eine ' +
|
||||
'Rückkehr nicht mehr in Betracht kommt (ärztliche Einschätzung beilegen).',
|
||||
tageBisFaellig: 7,
|
||||
},
|
||||
{
|
||||
titel: 'Wunsch der betreuten Person erfragen und dokumentieren',
|
||||
beschreibung:
|
||||
'Die Wohnung ist für viele der letzte Bezug zum früheren Leben. Der geäußerte ' +
|
||||
'oder mutmaßliche Wille ist nach § 1821 BGB maßgeblich und gehört ins ' +
|
||||
'Kontaktprotokoll - das Gericht fragt danach.',
|
||||
tageBisFaellig: 7,
|
||||
},
|
||||
{
|
||||
titel: 'Genehmigung des Gerichts abwarten',
|
||||
beschreibung:
|
||||
'Erst mit rechtskräftiger Genehmigung wird gekündigt. Ohne sie ist die ' +
|
||||
'Kündigung schwebend unwirksam und der Betreuer haftet persönlich.',
|
||||
tageBisFaellig: 45,
|
||||
},
|
||||
{
|
||||
titel: 'Wohnung vollständig fotografieren',
|
||||
beschreibung:
|
||||
'Raum für Raum, auch Keller, Dachboden und Zählerschränke. Die Bilder sind ' +
|
||||
'später der einzige Beleg gegenüber Gericht und möglichen Miterben, in welchem ' +
|
||||
'Zustand die Wohnung war und was darin stand.',
|
||||
tageBisFaellig: 50,
|
||||
},
|
||||
{
|
||||
titel: 'Inventarverzeichnis aufnehmen',
|
||||
beschreibung:
|
||||
'Liste aller Gegenstände mit geschätztem Wert. Sie ist Teil des ' +
|
||||
'Vermögensverzeichnisses (§ 1835 BGB) und Grundlage für die Frage, was verkauft, ' +
|
||||
'verschenkt oder entsorgt wird.',
|
||||
tageBisFaellig: 55,
|
||||
},
|
||||
{
|
||||
titel: 'Wertgegenstände, Papiere und Erinnerungsstücke sichern',
|
||||
beschreibung:
|
||||
'Schmuck, Bargeld, Sparbücher, Urkunden, Versicherungspolicen, Fotoalben. ' +
|
||||
'Getrennt verwahren und im Vermögensverzeichnis führen. Erinnerungsstücke ins ' +
|
||||
'Heimzimmer mitnehmen, soweit dort Platz ist.',
|
||||
tageBisFaellig: 55,
|
||||
},
|
||||
{
|
||||
titel: 'Mietverhältnis kündigen',
|
||||
beschreibung:
|
||||
'Erst jetzt, mit Genehmigung in der Hand. Kündigungsschreiben mit Kopie des ' +
|
||||
'Betreuerausweises und der Genehmigung, Zugang nachweisbar (Einschreiben).',
|
||||
tageBisFaellig: 60,
|
||||
},
|
||||
{
|
||||
titel: 'Wohnungsübergabe mit Protokoll',
|
||||
beschreibung:
|
||||
'Übergabeprotokoll von beiden Seiten unterschreiben, Mängel und Schlüsselzahl ' +
|
||||
'festhalten. Ohne Protokoll gibt es später Streit um die Kaution.',
|
||||
tageBisFaellig: 90,
|
||||
},
|
||||
{
|
||||
titel: 'Zählerstände ablesen und Versorger abmelden',
|
||||
beschreibung:
|
||||
'Strom, Gas, Wasser, Heizung - Stände mit Foto festhalten und mit Datum an die ' +
|
||||
'Versorger melden. Danach Verträge kündigen und Endabrechnung anfordern.',
|
||||
tageBisFaellig: 90,
|
||||
},
|
||||
{
|
||||
titel: 'Nachsendeauftrag einrichten und Kaution zurückfordern',
|
||||
beschreibung:
|
||||
'Kaution nebst Zinsen anfordern; der Vermieter darf sie nur für berechtigte ' +
|
||||
'Ansprüche zurückbehalten, üblicherweise bis zur Betriebskostenabrechnung.',
|
||||
tageBisFaellig: 100,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Betriebskostenabrechnung und Kautionsrückzahlung nachfassen',
|
||||
tageBisFaellig: 180,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'hausverkauf',
|
||||
titel: 'Hausgrundstück verkaufen',
|
||||
kategorie: 'IMMOBILIE',
|
||||
beschreibung:
|
||||
'Verkauf eines Grundstücks aus dem Vermögen der betreuten Person. Genehmigungs' +
|
||||
'pflichtig; die Genehmigung muss dem Vertragspartner in Ausfertigung mit ' +
|
||||
'Rechtskraftvermerk vorgelegt werden, sonst wird der Vertrag nicht wirksam.',
|
||||
genehmigungspflichtig: true,
|
||||
rechtsgrundlage: '§ 1850 Nr. 1 BGB',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Verkehrswert ermitteln lassen',
|
||||
beschreibung:
|
||||
'Gutachten eines öffentlich bestellten Sachverständigen oder Auskunft des ' +
|
||||
'Gutachterausschusses. Das Gericht genehmigt keinen Verkauf ohne belastbaren ' +
|
||||
'Wert - und ein Verkauf unter Wert ist eine Haftungsfalle.',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
{
|
||||
titel: 'Aktuellen Grundbuchauszug und Flurkarte besorgen',
|
||||
beschreibung:
|
||||
'Abteilung II und III prüfen: Wohnrechte, Nießbrauch, Grundschulden, ' +
|
||||
'Sanierungsvermerke. Alles davon beeinflusst den Preis und die Abwicklung.',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
{
|
||||
titel: 'Maklerauftrag vergeben oder freihändig vermarkten',
|
||||
beschreibung:
|
||||
'Auftrag zeitlich begrenzen, Provision und Kündigungsmöglichkeit schriftlich ' +
|
||||
'festhalten. Angebote dokumentieren - das Gericht will sehen, dass der Markt ' +
|
||||
'befragt wurde.',
|
||||
tageBisFaellig: 60,
|
||||
},
|
||||
{
|
||||
titel: 'Notar beauftragen und Kaufvertragsentwurf erstellen lassen',
|
||||
beschreibung:
|
||||
'Der Notar kennt die betreuungsrechtliche Abwicklung. Im Entwurf sollte stehen, ' +
|
||||
'dass der Vertrag erst mit rechtskräftiger betreuungsgerichtlicher Genehmigung ' +
|
||||
'wirksam wird und wer die Kosten trägt, falls sie versagt wird.',
|
||||
tageBisFaellig: 90,
|
||||
},
|
||||
{
|
||||
titel: 'Kaufvertragsentwurf beim Betreuungsgericht einreichen',
|
||||
beschreibung:
|
||||
'Mit Wertgutachten, Grundbuchauszug und einer kurzen Begründung, warum der ' +
|
||||
'Verkauf dem Wohl und dem Willen der betreuten Person entspricht.',
|
||||
tageBisFaellig: 95,
|
||||
},
|
||||
{
|
||||
titel: 'Genehmigungsbeschluss abwarten und Rechtskraft prüfen',
|
||||
beschreibung:
|
||||
'Der Beschluss wird erst mit Bekanntgabe an den Betreuer und Ablauf der ' +
|
||||
'Beschwerdefrist wirksam. Ausfertigung mit Rechtskraftvermerk beim Gericht ' +
|
||||
'anfordern - der Notar braucht genau dieses Papier.',
|
||||
tageBisFaellig: 130,
|
||||
},
|
||||
{
|
||||
titel: 'Beurkundung beim Notar',
|
||||
beschreibung: 'Termin erst nach Vorliegen der Genehmigung wahrnehmen.',
|
||||
tageBisFaellig: 140,
|
||||
},
|
||||
{
|
||||
titel: 'Genehmigung mit Rechtskraftvermerk dem Käufer vorlegen',
|
||||
beschreibung:
|
||||
'Erst mit Vorlage wird der Vertrag endgültig wirksam (§ 1856 BGB). Der Notar ' +
|
||||
'übernimmt das üblicherweise - kontrollieren und zu den Akten nehmen.',
|
||||
tageBisFaellig: 145,
|
||||
},
|
||||
{
|
||||
titel: 'Kaufpreiseingang überwachen und im Kassenbuch erfassen',
|
||||
beschreibung:
|
||||
'Der Erlös ist vermögenswirksam, keine laufende Einnahme. Auf ein Konto der ' +
|
||||
'betreuten Person, niemals auf ein eigenes. Sofort dem Sozialhilfeträger melden - ' +
|
||||
'er ändert die Berechnung.',
|
||||
tageBisFaellig: 170,
|
||||
},
|
||||
{
|
||||
titel: 'Löschung der Belastungen und Eigentumsumschreibung nachverfolgen',
|
||||
beschreibung:
|
||||
'Löschungsbewilligungen der Gläubiger, Löschung der Auflassungsvormerkung, ' +
|
||||
'Eintragung des neuen Eigentümers. Neuen Grundbuchauszug zur Akte nehmen.',
|
||||
tageBisFaellig: 210,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Vermögensverzeichnis nach Verkauf fortschreiben',
|
||||
tageBisFaellig: 180,
|
||||
rechtsgrundlage: '§ 1835 BGB',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'darlehen-91-sgb-xii',
|
||||
titel: 'Sozialhilfe als Darlehen gegen Grundschuld',
|
||||
kategorie: 'SOZIALHILFE',
|
||||
beschreibung:
|
||||
'Wenn das Hausgrundstück nicht sofort verwertet werden kann oder die Verwertung eine ' +
|
||||
'Härte wäre, leistet der Sozialhilfeträger darlehensweise und sichert sich im ' +
|
||||
'Grundbuch ab. Die Bestellung der Grundschuld ist ein genehmigungspflichtiges ' +
|
||||
'Grundstücksgeschäft.',
|
||||
genehmigungspflichtig: true,
|
||||
rechtsgrundlage: '§ 1850 BGB',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Darlehensweise Leistung nach § 91 SGB XII beantragen',
|
||||
beschreibung:
|
||||
'Begründen, warum die sofortige Verwertung nicht möglich oder eine Härte ist: ' +
|
||||
'kein Käufer zum Verkehrswert, laufendes Verfahren, Wohnrecht Dritter, ' +
|
||||
'Rückkehroption. Alternative zum Verkauf unter Druck.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Härtegesichtspunkte und Schonvermögen darlegen',
|
||||
beschreibung:
|
||||
'Prüfen, ob das Hausgrundstück ganz oder teilweise Schonvermögen nach ' +
|
||||
'§ 90 Abs. 2 Nr. 8 und Abs. 3 SGB XII ist. Fällt es darunter, ist überhaupt kein ' +
|
||||
'Darlehen nötig.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Darlehensvertrag und Sicherungsabrede prüfen',
|
||||
beschreibung:
|
||||
'Verzinsung, Rangstelle, Fälligkeit und Kündigungsgründe genau lesen. ' +
|
||||
'Unverzinsliche Darlehen sind der Regelfall - eine Verzinsung nicht ' +
|
||||
'kommentarlos hinnehmen.',
|
||||
tageBisFaellig: 35,
|
||||
},
|
||||
{
|
||||
titel: 'Genehmigung des Betreuungsgerichts einholen',
|
||||
beschreibung:
|
||||
'Die Bestellung einer Grundschuld belastet ein Grundstück und ist deshalb ' +
|
||||
'genehmigungspflichtig (§ 1850 BGB). Vertragsentwurf und Sicherungsabrede ' +
|
||||
'beilegen.',
|
||||
tageBisFaellig: 50,
|
||||
},
|
||||
{
|
||||
titel: 'Grundschuld beim Notar bestellen und eintragen lassen',
|
||||
beschreibung:
|
||||
'Erst nach rechtskräftiger Genehmigung. Auf die Rangstelle achten - eine ' +
|
||||
'nachrangige Eintragung ist für den Träger üblich und für die betreute Person ' +
|
||||
'günstiger.',
|
||||
tageBisFaellig: 80,
|
||||
},
|
||||
{
|
||||
titel: 'Eintragung im Grundbuch prüfen und Vermögensverzeichnis anpassen',
|
||||
beschreibung:
|
||||
'Neuer Grundbuchauszug zur Akte. Das Darlehen ist eine Verbindlichkeit und ' +
|
||||
'gehört als solche in die Vermögensübersicht.',
|
||||
tageBisFaellig: 110,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'versicherungsverwertung',
|
||||
titel: 'Lebens- oder Rentenversicherung verwerten',
|
||||
kategorie: 'VERSICHERUNG',
|
||||
beschreibung:
|
||||
'Der Sozialhilfeträger verlangt regelmäßig, kapitalbildende Versicherungen zu ' +
|
||||
'kündigen. Bevor gekündigt wird, gehört geprüft, ob die Versicherung überhaupt ' +
|
||||
'einzusetzendes Vermögen ist - eine Kündigung lässt sich nicht rückgängig machen.',
|
||||
genehmigungspflichtig: false,
|
||||
rechtsgrundlage: '§ 90 SGB XII',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Aktuellen Rückkaufswert und Vertragsdaten anfordern',
|
||||
beschreibung:
|
||||
'Vom Versicherer schriftlich: Rückkaufswert zum Stichtag, Überschussanteile, ' +
|
||||
'Ablaufleistung, Bezugsberechtigung, Verwertungsausschluss. Der Rückkaufswert ' +
|
||||
'gehört ohnehin jährlich ins Vermögensverzeichnis.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Prüfen, ob Schonvermögen vorliegt',
|
||||
beschreibung:
|
||||
'Bestattungsvorsorge, angemessene Alterssicherung und Verträge mit vereinbartem ' +
|
||||
'Verwertungsausschluss bleiben geschützt; ebenso greift der Schonbetrag nach ' +
|
||||
'§ 90 Abs. 2 Nr. 9 SGB XII. Ergebnis schriftlich festhalten.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Härte nach § 90 Abs. 3 SGB XII prüfen',
|
||||
beschreibung:
|
||||
'Ist der Rückkaufswert deutlich niedriger als die eingezahlten Beiträge, kann die ' +
|
||||
'Verwertung eine Härte sein. Differenz ausrechnen und dem Träger vorrechnen - ' +
|
||||
'das ist das stärkste Argument gegen eine Kündigung.',
|
||||
tageBisFaellig: 28,
|
||||
},
|
||||
{
|
||||
titel: 'Alternativen zur Kündigung prüfen',
|
||||
beschreibung:
|
||||
'Beitragsfreistellung, Beleihung oder Umwandlung in eine Bestattungsvorsorge sind ' +
|
||||
'oft günstiger als der Rückkauf. Mit dem Sachbearbeiter besprechen, bevor ' +
|
||||
'gekündigt wird.',
|
||||
tageBisFaellig: 35,
|
||||
},
|
||||
{
|
||||
titel: 'Genehmigungsfrage klären und beim Gericht abstimmen',
|
||||
beschreibung:
|
||||
'Bei einer schlichten Kündigung liegt in der Regel kein Genehmigungstatbestand ' +
|
||||
'vor. Geht es aber um Wertpapiere oder eine Beleihung, greift § 1851 BGB. Im ' +
|
||||
'Zweifel den Rechtspfleger fragen und die Antwort im Vorgang notieren.',
|
||||
tageBisFaellig: 42,
|
||||
},
|
||||
{
|
||||
titel: 'Kündigung erklären und Auszahlung überwachen',
|
||||
beschreibung:
|
||||
'Kündigung schriftlich mit Betreuerausweis, Auszahlung nur auf ein Konto der ' +
|
||||
'betreuten Person. Eingang als vermögenswirksame Buchung erfassen und dem ' +
|
||||
'Sozialhilfeträger melden.',
|
||||
tageBisFaellig: 60,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'pflegegrad-hoeherstufung',
|
||||
titel: 'Höherstufung des Pflegegrads',
|
||||
kategorie: 'HEIM_PFLEGE',
|
||||
beschreibung:
|
||||
'Antrag auf Höherstufung, wenn der Pflegebedarf gestiegen ist. Bei einer ' +
|
||||
'fortschreitenden COPD ist das der Regelfall, nicht die Ausnahme.',
|
||||
genehmigungspflichtig: false,
|
||||
rechtsgrundlage: '§ 18 SGB XI',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Pflegetagebuch über mindestens zwei Wochen führen lassen',
|
||||
beschreibung:
|
||||
'Zusammen mit der Pflegedienstleitung: Hilfebedarf je Modul, Atemnot, ' +
|
||||
'Sauerstoffbedarf, nächtliche Unruhe, Sturzereignisse. Ohne dieses Tagebuch ist ' +
|
||||
'die Begutachtung ein Blindflug.',
|
||||
tageBisFaellig: 21,
|
||||
},
|
||||
{
|
||||
titel: 'Antrag auf Höherstufung bei der Pflegekasse stellen',
|
||||
beschreibung:
|
||||
'Formlos genügt. Änderung des Zustands kurz beschreiben und auf das ' +
|
||||
'Pflegetagebuch verweisen.',
|
||||
tageBisFaellig: 25,
|
||||
},
|
||||
{
|
||||
titel: 'Begutachtung durch den Medizinischen Dienst vorbereiten',
|
||||
beschreibung:
|
||||
'Termin so legen, dass Pflegekraft und Betreuer dabei sind. Aktuelle ' +
|
||||
'Arztberichte, Medikamentenplan und das Pflegetagebuch bereitlegen. Die ' +
|
||||
'schlechten Tage schildern, nicht die guten.',
|
||||
tageBisFaellig: 45,
|
||||
},
|
||||
{
|
||||
titel: 'Gutachten anfordern und lesen',
|
||||
beschreibung:
|
||||
'Das Gutachten wird auf Verlangen übersandt. Punktvergabe je Modul mit der ' +
|
||||
'eigenen Wahrnehmung abgleichen - hier stehen die Ansatzpunkte für einen ' +
|
||||
'Widerspruch.',
|
||||
tageBisFaellig: 70,
|
||||
},
|
||||
{
|
||||
titel: 'Bescheid prüfen und ggf. Widerspruch einlegen',
|
||||
beschreibung:
|
||||
'Widerspruchsfrist: ein Monat ab Bekanntgabe (§ 84 SGG). Fristwahrend einlegen, ' +
|
||||
'Begründung nach Erhalt des Gutachtens nachreichen.',
|
||||
tageBisFaellig: 80,
|
||||
},
|
||||
{
|
||||
titel: 'Heim, Sozialhilfeträger und Kassen über den neuen Grad informieren',
|
||||
beschreibung:
|
||||
'Der Pflegegrad ändert Heimentgelt und Leistungsbetrag - und damit die ' +
|
||||
'Berechnung der Hilfe zur Pflege.',
|
||||
tageBisFaellig: 95,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Frist zur Bearbeitung durch die Pflegekasse endet (5 Wochen)',
|
||||
tageBisFaellig: 35,
|
||||
rechtsgrundlage: '§ 18 Abs. 3b SGB XI',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'steuererklaerung',
|
||||
titel: 'Einkommensteuererklärung',
|
||||
kategorie: 'STEUERN',
|
||||
beschreibung:
|
||||
'Steuererklärung für die betreute Person. Auch wer nur Rente bezieht, ist häufig ' +
|
||||
'erklärungspflichtig - und bekommt wegen der außergewöhnlichen Belastungen durch ' +
|
||||
'Heim und Pflege oft etwas zurück.',
|
||||
genehmigungspflichtig: false,
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Prüfen, ob eine Erklärungspflicht besteht',
|
||||
beschreibung:
|
||||
'Rentenbezugsmitteilung, weitere Einkünfte, Aufforderung des Finanzamts. Auch ' +
|
||||
'ohne Pflicht lohnt die Abgabe fast immer, wenn Heimkosten selbst getragen wurden.',
|
||||
tageBisFaellig: 30,
|
||||
},
|
||||
{
|
||||
titel: 'Unterlagen sammeln',
|
||||
beschreibung:
|
||||
'Rentenbezugsmitteilungen, Steuerbescheinigungen der Banken, Heimrechnungen und ' +
|
||||
'Eigenanteil, Zuzahlungen, Medikamente, Fahrtkosten, Spenden, Grad der ' +
|
||||
'Behinderung.',
|
||||
tageBisFaellig: 60,
|
||||
},
|
||||
{
|
||||
titel: 'Heimkosten als außergewöhnliche Belastung ansetzen',
|
||||
beschreibung:
|
||||
'Der selbst getragene Heimanteil ist abzüglich Haushaltsersparnis absetzbar ' +
|
||||
'(§ 33 EStG); der Behinderten-Pauschbetrag nach § 33b EStG ist eine Alternative. ' +
|
||||
'Beides gegeneinander rechnen.',
|
||||
tageBisFaellig: 75,
|
||||
},
|
||||
{
|
||||
titel: 'Erklärung erstellen und einreichen',
|
||||
beschreibung:
|
||||
'Als Betreuer unterschreiben, Betreuerausweis in Kopie beifügen. Abgabefrist ' +
|
||||
'für nicht beratene Fälle: 31. Juli des Folgejahres.',
|
||||
tageBisFaellig: 100,
|
||||
},
|
||||
{
|
||||
titel: 'Bescheid prüfen',
|
||||
beschreibung:
|
||||
'Einspruchsfrist: ein Monat ab Bekanntgabe (§ 355 AO). Angesetzte Belastungen ' +
|
||||
'mit der eigenen Aufstellung abgleichen.',
|
||||
tageBisFaellig: 160,
|
||||
},
|
||||
{
|
||||
titel: 'Erstattung oder Nachzahlung verbuchen und melden',
|
||||
beschreibung:
|
||||
'Erstattungen sind Einnahmen und dem Sozialhilfeträger zu melden.',
|
||||
tageBisFaellig: 175,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Abgabefrist Einkommensteuererklärung',
|
||||
tageBisFaellig: 120,
|
||||
rechtsgrundlage: '§ 149 AO',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
{
|
||||
schluessel: 'widerspruch-bescheid',
|
||||
titel: 'Widerspruch gegen einen Bescheid',
|
||||
kategorie: 'SOZIALHILFE',
|
||||
beschreibung:
|
||||
'Widerspruch gegen einen Bescheid des Sozialhilfeträgers, der Kranken- oder ' +
|
||||
'Pflegekasse. Die Frist beträgt einen Monat ab Bekanntgabe - sie ist die härteste ' +
|
||||
'Frist in diesem ganzen Programm. Zuerst einlegen, dann begründen.',
|
||||
genehmigungspflichtig: false,
|
||||
rechtsgrundlage: '§ 84 SGG',
|
||||
aufgaben: [
|
||||
{
|
||||
titel: 'Widerspruch fristwahrend einlegen, Begründung nachreichen',
|
||||
beschreibung:
|
||||
'Ein Satz genügt: "Gegen den Bescheid vom … lege ich Widerspruch ein. Die ' +
|
||||
'Begründung reiche ich nach." Sofort raus, Zugang nachweisbar. Die Monatsfrist ' +
|
||||
'nach § 84 SGG läuft ab Bekanntgabe; fehlt die Rechtsbehelfsbelehrung, sind es ' +
|
||||
'ein Jahr - darauf sollte man sich aber nie verlassen.',
|
||||
tageBisFaellig: 7,
|
||||
},
|
||||
{
|
||||
titel: 'Bekanntgabedatum feststellen und dokumentieren',
|
||||
beschreibung:
|
||||
'Maßgeblich ist nicht das Datum auf dem Bescheid: Bei Zusendung mit einfachem ' +
|
||||
'Brief gilt er am dritten Tag nach Aufgabe zur Post als bekanntgegeben ' +
|
||||
'(§ 37 Abs. 2 SGB X). Briefumschlag aufheben.',
|
||||
tageBisFaellig: 3,
|
||||
},
|
||||
{
|
||||
titel: 'Akteneinsicht beantragen',
|
||||
beschreibung:
|
||||
'Nach § 25 SGB X. Erst die Akte zeigt, worauf der Träger seine Berechnung ' +
|
||||
'stützt und welche Unterlagen er hat.',
|
||||
tageBisFaellig: 14,
|
||||
},
|
||||
{
|
||||
titel: 'Begründung schreiben und einreichen',
|
||||
beschreibung:
|
||||
'Punkt für Punkt am Bescheid entlang: welche Rechengröße ist falsch, welche ' +
|
||||
'Vorschrift wurde übersehen, welche Unterlage fehlte. Belege beifügen.',
|
||||
tageBisFaellig: 35,
|
||||
},
|
||||
{
|
||||
titel: 'Aufschiebende Wirkung bzw. einstweiligen Rechtsschutz prüfen',
|
||||
beschreibung:
|
||||
'Bei Aufhebung oder Erstattung entfällt die aufschiebende Wirkung teilweise ' +
|
||||
'(§ 86a SGG). Droht ein Zahlungsausfall, ist ein Eilantrag beim Sozialgericht ' +
|
||||
'zu erwägen.',
|
||||
tageBisFaellig: 40,
|
||||
},
|
||||
{
|
||||
titel: 'Widerspruchsbescheid prüfen und Klagefrist notieren',
|
||||
beschreibung:
|
||||
'Gegen den Widerspruchsbescheid ist binnen eines Monats Klage beim Sozialgericht ' +
|
||||
'möglich (§ 87 SGG) - gerichtskostenfrei.',
|
||||
tageBisFaellig: 120,
|
||||
},
|
||||
],
|
||||
fristen: [
|
||||
{
|
||||
titel: 'Widerspruchsfrist läuft ab (ein Monat ab Bekanntgabe)',
|
||||
tageBisFaellig: 30,
|
||||
rechtsgrundlage: '§ 84 SGG',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
/** Sucht eine Vorlage. Gibt undefined zurück, wenn es sie nicht gibt. */
|
||||
export function vorlageFinden(schluessel: string): Vorgangsvorlage | undefined {
|
||||
return VORLAGEN.find((v) => v.schluessel === schluessel)
|
||||
}
|
||||
|
||||
export const VORLAGEN_SCHLUESSEL = VORLAGEN.map((v) => v.schluessel)
|
||||
|
||||
/**
|
||||
* Rechnet die relativen Angaben einer Vorlage in echte Termine um.
|
||||
*
|
||||
* Bewusst rein und ohne Datenbank: so lässt sich im Test prüfen, dass eine
|
||||
* Vorlage die erwarteten Aufgaben in der erwarteten Reihenfolge erzeugt.
|
||||
* Datumsrechnung über date-fns, nie über setDate von Hand.
|
||||
*/
|
||||
export type ErzeugteAufgabe = {
|
||||
titel: string
|
||||
beschreibung: string | null
|
||||
faelligAm: Date | null
|
||||
reihenfolge: number
|
||||
}
|
||||
|
||||
export type ErzeugteFrist = {
|
||||
titel: string
|
||||
datum: Date
|
||||
rechtsgrundlage: string | null
|
||||
}
|
||||
|
||||
export type VorlagenErgebnis = {
|
||||
vorlage: Vorgangsvorlage
|
||||
aufgaben: ErzeugteAufgabe[]
|
||||
fristen: ErzeugteFrist[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Tagesanteil eines Datums, auf Mitternacht UTC normiert.
|
||||
*
|
||||
* Fristen und Fälligkeiten sind in der Datenbank @db.Date - ohne diese
|
||||
* Normierung verschiebt die Zeitzone eine Frist um einen Tag.
|
||||
*/
|
||||
export function alsTag(datum: Date): Date {
|
||||
return new Date(
|
||||
Date.UTC(datum.getUTCFullYear(), datum.getUTCMonth(), datum.getUTCDate(), 0, 0, 0, 0),
|
||||
)
|
||||
}
|
||||
|
||||
export function vorlageAnwenden(schluessel: string, start: Date = new Date()): VorlagenErgebnis {
|
||||
const vorlage = vorlageFinden(schluessel)
|
||||
if (!vorlage) {
|
||||
throw new Error(`Unbekannte Vorgangs-Vorlage: ${schluessel}`)
|
||||
}
|
||||
|
||||
const basis = alsTag(start)
|
||||
|
||||
return {
|
||||
vorlage,
|
||||
aufgaben: vorlage.aufgaben.map((aufgabe, index) => ({
|
||||
titel: aufgabe.titel,
|
||||
beschreibung: aufgabe.beschreibung ?? null,
|
||||
faelligAm:
|
||||
aufgabe.tageBisFaellig === undefined ? null : alsTag(addDays(basis, aufgabe.tageBisFaellig)),
|
||||
// Die Reihenfolge ist der fachliche Kern der Vorlage - sie wird
|
||||
// festgeschrieben, damit spaeteres Sortieren sie nicht zerstoert.
|
||||
reihenfolge: index,
|
||||
})),
|
||||
fristen: (vorlage.fristen ?? []).map((frist) => ({
|
||||
titel: frist.titel,
|
||||
datum: alsTag(addDays(basis, frist.tageBisFaellig)),
|
||||
rechtsgrundlage: frist.rechtsgrundlage ?? null,
|
||||
})),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
import type { BuchungRichtung, GenehmigungStatus, KontaktArt, VorgangStatus } from '@prisma/client'
|
||||
import { GENEHMIGUNG_STATUS_BESCHRIFTUNG, GENEHMIGUNG_STUFEN } from '@/lib/vorgaenge/genehmigungskette'
|
||||
|
||||
/**
|
||||
* Zeitstrahl einer Fallakte.
|
||||
*
|
||||
* Ein Vorgang zerfällt in der Datenbank in fünf Tabellen: Dokumente,
|
||||
* Kontaktprotokolle, Fristen, Buchungen, Genehmigungsstufen. Für die Frage
|
||||
* "was ist in dieser Sache eigentlich passiert?" ist genau diese Aufteilung
|
||||
* unbrauchbar - man will eine Spalte, von unten nach oben gelesen.
|
||||
*
|
||||
* Und man braucht sie nicht nur zum Nachlesen: Wenn das Gericht oder der
|
||||
* Bezirk fragt, wann etwas geschickt wurde, ist diese Liste die Antwort.
|
||||
*
|
||||
* Die Funktion ist bewusst rein: sie bekommt fertig geladene Daten und gibt
|
||||
* eine sortierte Liste zurück. Kein Datenbankzugriff, damit sie im Test
|
||||
* ohne Datenbank prüfbar bleibt.
|
||||
*/
|
||||
|
||||
export type Zeitstrahlart =
|
||||
| 'ANGELEGT'
|
||||
| 'DOKUMENT'
|
||||
| 'KONTAKT'
|
||||
| 'FRIST'
|
||||
| 'BUCHUNG'
|
||||
| 'GENEHMIGUNG'
|
||||
| 'STATUS'
|
||||
| 'ERLEDIGT'
|
||||
|
||||
export type Zeitstrahleintrag = {
|
||||
/** Eindeutig über alle Quellen hinweg: "<art>:<id>[:<zusatz>]". */
|
||||
id: string
|
||||
art: Zeitstrahlart
|
||||
datum: Date
|
||||
titel: string
|
||||
detail: string | null
|
||||
/** Ziel zum Weiterklicken, wenn es eine eigene Seite gibt. */
|
||||
href: string | null
|
||||
/** Cent als Zahl - der Zeitstrahl wandert zu Client Components. */
|
||||
betragCent: number | null
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Eingangsdaten
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export type ZeitstrahlDokument = {
|
||||
id: string
|
||||
titel: string
|
||||
eingangAm: Date | null
|
||||
versandAm: Date | null
|
||||
erstelltAm: Date
|
||||
absender: string | null
|
||||
empfaenger: string | null
|
||||
}
|
||||
|
||||
export type ZeitstrahlKontaktprotokoll = {
|
||||
id: string
|
||||
datum: Date
|
||||
art: KontaktArt
|
||||
gespraechspartner: string | null
|
||||
mitBetreuter: boolean
|
||||
/** Bereits entschlüsselter Inhalt, gekürzt. */
|
||||
inhalt: string | null
|
||||
}
|
||||
|
||||
export type ZeitstrahlFrist = {
|
||||
id: string
|
||||
titel: string
|
||||
datum: Date
|
||||
erledigtAm: Date | null
|
||||
ausschlussfrist: boolean
|
||||
rechtsgrundlage: string | null
|
||||
}
|
||||
|
||||
export type ZeitstrahlBuchung = {
|
||||
id: string
|
||||
datum: Date
|
||||
betragCent: number
|
||||
richtung: BuchungRichtung
|
||||
gegenstelle: string | null
|
||||
/** Bereits entschlüsselter Verwendungszweck. */
|
||||
verwendungszweck: string | null
|
||||
}
|
||||
|
||||
export type ZeitstrahlGenehmigung = {
|
||||
id: string
|
||||
titel: string
|
||||
rechtsgrundlage: string
|
||||
status: GenehmigungStatus
|
||||
mitteilungAm: Date | null
|
||||
antragAm: Date | null
|
||||
anhoerungAm: Date | null
|
||||
beschlussAm: Date | null
|
||||
rechtskraftAm: Date | null
|
||||
vollzugAm: Date | null
|
||||
}
|
||||
|
||||
/** Ein aus dem Audit-Log gelesener Statuswechsel des Vorgangs. */
|
||||
export type ZeitstrahlStatuswechsel = {
|
||||
id: string
|
||||
zeitpunkt: Date
|
||||
von: VorgangStatus | null
|
||||
nach: VorgangStatus
|
||||
wer: string | null
|
||||
}
|
||||
|
||||
export type ZeitstrahlQuellen = {
|
||||
vorgang: {
|
||||
titel: string
|
||||
erstelltAm: Date
|
||||
erledigtAm: Date | null
|
||||
}
|
||||
dokumente?: ZeitstrahlDokument[]
|
||||
kontaktprotokolle?: ZeitstrahlKontaktprotokoll[]
|
||||
fristen?: ZeitstrahlFrist[]
|
||||
buchungen?: ZeitstrahlBuchung[]
|
||||
genehmigungen?: ZeitstrahlGenehmigung[]
|
||||
statuswechsel?: ZeitstrahlStatuswechsel[]
|
||||
}
|
||||
|
||||
export const VORGANG_STATUS_BESCHRIFTUNG: Record<VorgangStatus, string> = {
|
||||
OFFEN: 'Offen',
|
||||
IN_ARBEIT: 'In Arbeit',
|
||||
WARTET_AUF_DRITTE: 'Wartet auf andere',
|
||||
WARTET_AUF_GENEHMIGUNG: 'Wartet auf Genehmigung',
|
||||
ERLEDIGT: 'Erledigt',
|
||||
}
|
||||
|
||||
export const KONTAKTART_BESCHRIFTUNG: Record<KontaktArt, string> = {
|
||||
BESUCH: 'Besuch',
|
||||
TELEFONAT: 'Telefonat',
|
||||
EMAIL: 'E-Mail',
|
||||
BRIEF: 'Brief',
|
||||
VIDEOCALL: 'Videogespräch',
|
||||
FAX: 'Fax',
|
||||
VORSPRACHE: 'Vorsprache',
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function kuerzen(text: string | null, laenge = 160): string | null {
|
||||
if (!text) return null
|
||||
const sauber = text.replace(/\s+/g, ' ').trim()
|
||||
if (sauber === '') return null
|
||||
return sauber.length <= laenge ? sauber : `${sauber.slice(0, laenge - 1)}…`
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt alle Quellen zu einer Liste zusammen.
|
||||
*
|
||||
* Sortierung: neueste zuerst. Bei gleichem Zeitpunkt entscheidet die
|
||||
* Reihenfolge in RANG - sonst springen Einträge bei jedem Aufruf, was beim
|
||||
* Vergleich zweier Ausdrucke unnötig verwirrt.
|
||||
*/
|
||||
const RANG: Record<Zeitstrahlart, number> = {
|
||||
ERLEDIGT: 0,
|
||||
STATUS: 1,
|
||||
GENEHMIGUNG: 2,
|
||||
DOKUMENT: 3,
|
||||
KONTAKT: 4,
|
||||
BUCHUNG: 5,
|
||||
FRIST: 6,
|
||||
ANGELEGT: 7,
|
||||
}
|
||||
|
||||
export function zeitstrahlBauen(
|
||||
quellen: ZeitstrahlQuellen,
|
||||
optionen: { reihenfolge?: 'neueste-zuerst' | 'aelteste-zuerst' } = {},
|
||||
): Zeitstrahleintrag[] {
|
||||
const eintraege: Zeitstrahleintrag[] = []
|
||||
|
||||
// --- Anlage und Erledigung des Vorgangs selbst ----------------------------
|
||||
eintraege.push({
|
||||
id: 'ANGELEGT:vorgang',
|
||||
art: 'ANGELEGT',
|
||||
datum: quellen.vorgang.erstelltAm,
|
||||
titel: 'Vorgang angelegt',
|
||||
detail: quellen.vorgang.titel,
|
||||
href: null,
|
||||
betragCent: null,
|
||||
})
|
||||
|
||||
if (quellen.vorgang.erledigtAm) {
|
||||
eintraege.push({
|
||||
id: 'ERLEDIGT:vorgang',
|
||||
art: 'ERLEDIGT',
|
||||
datum: quellen.vorgang.erledigtAm,
|
||||
titel: 'Vorgang erledigt',
|
||||
detail: null,
|
||||
href: null,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
// --- Dokumente ------------------------------------------------------------
|
||||
for (const dokument of quellen.dokumente ?? []) {
|
||||
// Eingang schlaegt Versand schlaegt Anlage: massgeblich ist, wann das
|
||||
// Papier tatsaechlich bewegt wurde - daran haengen Rechtsbehelfsfristen.
|
||||
const datum = dokument.eingangAm ?? dokument.versandAm ?? dokument.erstelltAm
|
||||
const richtung = dokument.eingangAm
|
||||
? `Eingang${dokument.absender ? ` von ${dokument.absender}` : ''}`
|
||||
: dokument.versandAm
|
||||
? `Versand${dokument.empfaenger ? ` an ${dokument.empfaenger}` : ''}`
|
||||
: 'Abgelegt'
|
||||
|
||||
eintraege.push({
|
||||
id: `DOKUMENT:${dokument.id}`,
|
||||
art: 'DOKUMENT',
|
||||
datum,
|
||||
titel: dokument.titel,
|
||||
detail: richtung,
|
||||
href: `/dokumente/${dokument.id}`,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
// --- Kontaktprotokolle ----------------------------------------------------
|
||||
for (const protokoll of quellen.kontaktprotokolle ?? []) {
|
||||
const art = KONTAKTART_BESCHRIFTUNG[protokoll.art]
|
||||
const partner = protokoll.gespraechspartner ? ` mit ${protokoll.gespraechspartner}` : ''
|
||||
eintraege.push({
|
||||
id: `KONTAKT:${protokoll.id}`,
|
||||
art: 'KONTAKT',
|
||||
datum: protokoll.datum,
|
||||
titel: `${art}${partner}`,
|
||||
detail:
|
||||
kuerzen(protokoll.inhalt) ??
|
||||
(protokoll.mitBetreuter ? 'Persönlicher Kontakt zur betreuten Person' : null),
|
||||
href: `/kontakte/protokoll/${protokoll.id}`,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
// --- Fristen --------------------------------------------------------------
|
||||
for (const frist of quellen.fristen ?? []) {
|
||||
eintraege.push({
|
||||
id: `FRIST:${frist.id}`,
|
||||
art: 'FRIST',
|
||||
datum: frist.datum,
|
||||
titel: frist.ausschlussfrist ? `Ausschlussfrist: ${frist.titel}` : `Frist: ${frist.titel}`,
|
||||
detail: [frist.rechtsgrundlage, frist.erledigtAm ? 'erledigt' : null]
|
||||
.filter(Boolean)
|
||||
.join(' · ') || null,
|
||||
href: `/fristen/${frist.id}`,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
// --- Buchungen ------------------------------------------------------------
|
||||
for (const buchung of quellen.buchungen ?? []) {
|
||||
const vorzeichen = buchung.richtung === 'AUSGABE' ? -1 : 1
|
||||
const bezeichnung =
|
||||
buchung.richtung === 'AUSGABE'
|
||||
? 'Ausgabe'
|
||||
: buchung.richtung === 'EINNAHME'
|
||||
? 'Einnahme'
|
||||
: 'Umbuchung'
|
||||
eintraege.push({
|
||||
id: `BUCHUNG:${buchung.id}`,
|
||||
art: 'BUCHUNG',
|
||||
datum: buchung.datum,
|
||||
titel: bezeichnung,
|
||||
detail:
|
||||
[buchung.gegenstelle, kuerzen(buchung.verwendungszweck, 80)].filter(Boolean).join(' · ') ||
|
||||
null,
|
||||
href: `/finanzen/buchungen/${buchung.id}`,
|
||||
betragCent: vorzeichen * Math.abs(buchung.betragCent),
|
||||
})
|
||||
}
|
||||
|
||||
// --- Genehmigungsstufen ---------------------------------------------------
|
||||
// Jede erreichte Stufe hat ihr eigenes Datumsfeld; daraus entsteht die
|
||||
// Chronik des Genehmigungsverfahrens ganz ohne zusaetzliche Tabelle.
|
||||
for (const genehmigung of quellen.genehmigungen ?? []) {
|
||||
for (const stufe of GENEHMIGUNG_STUFEN) {
|
||||
if (!stufe.datumsfeld) continue
|
||||
const datum = genehmigung[stufe.datumsfeld]
|
||||
if (!datum) continue
|
||||
eintraege.push({
|
||||
id: `GENEHMIGUNG:${genehmigung.id}:${stufe.status}`,
|
||||
art: 'GENEHMIGUNG',
|
||||
datum,
|
||||
titel: `Genehmigung: ${stufe.beschriftung}`,
|
||||
detail: `${genehmigung.titel} · ${genehmigung.rechtsgrundlage}`,
|
||||
href: null,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
// Die Versagung hat kein eigenes Datumsfeld - sie wird am Beschluss-
|
||||
// datum gezeigt, weil das Gericht mit dem Beschluss versagt.
|
||||
if (genehmigung.status === 'VERSAGT' && genehmigung.beschlussAm) {
|
||||
eintraege.push({
|
||||
id: `GENEHMIGUNG:${genehmigung.id}:VERSAGT`,
|
||||
art: 'GENEHMIGUNG',
|
||||
datum: genehmigung.beschlussAm,
|
||||
titel: `Genehmigung: ${GENEHMIGUNG_STATUS_BESCHRIFTUNG.VERSAGT}`,
|
||||
detail: `${genehmigung.titel} · ${genehmigung.rechtsgrundlage}`,
|
||||
href: null,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --- Statuswechsel aus dem Audit-Log -------------------------------------
|
||||
for (const wechsel of quellen.statuswechsel ?? []) {
|
||||
const von = wechsel.von ? VORGANG_STATUS_BESCHRIFTUNG[wechsel.von] : null
|
||||
eintraege.push({
|
||||
id: `STATUS:${wechsel.id}`,
|
||||
art: 'STATUS',
|
||||
datum: wechsel.zeitpunkt,
|
||||
titel: von
|
||||
? `Status: ${von} → ${VORGANG_STATUS_BESCHRIFTUNG[wechsel.nach]}`
|
||||
: `Status: ${VORGANG_STATUS_BESCHRIFTUNG[wechsel.nach]}`,
|
||||
detail: wechsel.wer,
|
||||
href: null,
|
||||
betragCent: null,
|
||||
})
|
||||
}
|
||||
|
||||
const richtung = optionen.reihenfolge === 'aelteste-zuerst' ? 1 : -1
|
||||
|
||||
return eintraege.sort((a, b) => {
|
||||
const differenz = a.datum.getTime() - b.datum.getTime()
|
||||
if (differenz !== 0) return differenz * richtung
|
||||
const rang = RANG[a.art] - RANG[b.art]
|
||||
if (rang !== 0) return rang
|
||||
return a.id.localeCompare(b.id, 'de')
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user