new features
This commit is contained in:
466
backend/src/controllers/bestellung.controller.ts
Normal file
466
backend/src/controllers/bestellung.controller.ts
Normal file
@@ -0,0 +1,466 @@
|
||||
import { Request, Response } from 'express';
|
||||
import bestellungService from '../services/bestellung.service';
|
||||
import logger from '../utils/logger';
|
||||
import fs from 'fs';
|
||||
|
||||
// Helper to safely extract a route param as string
|
||||
const param = (req: Request, key: string): string => req.params[key] as string;
|
||||
|
||||
class BestellungController {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vendors
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async listVendors(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const vendors = await bestellungService.getVendors();
|
||||
res.status(200).json({ success: true, data: vendors });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.listVendors error', { error });
|
||||
res.status(500).json({ success: false, message: 'Lieferanten konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createVendor(req: Request, res: Response): Promise<void> {
|
||||
const { name } = req.body;
|
||||
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Name ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const vendor = await bestellungService.createVendor(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data: vendor });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.createVendor error', { error });
|
||||
res.status(500).json({ success: false, message: 'Lieferant konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateVendor(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 vendor = await bestellungService.updateVendor(id, req.body, req.user!.id);
|
||||
if (!vendor) {
|
||||
res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: vendor });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.updateVendor error', { error });
|
||||
res.status(500).json({ success: false, message: 'Lieferant konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteVendor(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 bestellungService.deleteVendor(id);
|
||||
if (!deleted) {
|
||||
res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Lieferant gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.deleteVendor error', { error });
|
||||
res.status(500).json({ success: false, message: 'Lieferant konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Orders
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async listOrders(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const filters: { status?: string; lieferant_id?: number; besteller_id?: string } = {};
|
||||
if (req.query.status) filters.status = req.query.status as string;
|
||||
if (req.query.lieferant_id) filters.lieferant_id = parseInt(req.query.lieferant_id as string, 10);
|
||||
if (req.query.besteller_id) filters.besteller_id = req.query.besteller_id as string;
|
||||
|
||||
const orders = await bestellungService.getOrders(filters);
|
||||
res.status(200).json({ success: true, data: orders });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.listOrders error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellungen konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getOrder(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 order = await bestellungService.getOrderById(id);
|
||||
if (!order) {
|
||||
res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: order });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.getOrder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellung konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createOrder(req: Request, res: Response): Promise<void> {
|
||||
const { titel } = req.body;
|
||||
if (!titel || typeof titel !== 'string' || titel.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Titel ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const order = await bestellungService.createOrder(req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data: order });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.createOrder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellung konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateOrder(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 order = await bestellungService.updateOrder(id, req.body, req.user!.id);
|
||||
if (!order) {
|
||||
res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: order });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.updateOrder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellung konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteOrder(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 bestellungService.deleteOrder(id, req.user!.id);
|
||||
if (!deleted) {
|
||||
res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Bestellung gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.deleteOrder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellung konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateStatus(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;
|
||||
}
|
||||
const { status } = req.body;
|
||||
if (!status || typeof status !== 'string') {
|
||||
res.status(400).json({ success: false, message: 'Status ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const order = await bestellungService.updateOrderStatus(id, status, req.user!.id);
|
||||
if (!order) {
|
||||
res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: order });
|
||||
} catch (error: any) {
|
||||
if (error.message?.includes('Ungültiger Statusübergang')) {
|
||||
res.status(400).json({ success: false, message: error.message });
|
||||
return;
|
||||
}
|
||||
logger.error('BestellungController.updateStatus error', { error });
|
||||
res.status(500).json({ success: false, message: 'Status konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Line Items
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async addLineItem(req: Request, res: Response): Promise<void> {
|
||||
const bestellungId = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(bestellungId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
|
||||
return;
|
||||
}
|
||||
const { artikel, menge } = req.body;
|
||||
if (!artikel || typeof artikel !== 'string' || artikel.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Artikel ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
if (menge === undefined || menge === null || menge <= 0) {
|
||||
res.status(400).json({ success: false, message: 'Menge muss größer als 0 sein' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const item = await bestellungService.addLineItem(bestellungId, req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data: item });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.addLineItem error', { error });
|
||||
res.status(500).json({ success: false, message: 'Position konnte nicht hinzugefügt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateLineItem(req: Request, res: Response): Promise<void> {
|
||||
const itemId = parseInt(param(req, 'itemId'), 10);
|
||||
if (isNaN(itemId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const item = await bestellungService.updateLineItem(itemId, req.body, req.user!.id);
|
||||
if (!item) {
|
||||
res.status(404).json({ success: false, message: 'Position nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: item });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.updateLineItem error', { error });
|
||||
res.status(500).json({ success: false, message: 'Position konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteLineItem(req: Request, res: Response): Promise<void> {
|
||||
const itemId = parseInt(param(req, 'itemId'), 10);
|
||||
if (isNaN(itemId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const deleted = await bestellungService.deleteLineItem(itemId, req.user!.id);
|
||||
if (!deleted) {
|
||||
res.status(404).json({ success: false, message: 'Position nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Position gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.deleteLineItem error', { error });
|
||||
res.status(500).json({ success: false, message: 'Position konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateReceivedQuantity(req: Request, res: Response): Promise<void> {
|
||||
const itemId = parseInt(param(req, 'itemId'), 10);
|
||||
if (isNaN(itemId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
|
||||
return;
|
||||
}
|
||||
const { menge } = req.body;
|
||||
if (menge === undefined || menge === null || menge < 0) {
|
||||
res.status(400).json({ success: false, message: 'Erhaltene Menge muss >= 0 sein' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const item = await bestellungService.updateReceivedQuantity(itemId, menge, req.user!.id);
|
||||
if (!item) {
|
||||
res.status(404).json({ success: false, message: 'Position nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: item });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.updateReceivedQuantity error', { error });
|
||||
res.status(500).json({ success: false, message: 'Liefermenge konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Files
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async uploadFile(req: Request, res: Response): Promise<void> {
|
||||
const bestellungId = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(bestellungId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
|
||||
return;
|
||||
}
|
||||
const file = (req as any).file;
|
||||
if (!file) {
|
||||
res.status(400).json({ success: false, message: 'Keine Datei hochgeladen' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const fileRecord = await bestellungService.addFile(bestellungId, {
|
||||
dateiname: file.originalname,
|
||||
dateipfad: file.path,
|
||||
dateityp: file.mimetype,
|
||||
dateigroesse: file.size,
|
||||
}, req.user!.id);
|
||||
res.status(201).json({ success: true, data: fileRecord });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.uploadFile error', { error });
|
||||
res.status(500).json({ success: false, message: 'Datei konnte nicht hochgeladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteFile(req: Request, res: Response): Promise<void> {
|
||||
const fileId = parseInt(param(req, 'fileId'), 10);
|
||||
if (isNaN(fileId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Datei-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await bestellungService.deleteFile(fileId, req.user!.id);
|
||||
if (!result) {
|
||||
res.status(404).json({ success: false, message: 'Datei nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
// Remove from disk
|
||||
try {
|
||||
if (result.dateipfad && fs.existsSync(result.dateipfad)) {
|
||||
fs.unlinkSync(result.dateipfad);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn('Failed to delete file from disk', { path: result.dateipfad, error: err });
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Datei gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.deleteFile error', { error });
|
||||
res.status(500).json({ success: false, message: 'Datei konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async listFiles(req: Request, res: Response): Promise<void> {
|
||||
const bestellungId = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(bestellungId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const files = await bestellungService.getFilesByOrder(bestellungId);
|
||||
res.status(200).json({ success: true, data: files });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.listFiles error', { error });
|
||||
res.status(500).json({ success: false, message: 'Dateien konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Reminders
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async addReminder(req: Request, res: Response): Promise<void> {
|
||||
const bestellungId = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(bestellungId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
|
||||
return;
|
||||
}
|
||||
const { titel, faellig_am } = req.body;
|
||||
if (!titel || typeof titel !== 'string' || titel.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Titel ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
if (!faellig_am) {
|
||||
res.status(400).json({ success: false, message: 'Fälligkeitsdatum ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const reminder = await bestellungService.addReminder(bestellungId, req.body, req.user!.id);
|
||||
res.status(201).json({ success: true, data: reminder });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.addReminder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Erinnerung konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async markReminderDone(req: Request, res: Response): Promise<void> {
|
||||
const remId = parseInt(param(req, 'remId'), 10);
|
||||
if (isNaN(remId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Erinnerungs-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const reminder = await bestellungService.markReminderDone(remId, req.user!.id);
|
||||
if (!reminder) {
|
||||
res.status(404).json({ success: false, message: 'Erinnerung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: reminder });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.markReminderDone error', { error });
|
||||
res.status(500).json({ success: false, message: 'Erinnerung konnte nicht als erledigt markiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteReminder(req: Request, res: Response): Promise<void> {
|
||||
const remId = parseInt(param(req, 'remId'), 10);
|
||||
if (isNaN(remId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Erinnerungs-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const deleted = await bestellungService.deleteReminder(remId);
|
||||
if (!deleted) {
|
||||
res.status(404).json({ success: false, message: 'Erinnerung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Erinnerung gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.deleteReminder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Erinnerung konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// History
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getHistory(req: Request, res: Response): Promise<void> {
|
||||
const bestellungId = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(bestellungId)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const history = await bestellungService.getHistory(bestellungId);
|
||||
res.status(200).json({ success: true, data: history });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.getHistory error', { error });
|
||||
res.status(500).json({ success: false, message: 'Historie konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export (placeholder — returns order detail as JSON for now)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async exportOrder(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 order = await bestellungService.getOrderById(id);
|
||||
if (!order) {
|
||||
res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: order });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.exportOrder error', { error });
|
||||
res.status(500).json({ success: false, message: 'Export fehlgeschlagen' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new BestellungController();
|
||||
Reference in New Issue
Block a user