From 967cad592291fa58dcaea09e740d232733c2cf9e Mon Sep 17 00:00:00 2001 From: Matthias Hochmeister Date: Tue, 14 Apr 2026 13:46:07 +0200 Subject: [PATCH] feat(buchhaltung): add edit support for pending transactions --- frontend/src/pages/Buchhaltung.tsx | 50 +++++++++++++++++-- frontend/src/pages/BuchhaltungKontoDetail.tsx | 16 ++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/frontend/src/pages/Buchhaltung.tsx b/frontend/src/pages/Buchhaltung.tsx index fd652a5..de5b020 100644 --- a/frontend/src/pages/Buchhaltung.tsx +++ b/frontend/src/pages/Buchhaltung.tsx @@ -501,12 +501,14 @@ function TransaktionDialog({ haushaltsjahre, selectedJahrId, onSave, + existing, }: { open: boolean; onClose: () => void; haushaltsjahre: Haushaltsjahr[]; selectedJahrId: number | null; onSave: (data: TransaktionFormData) => void; + existing?: Transaktion; }) { const today = new Date().toISOString().slice(0, 10); const [form, setForm] = useState({ @@ -537,13 +539,32 @@ function TransaktionDialog({ }); useEffect(() => { - if (open) setForm(f => ({ ...f, haushaltsjahr_id: selectedJahrId || 0, datum: today })); + if (open) { + if (existing) { + setForm({ + haushaltsjahr_id: existing.haushaltsjahr_id, + typ: existing.typ as 'einnahme' | 'ausgabe', + betrag: Number(existing.betrag), + datum: existing.datum.slice(0, 10), + konto_id: existing.konto_id, + bankkonto_id: existing.bankkonto_id, + beschreibung: existing.beschreibung || '', + empfaenger_auftraggeber: existing.empfaenger_auftraggeber || '', + verwendungszweck: existing.verwendungszweck || '', + beleg_nr: existing.beleg_nr || '', + bestellung_id: existing.bestellung_id, + ausgaben_typ: existing.ausgaben_typ, + }); + } else { + setForm(f => ({ ...f, haushaltsjahr_id: selectedJahrId || 0, datum: today })); + } + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [open]); return ( - Neue Transaktion + {existing ? 'Transaktion bearbeiten' : 'Neue Transaktion'} @@ -609,7 +630,7 @@ function TransaktionDialog({ - + ); @@ -1119,6 +1140,7 @@ function TransaktionenTab({ haushaltsjahre, selectedJahrId, onJahrChange }: { const { hasPermission } = usePermissionContext(); const [filters, setFilters] = useState({ haushaltsjahr_id: selectedJahrId || undefined }); const [createOpen, setCreateOpen] = useState(false); + const [editingTx, setEditingTx] = useState(null); const [filterAusgabenTyp, setFilterAusgabenTyp] = useState(''); const [txSubTab, setTxSubTab] = useState(0); @@ -1150,6 +1172,12 @@ function TransaktionenTab({ haushaltsjahre, selectedJahrId, onJahrChange }: { onError: () => showError('Transaktion konnte nicht erstellt werden'), }); + const updateMut = useMutation({ + mutationFn: ({ id, data }: { id: number; data: Partial }) => buchhaltungApi.updateTransaktion(id, data), + onSuccess: () => { qc.invalidateQueries({ queryKey: ['buchhaltung-transaktionen'] }); setEditingTx(null); showSuccess('Transaktion aktualisiert'); }, + onError: () => showError('Aktualisierung fehlgeschlagen'), + }); + const buchenMut = useMutation({ mutationFn: (id: number) => buchhaltungApi.buchenTransaktion(id), onSuccess: () => { qc.invalidateQueries({ queryKey: ['buchhaltung-transaktionen'] }); qc.invalidateQueries({ queryKey: ['buchhaltung-stats'] }); showSuccess('Transaktion gebucht'); }, @@ -1383,6 +1411,13 @@ function TransaktionenTab({ haushaltsjahre, selectedJahrId, onJahrChange }: { Stornieren )} + {t.status === 'entwurf' && hasPermission('buchhaltung:edit') && ( + + setEditingTx(t)}> + + + + )} {t.status === 'entwurf' && hasPermission('buchhaltung:delete') && ( deleteMut.mutate(t.id)}> @@ -1413,6 +1448,15 @@ function TransaktionenTab({ haushaltsjahre, selectedJahrId, onJahrChange }: { onSave={data => createMut.mutate(data)} /> + setEditingTx(null)} + haushaltsjahre={haushaltsjahre} + selectedJahrId={selectedJahrId} + existing={editingTx ?? undefined} + onSave={data => updateMut.mutate({ id: editingTx!.id, data })} + /> + setErstattungOpen(false)} diff --git a/frontend/src/pages/BuchhaltungKontoDetail.tsx b/frontend/src/pages/BuchhaltungKontoDetail.tsx index 7b852ee..97733a9 100644 --- a/frontend/src/pages/BuchhaltungKontoDetail.tsx +++ b/frontend/src/pages/BuchhaltungKontoDetail.tsx @@ -4,7 +4,7 @@ import { useQuery } from '@tanstack/react-query'; import { Box, Typography, Button, Grid, Card, CardContent, Table, TableHead, TableBody, TableRow, TableCell, - LinearProgress, Chip, Alert, Skeleton, TableContainer, Paper, + Chip, Alert, Skeleton, TableContainer, Paper, IconButton, CircularProgress, } from '@mui/material'; import { ArrowBack, KeyboardArrowDown, KeyboardArrowUp } from '@mui/icons-material'; @@ -16,23 +16,13 @@ import type { AusgabenTyp, BuchhaltungAudit } from '../types/buchhaltung.types'; const fmtEur = (n: number) => new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(n); function BudgetCard({ label, budget, spent }: { label: string; budget: number; spent: number }) { - const utilization = budget > 0 ? Math.min((spent / budget) * 100, 100) : 0; - const over = spent > budget && budget > 0; return ( {label} {fmtEur(Number(spent))} {budget > 0 && ( - <> - Budget: {fmtEur(Number(budget))} - 80 ? 'warning' : 'primary'} - sx={{ mt: 1, height: 6, borderRadius: 3 }} - /> - + Budget: {fmtEur(Number(budget))} )} @@ -204,7 +194,7 @@ export default function BuchhaltungKontoDetail() { const childIsEinfach = (child.budget_typ || 'detailliert') === 'einfach'; const childTotal = childIsEinfach ? Number(child.budget_gesamt || 0) - : Number(child.budget_gwg) + Number(child.budget_anlagen) + Number(child.budget_instandhaltung); + : Number(child.budget_gwg || 0) + Number(child.budget_anlagen || 0) + Number(child.budget_instandhaltung || 0); return (