import Link from 'next/link' import { Banknote, Plus, Upload } from 'lucide-react' import type { Prisma } from '@prisma/client' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { SeitenKopf, Leerzustand } from '@/components/seiten-kopf' import { Rechtshinweis } from '@/components/rechtshinweis' import { Belegzeichen, Betrag, Kennzahl, Vermischungswarnung } from '@/components/finanzen/bausteine' import { Buchungsfilter } from '@/components/finanzen/buchungs-filter' import { centZuZahl, db, nichtGeloescht } from '@/lib/db' import { formatCent, formatDatum } from '@/lib/utils' import { finanzKontext } from '@/lib/finanzen/seite' import { BUCHUNG_EINBEZUG, zuBuchungEingabe } from '@/lib/berichte/gemeinsam' import { belegDurchVertrag, betragPruefen, belegFehlt, kennzahlen, vermischungsWarnung, type BuchungEingabe } from '@/lib/finanzen/kassenbuch' import { KATEGORIE_BESCHRIFTUNG, RICHTUNG_BESCHRIFTUNG } from '@/lib/finanzen/kategorien' import { buchungsfilterSchema } from '@/lib/validierung/finanzen' export const metadata = { title: 'Kassenbuch' } const HOECHSTZAHL = 300 /** * Das Kassenbuch. * * Zwei Dinge sind hier absichtlich auffällig: Buchungen ohne Beleg und * ohne Begründung werden rot markiert, und eine Buchung, die auf einem * Konto des Betreuers läuft und trotzdem als Vermögen der Betreuten * gilt, bekommt eine eigene Warnung. Beides sind die Punkte, an denen * eine Rechnungslegung beim Gericht auseinanderfällt. */ export default async function BuchungenSeite({ searchParams, }: { searchParams: Promise> }) { const roh = await searchParams const { betreute, darfSchreiben } = await finanzKontext() const schreiben = darfSchreiben('FINANZEN') const flach: Record = {} for (const [schluessel, wert] of Object.entries(roh)) { if (typeof wert === 'string') flach[schluessel] = wert } const gepruft = buchungsfilterSchema.safeParse(flach) const filter = gepruft.success ? gepruft.data : { kontoId: null, kategorie: null, richtung: null, von: null, bis: null, suche: null, nurOhneBeleg: false, nurEigeneAuslagen: false, } const bedingung: Prisma.BuchungWhereInput = { betreuteId: betreute.id, ...nichtGeloescht, ...(filter.kontoId ? { kontoId: filter.kontoId } : {}), ...(filter.kategorie ? { kategorie: filter.kategorie } : {}), ...(filter.richtung ? { richtung: filter.richtung } : {}), ...(filter.von || filter.bis ? { datum: { ...(filter.von ? { gte: filter.von } : {}), ...(filter.bis ? { lte: filter.bis } : {}), }, } : {}), // Der Verwendungszweck ist verschluesselt und laesst sich nicht // durchsuchen - gesucht wird deshalb nur in der Gegenstelle. ...(filter.suche ? { gegenstelle: { contains: filter.suche, mode: 'insensitive' } } : {}), ...(filter.nurEigeneAuslagen ? { betrifftBetreute: false } : {}), ...(filter.nurOhneBeleg ? { belegId: null, OR: [{ belegFehltBegruendung: null }, { belegFehltBegruendung: '' }] } : {}), } const [zeilen, gesamt, konten] = await Promise.all([ db.buchung.findMany({ where: bedingung, include: BUCHUNG_EINBEZUG, orderBy: [{ datum: 'desc' }, { erstelltAm: 'desc' }], take: HOECHSTZAHL, }), db.buchung.count({ where: bedingung }), db.konto.findMany({ where: { betreuteId: betreute.id, ...nichtGeloescht }, select: { id: true, bezeichnung: true }, orderBy: { bezeichnung: 'asc' }, }), ]) const buchungen: BuchungEingabe[] = zeilen.map(zuBuchungEingabe) const zahlen = kennzahlen(buchungen) return (
) : undefined } />
0 ? 'Genau danach fragt der Rechtspfleger.' : 'Da fehlt nichts.' } ton={zahlen.beleg.ohneNachweis > 0 ? 'achtung' : 'gut'} />
{zahlen.vermischungen > 0 && } {buchungen.length === 0 ? (
) }