From 5f25d644f4bf050aef22f848d7c486d4d7b1ff4f Mon Sep 17 00:00:00 2001 From: Matthias Hochmeister Date: Mon, 30 Mar 2026 11:16:57 +0200 Subject: [PATCH] feat: add Buchhaltung data reset (Transaktionen, Konten, Bankkonten) to admin DataManagementTab --- backend/src/routes/admin.routes.ts | 16 +++++--- backend/src/services/cleanup.service.ts | 41 +++++++++++++++++++ .../components/admin/DataManagementTab.tsx | 3 ++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/backend/src/routes/admin.routes.ts b/backend/src/routes/admin.routes.ts index e94e64d..57fffa2 100644 --- a/backend/src/routes/admin.routes.ts +++ b/backend/src/routes/admin.routes.ts @@ -241,6 +241,9 @@ const CLEANUP_TARGETS: Record router.delete('/cleanup/reset-bestellungen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-bestellungen'; return resetHandler(req, res); }); router.delete('/cleanup/reset-ausruestung-anfragen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-ausruestung-anfragen'; return resetHandler(req, res); }); router.delete('/cleanup/reset-issues', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-issues'; return resetHandler(req, res); }); +router.delete('/cleanup/reset-buchhaltung-transaktionen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-transaktionen'; return resetHandler(req, res); }); +router.delete('/cleanup/reset-buchhaltung-konten', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-konten'; return resetHandler(req, res); }); +router.delete('/cleanup/reset-buchhaltung-bankkonten', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-bankkonten'; return resetHandler(req, res); }); router.delete('/cleanup/reset-checklist-history', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-checklist-history'; return resetHandler(req, res); }); router.delete('/cleanup/issues-all', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'issues-all'; return resetHandler(req, res); }); @@ -277,11 +280,14 @@ router.delete( // --------------------------------------------------------------------------- const RESET_TARGETS: Record Promise<{ count: number; deleted: boolean }>> = { - 'reset-bestellungen': (c) => cleanupService.resetBestellungenSequence(c), - 'reset-ausruestung-anfragen': (c) => cleanupService.resetAusruestungAnfragenSequence(c), - 'reset-issues': (c) => cleanupService.resetIssuesSequence(c), - 'issues-all': (c) => cleanupService.resetIssuesSequence(c), - 'reset-checklist-history': (c) => cleanupService.resetChecklistHistory(c), + 'reset-bestellungen': (c) => cleanupService.resetBestellungenSequence(c), + 'reset-ausruestung-anfragen': (c) => cleanupService.resetAusruestungAnfragenSequence(c), + 'reset-issues': (c) => cleanupService.resetIssuesSequence(c), + 'issues-all': (c) => cleanupService.resetIssuesSequence(c), + 'reset-checklist-history': (c) => cleanupService.resetChecklistHistory(c), + 'reset-buchhaltung-transaktionen': (c) => cleanupService.resetBuchhaltungTransaktionen(c), + 'reset-buchhaltung-konten': (c) => cleanupService.resetBuchhaltungKonten(c), + 'reset-buchhaltung-bankkonten': (c) => cleanupService.resetBuchhaltungBankkonten(c), }; const resetHandler = async (req: Request, res: Response): Promise => { diff --git a/backend/src/services/cleanup.service.ts b/backend/src/services/cleanup.service.ts index cab2cad..a5577bb 100644 --- a/backend/src/services/cleanup.service.ts +++ b/backend/src/services/cleanup.service.ts @@ -197,6 +197,47 @@ class CleanupService { logger.info(`Cleanup: truncated issues (${count} rows) and reset sequence`); return { count, deleted: true }; } + + async resetBuchhaltungTransaktionen(confirm: boolean): Promise { + if (!confirm) { + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_transaktionen'); + return { count: rows[0].count, deleted: false }; + } + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_transaktionen'); + const count = rows[0].count; + await pool.query('TRUNCATE buchhaltung_transaktionen CASCADE'); + try { await pool.query('ALTER SEQUENCE buchhaltung_transaktionen_id_seq RESTART WITH 1'); } catch { /* sequence may not exist */ } + logger.info(`Cleanup: truncated buchhaltung_transaktionen (${count} rows) and reset sequence`); + return { count, deleted: true }; + } + + async resetBuchhaltungKonten(confirm: boolean): Promise { + if (!confirm) { + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_konten'); + return { count: rows[0].count, deleted: false }; + } + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_konten'); + const count = rows[0].count; + await pool.query('TRUNCATE buchhaltung_transaktionen CASCADE'); + await pool.query('TRUNCATE buchhaltung_konten CASCADE'); + try { await pool.query('ALTER SEQUENCE buchhaltung_konten_id_seq RESTART WITH 1'); } catch { /* sequence may not exist */ } + try { await pool.query('ALTER SEQUENCE buchhaltung_transaktionen_id_seq RESTART WITH 1'); } catch { /* sequence may not exist */ } + logger.info(`Cleanup: truncated buchhaltung_konten (${count} rows) and reset sequence`); + return { count, deleted: true }; + } + + async resetBuchhaltungBankkonten(confirm: boolean): Promise { + if (!confirm) { + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_bankkonten'); + return { count: rows[0].count, deleted: false }; + } + const { rows } = await pool.query('SELECT COUNT(*)::int AS count FROM buchhaltung_bankkonten'); + const count = rows[0].count; + await pool.query('TRUNCATE buchhaltung_bankkonten CASCADE'); + try { await pool.query('ALTER SEQUENCE buchhaltung_bankkonten_id_seq RESTART WITH 1'); } catch { /* sequence may not exist */ } + logger.info(`Cleanup: truncated buchhaltung_bankkonten (${count} rows) and reset sequence`); + return { count, deleted: true }; + } } export default new CleanupService(); diff --git a/frontend/src/components/admin/DataManagementTab.tsx b/frontend/src/components/admin/DataManagementTab.tsx index dce4f49..a898a9c 100644 --- a/frontend/src/components/admin/DataManagementTab.tsx +++ b/frontend/src/components/admin/DataManagementTab.tsx @@ -38,6 +38,9 @@ const RESET_SECTIONS: ResetSection[] = [ { key: 'reset-ausruestung-anfragen', label: 'Interne Bestellungen zuruecksetzen', description: 'Alle internen Bestellungen und zugehoerige Positionen loeschen und Nummern zuruecksetzen.' }, { key: 'reset-issues', label: 'Issues zuruecksetzen', description: 'Alle Issues und Kommentare loeschen und Nummern zuruecksetzen.' }, { key: 'reset-checklist-history', label: 'Checklisten-Historie zuruecksetzen', description: 'Alle Checklisten-Ausfuehrungen und Faelligkeiten loeschen und Nummern zuruecksetzen.' }, + { key: 'reset-buchhaltung-transaktionen', label: 'Buchhaltung: Transaktionen loeschen', description: 'Alle Buchungen und Transaktionen loeschen und Nummerierung zuruecksetzen. Konten und Haushaltsjahre bleiben erhalten.' }, + { key: 'reset-buchhaltung-konten', label: 'Buchhaltung: Konten loeschen', description: 'Alle Konten und alle zugehoerigen Transaktionen loeschen und Nummerierung zuruecksetzen. Haushaltsjahre bleiben erhalten.' }, + { key: 'reset-buchhaltung-bankkonten', label: 'Buchhaltung: Bankkonten loeschen', description: 'Alle Bankkonten loeschen und Nummerierung zuruecksetzen.' }, ]; interface SectionState {