Wiederkehrende Zahlungen aufspueren
Am Anfang einer Betreuung weiss niemand, welche Vertraege es gibt. Die Antwort steht aber im Kontoauszug: Wer regelmaessig abbucht, hat einen Vertrag. Neu unter Vermoegen & Kasse wird aus hunderten Buchungszeilen eine Arbeitsliste. Aufbau: - Die Erkennung liegt als reine Funktionen in src/lib/finanzen/wiederkehrend.ts, ohne Datenbank. Nur so laesst sich jede Einordnung einzeln nachrechnen. - Der Datenzugriff steht getrennt in wiederkehrend-laden.ts. - Ein kleines Modell haelt fest, was bewusst KEIN Vertrag ist. Es haengt am normalisierten Empfaengernamen, nicht an Buchungen - nur so ueberlebt die Entscheidung den naechsten Import. Zwei Haltungen liegen der Erkennung zugrunde: Im Zweifel getrennt lassen. Zusammengefasst wird nur das Unstrittige: Gross- und Kleinschreibung, Satzzeichen, Umlaute, Rechtsform am Ende. Keine Aehnlichkeitssuche - "Stadtwerke Bamberg" und "Stadtwerke Bayreuth" trennen drei Zeichen und zwei Rechnungssteller. Zwei Zeilen zu viel sind harmlos; eine falsche Gruppe verbirgt einen Vertrag. Nichts behaupten, was nicht belegt ist. Statt "monatlich" steht dort "6 Zahlungen, etwa monatlich". Schwankt der Betrag, wird die Spanne genannt. Ohne erkennbaren Abstand wird nicht hochgerechnet, sondern gezeigt, was geflossen ist. Dazu eine zweite Liste fuer einzelne groessere Zahlungen: Die Gruppierung braucht zwei Zahlungen, ein Jahresbeitrag erscheint bei einem importierten Jahr aber nur einmal - und ausgerechnet Versicherungen zahlt man oft jaehrlich. Geprueft: 37 Einheitstests, die Haelfte davon in der Gegenrichtung, plus vier End-to-End-Tests auf beiden Geraeteprofilen. Der Browsertest hat zwei Fehler gefunden, die Typpruefung und Einheitstests durchgelassen haben - darunter ein verlorener Backslash, der die Vorbelegung des Beitrags stillschweigend verschluckte. Nebenbei: .claude/ ins .gitignore. Dort legen parallel arbeitende Agenten ihre Worktrees ab; ein "git add -A" haette einen kompletten zweiten Checkout eingecheckt. Refs #3
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import Link from 'next/link'
|
||||
import { ArrowRight, Banknote, FileDown, Landmark, Plus, Upload } from 'lucide-react'
|
||||
import { ArrowRight, Banknote, FileDown, Landmark, Plus, Repeat, Upload } from 'lucide-react'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
@@ -20,6 +21,7 @@ import { kennzahlen, vermischungsWarnung } from '@/lib/finanzen/kassenbuch'
|
||||
import { KATEGORIE_BESCHRIFTUNG } from '@/lib/finanzen/kategorien'
|
||||
import { laufendesBetreuungsjahr } from '@/lib/finanzen/betreuungsjahr'
|
||||
import { buchungenLaden, kontenLaden, kontostaendeZumStichtag, vermoegenLaden } from '@/lib/berichte/gemeinsam'
|
||||
import { offeneZahlungsgruppen } from '@/lib/finanzen/wiederkehrend-laden'
|
||||
|
||||
export const metadata = { title: 'Vermögen & Kasse' }
|
||||
|
||||
@@ -48,6 +50,7 @@ export default async function FinanzenSeite() {
|
||||
const zwoelfMonate = tagePlus(monatePlus(stichtag, -12), 1)
|
||||
const letzteZwoelf = buchungen.filter((b) => b.datum >= zwoelfMonate)
|
||||
const zahlen = kennzahlen(letzteZwoelf)
|
||||
const offeneGruppen = await offeneZahlungsgruppen(betreute.id)
|
||||
|
||||
const letzte = [...buchungen].sort((a, b) => b.datum.getTime() - a.datum.getTime()).slice(0, 8)
|
||||
|
||||
@@ -134,6 +137,22 @@ export default async function FinanzenSeite() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{offeneGruppen > 0 && (
|
||||
<Alert variant="hinweis">
|
||||
<Repeat aria-hidden="true" />
|
||||
<AlertDescription className="flex flex-wrap items-center justify-between gap-3">
|
||||
<span>
|
||||
<strong>{offeneGruppen}</strong> regelmäßige Abbuchung
|
||||
{offeneGruppen === 1 ? '' : 'en'} ohne hinterlegten Vertrag. Wer regelmäßig
|
||||
abbucht, hat einen — und der fehlt dann im Vermögensverzeichnis.
|
||||
</span>
|
||||
<Button asChild size="sm" variant="outline">
|
||||
<Link href="/finanzen/wiederkehrend">Ansehen</Link>
|
||||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{zahlen.vermischungen > 0 && <Vermischungswarnung />}
|
||||
|
||||
<Hinweisliste hinweise={hinweise} titel="Das solltest du nachtragen" />
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
import Link from 'next/link'
|
||||
import { AlertCircle, FileSearch, Plus, Repeat } from 'lucide-react'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { Leerzustand, SeitenKopf } from '@/components/seiten-kopf'
|
||||
import { Betrag } from '@/components/finanzen/bausteine'
|
||||
import {
|
||||
AlsGeklaertAbhaken,
|
||||
Zurueckholen,
|
||||
} from '@/components/finanzen/wiederkehrend-aktionen'
|
||||
import { finanzKontext } from '@/lib/finanzen/seite'
|
||||
import { wiederkehrendLaden } from '@/lib/finanzen/wiederkehrend-laden'
|
||||
import {
|
||||
EINZELZAHLUNG_AB_CENT,
|
||||
RHYTHMUS_BESCHRIFTUNG,
|
||||
rhythmusErklaerung,
|
||||
} from '@/lib/finanzen/wiederkehrend'
|
||||
import { centZuZahl } from '@/lib/db'
|
||||
import { formatCent, formatDatum } from '@/lib/utils'
|
||||
|
||||
export const metadata = { title: 'Wiederkehrende Zahlungen' }
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
/**
|
||||
* Wiederkehrende Zahlungen — die Suche nach unbekannten Verträgen.
|
||||
*
|
||||
* Am Anfang einer Betreuung weiß niemand, welche Verträge es gibt. Die
|
||||
* Antwort steht im Kontoauszug: Wer regelmäßig abbucht, hat einen Vertrag.
|
||||
* Diese Seite macht aus hunderten Buchungszeilen eine Arbeitsliste.
|
||||
*
|
||||
* Sie legt von sich aus nichts an. Jede Zeile endet in einer Entscheidung,
|
||||
* die ein Mensch trifft — Vertrag anlegen oder abhaken.
|
||||
*/
|
||||
export default async function WiederkehrendSeite() {
|
||||
const { betreute, darfSchreiben } = await finanzKontext()
|
||||
const schreiben = darfSchreiben('FINANZEN')
|
||||
const bild = await wiederkehrendLaden(betreute.id)
|
||||
|
||||
const ohneVertrag = bild.gruppen.filter((gruppe) => gruppe.vertragId === null)
|
||||
const mitVertrag = bild.gruppen.filter((gruppe) => gruppe.vertragId !== null)
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<SeitenKopf
|
||||
titel="Wiederkehrende Zahlungen"
|
||||
beschreibung="Wer regelmäßig abbucht, hat einen Vertrag. Hier stehen die Kandidaten, zu denen noch keiner in der Akte liegt."
|
||||
aktionen={
|
||||
<Button asChild variant="outline">
|
||||
<Link href="/finanzen/buchungen">Zu den Buchungen</Link>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
{bild.ausgabenGesamt === 0 ? (
|
||||
<Leerzustand
|
||||
icon={FileSearch}
|
||||
titel="Noch keine Ausgaben erfasst"
|
||||
beschreibung="Diese Auswertung liest die Kontobewegungen. Importiere zuerst einen Kontoauszug, dann findest du hier die regelmäßigen Abbuchungen."
|
||||
aktion={
|
||||
<Button asChild>
|
||||
<Link href="/finanzen/buchungen/import">Kontoauszug einlesen</Link>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{/* --- Kandidaten ohne Vertrag ----------------------------------- */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-base">
|
||||
<Repeat className="size-5" aria-hidden="true" />
|
||||
Ohne hinterlegten Vertrag
|
||||
{ohneVertrag.length > 0 && (
|
||||
<Badge variant="secondary">{ohneVertrag.length}</Badge>
|
||||
)}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Nach Jahresbetrag sortiert — was am meisten kostet, will man zuerst geklärt haben.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{ohneVertrag.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Zu jeder regelmäßigen Abbuchung liegt ein Vertrag in der Akte. Das ist der
|
||||
Zustand, den man haben will.
|
||||
</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Empfänger</TableHead>
|
||||
<TableHead>Rhythmus</TableHead>
|
||||
<TableHead className="text-right">je Zahlung</TableHead>
|
||||
<TableHead className="text-right">im Jahr</TableHead>
|
||||
<TableHead>Zeitraum</TableHead>
|
||||
{schreiben && <TableHead className="text-right">Und jetzt?</TableHead>}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{ohneVertrag.map((gruppe) => (
|
||||
<TableRow key={gruppe.schluessel}>
|
||||
<TableCell className="align-top">
|
||||
<p className="font-medium">{gruppe.anzeigename}</p>
|
||||
{gruppe.schreibweisen.length > 1 && (
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{gruppe.schreibweisen.length} Schreibweisen zusammengefasst
|
||||
</p>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="align-top">
|
||||
<span
|
||||
className={
|
||||
gruppe.rhythmus === 'UNREGELMAESSIG'
|
||||
? 'text-muted-foreground'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{RHYTHMUS_BESCHRIFTUNG[gruppe.rhythmus]}
|
||||
</span>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{rhythmusErklaerung(gruppe)}
|
||||
</p>
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="text-right align-top">
|
||||
<Betrag cent={centZuZahl(gruppe.betragCent)} />
|
||||
{gruppe.betragSchwankt && (
|
||||
<p className="mt-0.5 text-xs text-ampel-orange">
|
||||
schwankt: {formatCent(centZuZahl(gruppe.kleinsterBetragCent))} bis{' '}
|
||||
{formatCent(centZuZahl(gruppe.groessterBetragCent))}
|
||||
</p>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="text-right align-top">
|
||||
<Betrag cent={centZuZahl(gruppe.jahresbetragCent)} />
|
||||
{gruppe.rhythmus === 'UNREGELMAESSIG' && (
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
tatsächlich gezahlt
|
||||
</p>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="align-top text-sm text-muted-foreground">
|
||||
{formatDatum(gruppe.ersteZahlung)}
|
||||
<br />
|
||||
bis {formatDatum(gruppe.letzteZahlung)}
|
||||
</TableCell>
|
||||
|
||||
{schreiben && (
|
||||
<TableCell className="align-top">
|
||||
<div className="flex flex-col items-end gap-2">
|
||||
<Button asChild size="sm" variant="outline">
|
||||
<Link
|
||||
href={`/vertraege/neu?gesellschaft=${encodeURIComponent(
|
||||
gruppe.anzeigename,
|
||||
)}&beitragCent=${gruppe.betragCent}&rhythmus=${gruppe.rhythmus}`}
|
||||
>
|
||||
<Plus aria-hidden="true" />
|
||||
Vertrag anlegen
|
||||
</Link>
|
||||
</Button>
|
||||
<AlsGeklaertAbhaken
|
||||
betreuteId={betreute.id}
|
||||
schluessel={gruppe.schluessel}
|
||||
anzeigename={gruppe.anzeigename}
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* --- Einzelne groessere Zahlungen ------------------------------ */}
|
||||
{bild.einzelne.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Einzelne größere Zahlungen</CardTitle>
|
||||
<CardDescription>
|
||||
Kein Vertragsverdacht, sondern eine Merkliste. Die Gruppierung oben braucht
|
||||
mindestens zwei Zahlungen — eine jährlich abgebuchte Prämie erscheint bei
|
||||
einem importierten Jahr aber nur einmal. Ausgerechnet Versicherungen werden
|
||||
oft jährlich gezahlt, deshalb steht hier alles ab{' '}
|
||||
{formatCent(centZuZahl(EINZELZAHLUNG_AB_CENT))}.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Empfänger</TableHead>
|
||||
<TableHead>Datum</TableHead>
|
||||
<TableHead className="text-right">Betrag</TableHead>
|
||||
<TableHead>Vertrag</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{bild.einzelne.map((zahlung) => (
|
||||
<TableRow key={zahlung.buchungId}>
|
||||
<TableCell className="font-medium">{zahlung.anzeigename}</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground">
|
||||
{formatDatum(zahlung.datum)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Betrag cent={centZuZahl(zahlung.betragCent)} />
|
||||
</TableCell>
|
||||
<TableCell className="text-sm">
|
||||
{zahlung.vertragBezeichnung ? (
|
||||
<Badge variant="secondary">{zahlung.vertragBezeichnung}</Badge>
|
||||
) : (
|
||||
<span className="text-muted-foreground">keiner</span>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* --- Bereits erklaert ------------------------------------------ */}
|
||||
{mitVertrag.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Schon einem Vertrag zugeordnet</CardTitle>
|
||||
<CardDescription>
|
||||
Erkannt am Namen der Gesellschaft. Steht hier etwas Falsches, stimmt die
|
||||
Schreibweise am Vertrag nicht mit der auf dem Kontoauszug überein.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="divide-y text-sm">
|
||||
{mitVertrag.map((gruppe) => (
|
||||
<li
|
||||
key={gruppe.schluessel}
|
||||
className="flex flex-wrap items-center justify-between gap-2 py-2"
|
||||
>
|
||||
<span>
|
||||
<span className="font-medium">{gruppe.anzeigename}</span>
|
||||
<span className="ml-2 text-muted-foreground">
|
||||
{RHYTHMUS_BESCHRIFTUNG[gruppe.rhythmus]},{' '}
|
||||
{formatCent(centZuZahl(gruppe.jahresbetragCent))} im Jahr
|
||||
</span>
|
||||
</span>
|
||||
<Button asChild variant="ghost" size="sm">
|
||||
<Link href={`/vertraege/${gruppe.vertragId}`}>
|
||||
{gruppe.vertragBezeichnung}
|
||||
</Link>
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* --- Abgehakt --------------------------------------------------- */}
|
||||
{bild.abgehakt.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Als „kein Vertrag“ abgehakt</CardTitle>
|
||||
<CardDescription>
|
||||
Diese Empfänger bleiben aus der Liste heraus, auch nach dem nächsten Import.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="divide-y text-sm">
|
||||
{bild.abgehakt.map((eintrag) => (
|
||||
<li
|
||||
key={eintrag.id}
|
||||
className="flex flex-wrap items-center justify-between gap-2 py-2"
|
||||
>
|
||||
<span>
|
||||
<span className="font-medium">{eintrag.anzeigename}</span>
|
||||
{eintrag.begruendung && (
|
||||
<span className="ml-2 text-muted-foreground">
|
||||
— {eintrag.begruendung}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
{schreiben && (
|
||||
<Zurueckholen betreuteId={betreute.id} eintragId={eintrag.id} />
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Alert variant="hinweis">
|
||||
<AlertCircle aria-hidden="true" />
|
||||
<AlertDescription>
|
||||
Diese Seite wertet nur aus, sie legt nichts an. Gruppiert wird nach dem Empfänger
|
||||
aus dem Kontoauszug — Groß- und Kleinschreibung, Satzzeichen und die Rechtsform
|
||||
werden dabei zusammengefasst. Ähnliche, aber verschiedene Namen bleiben bewusst
|
||||
getrennt: „Stadtwerke Bamberg“ und „Stadtwerke Bayreuth“ sind zwei Rechnungssteller.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,62 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
import { Info } from 'lucide-react'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { SeitenKopf } from '@/components/seiten-kopf'
|
||||
import { LEERER_VERTRAG, VertragFormular } from '@/components/vertraege/vertrag-formular'
|
||||
import { aktiveBetreute, erfordereBenutzer, erfordereZugang } from '@/lib/auth/sitzung'
|
||||
import { alsZahlRhythmus, type Rhythmus } from '@/lib/finanzen/wiederkehrend'
|
||||
import { betragFormatieren } from '@/lib/finanzen/betrag'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function VertragAnlegen() {
|
||||
/**
|
||||
* Uebernimmt eine Vorbelegung aus der Adresszeile.
|
||||
*
|
||||
* Sie kommt von "Wiederkehrende Zahlungen": Dort steht schon, wer da
|
||||
* abbucht und wie viel. Diese Angaben noch einmal abzutippen waere genau
|
||||
* die Arbeit, die die Auswertung ersparen soll.
|
||||
*
|
||||
* Uebernommen wird nur, was aus dem Kontoauszug ablesbar ist - Gesellschaft,
|
||||
* Beitrag, Rhythmus. Die Bezeichnung und die Vertragsart bleiben leer: Was
|
||||
* fuer ein Vertrag das ist, steht nicht im Auszug, und eine geratene
|
||||
* Vorbelegung wird uebersehen statt korrigiert.
|
||||
*/
|
||||
function vorbelegung(parameter: Record<string, string | string[] | undefined>) {
|
||||
const text = (name: string): string => {
|
||||
const wert = parameter[name]
|
||||
return typeof wert === 'string' ? wert.trim() : ''
|
||||
}
|
||||
|
||||
const werte = { ...LEERER_VERTRAG }
|
||||
let etwasUebernommen = false
|
||||
|
||||
const gesellschaft = text('gesellschaft')
|
||||
if (gesellschaft) {
|
||||
werte.gesellschaft = gesellschaft.slice(0, 200)
|
||||
etwasUebernommen = true
|
||||
}
|
||||
|
||||
const cent = text('beitragCent')
|
||||
if (/^[0-9]{1,15}$/.test(cent)) {
|
||||
werte.beitrag = betragFormatieren(BigInt(cent))
|
||||
etwasUebernommen = true
|
||||
}
|
||||
|
||||
const rhythmus = alsZahlRhythmus(text('rhythmus') as Rhythmus)
|
||||
if (rhythmus) {
|
||||
werte.rhythmus = rhythmus as typeof werte.rhythmus
|
||||
etwasUebernommen = true
|
||||
}
|
||||
|
||||
return { werte, etwasUebernommen }
|
||||
}
|
||||
|
||||
export default async function VertragAnlegen({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<Record<string, string | string[] | undefined>>
|
||||
}) {
|
||||
const parameter = await searchParams
|
||||
const benutzer = await erfordereBenutzer('/vertraege/neu')
|
||||
const aktive = await aktiveBetreute(benutzer)
|
||||
if (!aktive) return null
|
||||
@@ -13,6 +64,8 @@ export default async function VertragAnlegen() {
|
||||
const { darfSchreiben } = await erfordereZugang(aktive.id, 'VERTRAEGE', 'lesen')
|
||||
if (!darfSchreiben('VERTRAEGE')) redirect('/vertraege')
|
||||
|
||||
const { werte, etwasUebernommen } = vorbelegung(parameter)
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<SeitenKopf
|
||||
@@ -25,7 +78,18 @@ export default async function VertragAnlegen() {
|
||||
]}
|
||||
/>
|
||||
|
||||
<VertragFormular betreuteId={aktive.id} werte={LEERER_VERTRAG} />
|
||||
{etwasUebernommen && (
|
||||
<Alert variant="hinweis">
|
||||
<Info aria-hidden="true" />
|
||||
<AlertDescription>
|
||||
Gesellschaft, Beitrag und Rhythmus sind aus den wiederkehrenden Zahlungen
|
||||
übernommen. Bezeichnung und Art musst du selbst wählen — was für ein Vertrag das
|
||||
ist, steht nicht im Kontoauszug.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<VertragFormular betreuteId={aktive.id} werte={werte} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user