import { alsTag, heute, jahrePlus, monatePlus, tagePlus, vorOderGleich } from '@/lib/finanzen/datum' /** * Das Betreuungsjahr. * * Es laeuft ab dem Tag der Bestellung, nicht ab dem 1. Januar. Wer am * 15.03.2025 bestellt wurde, legt fuer den Zeitraum 15.03.2025 bis * 14.03.2026 Rechnung (§ 1865 Abs. 1 BGB), und die Aufwandspauschale * nach § 1878 BGB verfaellt sechs Monate nach dessen Ende. * * Das ist der haeufigste Rechenfehler in selbstgebauten Tabellen: man * rechnet das Kalenderjahr ab und wundert sich, warum das Gericht * nachfragt. Deshalb steht die Rechnung hier an genau einer Stelle. * * Schaltjahrfall: Ist die Bestellung am 29.02. erfolgt, gibt es in * Nicht-Schaltjahren keinen 29.02. Das Jahr endet dann am 27.02. und das * folgende beginnt am 28.02. - so entsteht weder eine Luecke noch eine * Ueberschneidung, und jeder Tag gehoert zu genau einem Betreuungsjahr. */ export type Betreuungsjahr = { /** 1 = das erste Jahr ab Bestellung. */ nummer: number /** Erster Tag, einschliesslich. */ von: Date /** Letzter Tag, einschliesslich. */ bis: Date /** "1. Betreuungsjahr (15.03.2025 – 14.03.2026)" - fuer Auswahllisten. */ bezeichnung: string } function formatKurz(datum: Date): string { const tag = String(datum.getUTCDate()).padStart(2, '0') const monat = String(datum.getUTCMonth() + 1).padStart(2, '0') return `${tag}.${monat}.${datum.getUTCFullYear()}` } function bauen(nummer: number, von: Date, bis: Date): Betreuungsjahr { return { nummer, von, bis, bezeichnung: `${nummer}. Betreuungsjahr (${formatKurz(von)} – ${formatKurz(bis)})`, } } /** * Das n-te Betreuungsjahr. nummer ist 1-basiert; 1 ist das Jahr, das am * Tag der Bestellung beginnt. */ export function betreuungsjahr(bestellungAm: Date, nummer: number): Betreuungsjahr { if (!Number.isInteger(nummer) || nummer < 1) { throw new Error('Das Betreuungsjahr wird ab 1 gezählt.') } const start = alsTag(bestellungAm) const von = jahrePlus(start, nummer - 1) const bis = tagePlus(jahrePlus(start, nummer), -1) return bauen(nummer, von, bis) } /** * In welches Betreuungsjahr faellt ein Datum? Null, wenn es vor der * Bestellung liegt - dafuer gibt es keine Rechnungslegung. */ export function betreuungsjahrZuDatum(bestellungAm: Date, datum: Date): Betreuungsjahr | null { const start = alsTag(bestellungAm) const ziel = alsTag(datum) if (ziel.getTime() < start.getTime()) return null // Grobe Schaetzung ueber die Jahresdifferenz, danach hoechstens zwei // Korrekturschritte - das haelt auch den Schaltjahrfall aus. let nummer = ziel.getUTCFullYear() - start.getUTCFullYear() + 1 if (nummer < 1) nummer = 1 for (let versuch = 0; versuch < 4; versuch++) { const jahr = betreuungsjahr(start, nummer) if (ziel.getTime() < jahr.von.getTime()) { nummer -= 1 if (nummer < 1) return null continue } if (ziel.getTime() > jahr.bis.getTime()) { nummer += 1 continue } return jahr } return null } /** Das Betreuungsjahr, in dem wir heute stehen. */ export function laufendesBetreuungsjahr( bestellungAm: Date, stichtag: Date = heute(), ): Betreuungsjahr | null { return betreuungsjahrZuDatum(bestellungAm, stichtag) } /** * Alle Betreuungsjahre von der Bestellung bis einschliesslich des Jahres, * in dem "bis" liegt. Fuer die Auswahlliste im Berichtsformular - das * laufende Jahr steht mit dabei, denn eine Zwischenaufstellung ist * jederzeit erlaubt. */ export function betreuungsjahre(bestellungAm: Date, bis: Date = heute()): Betreuungsjahr[] { const letztes = betreuungsjahrZuDatum(bestellungAm, bis) if (!letztes) return [] const liste: Betreuungsjahr[] = [] for (let nummer = 1; nummer <= letztes.nummer; nummer++) { liste.push(betreuungsjahr(bestellungAm, nummer)) } return liste } /** * Ist das Betreuungsjahr abgeschlossen? Nur dann ist die Rechnungslegung * faellig; vorher ist der Bericht eine Zwischenaufstellung. */ export function jahrAbgeschlossen(jahr: Betreuungsjahr, stichtag: Date = heute()): boolean { return vorOderGleich(jahr.bis, stichtag) } /** * Ende der Ausschlussfrist fuer die Aufwandspauschale nach § 1878 BGB: * sechs Monate nach dem Ende des Betreuungsjahres. Danach ist der * Anspruch weg - kein Ermessen, keine Nachsicht. */ export function aufwandspauschaleBis(jahr: Betreuungsjahr): Date { return monatePlus(jahr.bis, 6) }