feat: add Buchhaltung module with fiscal years, budget accounts, transactions, and approval workflow
This commit is contained in:
339
backend/src/controllers/buchhaltung.controller.ts
Normal file
339
backend/src/controllers/buchhaltung.controller.ts
Normal file
@@ -0,0 +1,339 @@
|
||||
import { Request, Response } from 'express';
|
||||
import buchhaltungService from '../services/buchhaltung.service';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
const param = (req: Request, key: string): string => req.params[key] as string;
|
||||
|
||||
class BuchhaltungController {
|
||||
|
||||
// ── Haushaltsjahre ──────────────────────────────────────────────────────────
|
||||
|
||||
async listHaushaltsjahre(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.getAllHaushaltsjahre();
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.listHaushaltsjahre', { error });
|
||||
res.status(500).json({ success: false, message: 'Haushaltsjahre konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createHaushaltsjahr(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.createHaushaltsjahr(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.createHaushaltsjahr', { error });
|
||||
res.status(500).json({ success: false, message: 'Haushaltsjahr konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateHaushaltsjahr(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.updateHaushaltsjahr(id, req.body);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Haushaltsjahr nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.updateHaushaltsjahr', { error });
|
||||
res.status(500).json({ success: false, message: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
async closeHaushaltsjahr(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.closeHaushaltsjahr(id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Haushaltsjahr nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.closeHaushaltsjahr', { error });
|
||||
res.status(400).json({ success: false, message: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Konto-Typen ─────────────────────────────────────────────────────────────
|
||||
|
||||
async listKontoTypen(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.getAllKontoTypen();
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.listKontoTypen', { error });
|
||||
res.status(500).json({ success: false, message: 'Kontotypen konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Bankkonten ───────────────────────────────────────────────────────────────
|
||||
|
||||
async listBankkonten(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.getAllBankkonten();
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.listBankkonten', { error });
|
||||
res.status(500).json({ success: false, message: 'Bankkonten konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createBankkonto(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.createBankkonto(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.createBankkonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Bankkonto konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateBankkonto(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.updateBankkonto(id, req.body);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Bankkonto nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.updateBankkonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Bankkonto konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteBankkonto(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
await buchhaltungService.deactivateBankkonto(id);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.deleteBankkonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Bankkonto konnte nicht deaktiviert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Konten ───────────────────────────────────────────────────────────────────
|
||||
|
||||
async listKonten(req: Request, res: Response): Promise<void> {
|
||||
const haushaltsjahrId = parseInt(req.query.haushaltsjahr_id as string, 10);
|
||||
if (isNaN(haushaltsjahrId)) { res.status(400).json({ success: false, message: 'haushaltsjahr_id erforderlich' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.getAllKonten(haushaltsjahrId);
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.listKonten', { error });
|
||||
res.status(500).json({ success: false, message: 'Konten konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createKonto(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.createKonto(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.createKonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Konto konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateKonto(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.updateKonto(id, req.body);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Konto nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.updateKonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Konto konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteKonto(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
await buchhaltungService.deleteKonto(id);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.deleteKonto', { error });
|
||||
res.status(500).json({ success: false, message: 'Konto konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getKontoBudget(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.getBudgetUtilisation(id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Konto nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.getKontoBudget', { error });
|
||||
res.status(500).json({ success: false, message: 'Budgetauslastung konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Stats ────────────────────────────────────────────────────────────────────
|
||||
|
||||
async getStats(req: Request, res: Response): Promise<void> {
|
||||
const haushaltsjahrId = parseInt(req.query.haushaltsjahr_id as string, 10);
|
||||
if (isNaN(haushaltsjahrId)) { res.status(400).json({ success: false, message: 'haushaltsjahr_id erforderlich' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.getOverview(haushaltsjahrId);
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.getStats', { error });
|
||||
res.status(500).json({ success: false, message: 'Statistik konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Transaktionen ────────────────────────────────────────────────────────────
|
||||
|
||||
async listTransaktionen(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const filters = {
|
||||
haushaltsjahr_id: req.query.haushaltsjahr_id ? parseInt(req.query.haushaltsjahr_id as string, 10) : undefined,
|
||||
konto_id: req.query.konto_id ? parseInt(req.query.konto_id as string, 10) : undefined,
|
||||
status: req.query.status as string | undefined,
|
||||
typ: req.query.typ as string | undefined,
|
||||
datum_von: req.query.datum_von as string | undefined,
|
||||
datum_bis: req.query.datum_bis as string | undefined,
|
||||
search: req.query.search as string | undefined,
|
||||
};
|
||||
const data = await buchhaltungService.listTransaktionen(filters);
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.listTransaktionen', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktionen konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getTransaktion(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.getTransaktionById(id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Transaktion nicht gefunden' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.getTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createTransaktion(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.createTransaktion(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.createTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateTransaktion(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.updateTransaktion(id, req.body, req.user!.id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Transaktion nicht gefunden oder nicht mehr bearbeitbar' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.updateTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteTransaktion(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const deleted = await buchhaltungService.deleteTransaktion(id);
|
||||
if (!deleted) { res.status(404).json({ success: false, message: 'Transaktion nicht gefunden oder nicht löschbar' }); return; }
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.deleteTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async buchenTransaktion(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.bookTransaktion(id, req.user!.id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Transaktion nicht gefunden oder bereits gebucht' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.buchenTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht gebucht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async stornoTransaktion(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.stornoTransaktion(id, req.user!.id);
|
||||
if (!data) { res.status(404).json({ success: false, message: 'Transaktion nicht stornierbar' }); return; }
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.stornoTransaktion', { error });
|
||||
res.status(500).json({ success: false, message: 'Transaktion konnte nicht storniert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Belege ───────────────────────────────────────────────────────────────────
|
||||
|
||||
async uploadBeleg(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
if (!req.file) { res.status(400).json({ success: false, message: 'Keine Datei hochgeladen' }); return; }
|
||||
try {
|
||||
const data = await buchhaltungService.uploadBeleg(id, req.file, req.user!.id);
|
||||
res.status(201).json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.uploadBeleg', { error });
|
||||
res.status(500).json({ success: false, message: 'Beleg konnte nicht hochgeladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteBeleg(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) { res.status(400).json({ success: false, message: 'Ungültige ID' }); return; }
|
||||
try {
|
||||
const deleted = await buchhaltungService.deleteBeleg(id);
|
||||
if (!deleted) { res.status(404).json({ success: false, message: 'Beleg nicht gefunden' }); return; }
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.deleteBeleg', { error });
|
||||
res.status(500).json({ success: false, message: 'Beleg konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ── Einstellungen ────────────────────────────────────────────────────────────
|
||||
|
||||
async getEinstellungen(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const data = await buchhaltungService.getEinstellungen();
|
||||
res.json({ success: true, data });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.getEinstellungen', { error });
|
||||
res.status(500).json({ success: false, message: 'Einstellungen konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async setEinstellungen(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
await buchhaltungService.setEinstellungen(req.body);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('BuchhaltungController.setEinstellungen', { error });
|
||||
res.status(500).json({ success: false, message: 'Einstellungen konnten nicht gespeichert werden' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new BuchhaltungController();
|
||||
Reference in New Issue
Block a user