rework internal order system
This commit is contained in:
@@ -5,6 +5,70 @@ import { permissionService } from '../services/permission.service';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
class AusruestungsanfrageController {
|
||||
// -------------------------------------------------------------------------
|
||||
// Categories (DB-backed)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
async getKategorien(_req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const kategorien = await ausruestungsanfrageService.getKategorien();
|
||||
res.status(200).json({ success: true, data: kategorien });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.getKategorien error', { error });
|
||||
res.status(500).json({ success: false, message: 'Kategorien konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createKategorie(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const { name } = req.body;
|
||||
if (!name || name.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Name ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
const kategorie = await ausruestungsanfrageService.createKategorie(name.trim());
|
||||
res.status(201).json({ success: true, data: kategorie });
|
||||
} catch (error: any) {
|
||||
if (error?.constraint === 'ausruestung_kategorien_katalog_name_key') {
|
||||
res.status(409).json({ success: false, message: 'Kategorie existiert bereits' });
|
||||
return;
|
||||
}
|
||||
logger.error('AusruestungsanfrageController.createKategorie error', { error });
|
||||
res.status(500).json({ success: false, message: 'Kategorie konnte nicht erstellt werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateKategorie(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const { name } = req.body;
|
||||
if (!name || name.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Name ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
const kategorie = await ausruestungsanfrageService.updateKategorie(id, name.trim());
|
||||
if (!kategorie) {
|
||||
res.status(404).json({ success: false, message: 'Kategorie nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: kategorie });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.updateKategorie error', { error });
|
||||
res.status(500).json({ success: false, message: 'Kategorie konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteKategorie(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
await ausruestungsanfrageService.deleteKategorie(id);
|
||||
res.status(200).json({ success: true, message: 'Kategorie gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.deleteKategorie error', { error });
|
||||
res.status(500).json({ success: false, message: 'Kategorie konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Catalog Items
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -12,8 +76,9 @@ class AusruestungsanfrageController {
|
||||
async getItems(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const kategorie = req.query.kategorie as string | undefined;
|
||||
const kategorie_id = req.query.kategorie_id ? Number(req.query.kategorie_id) : undefined;
|
||||
const aktiv = req.query.aktiv !== undefined ? req.query.aktiv === 'true' : undefined;
|
||||
const items = await ausruestungsanfrageService.getItems({ kategorie, aktiv });
|
||||
const items = await ausruestungsanfrageService.getItems({ kategorie, kategorie_id, aktiv });
|
||||
res.status(200).json({ success: true, data: items });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.getItems error', { error });
|
||||
@@ -87,6 +152,59 @@ class AusruestungsanfrageController {
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Artikel Eigenschaften (characteristics)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
async getArtikelEigenschaften(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const artikelId = Number(req.params.id);
|
||||
const eigenschaften = await ausruestungsanfrageService.getArtikelEigenschaften(artikelId);
|
||||
res.status(200).json({ success: true, data: eigenschaften });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.getArtikelEigenschaften error', { error });
|
||||
res.status(500).json({ success: false, message: 'Eigenschaften konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async upsertArtikelEigenschaft(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const artikelId = Number(req.params.id);
|
||||
const { name, typ, optionen, pflicht, sort_order, eigenschaft_id } = req.body;
|
||||
if (!name || name.trim().length === 0) {
|
||||
res.status(400).json({ success: false, message: 'Name ist erforderlich' });
|
||||
return;
|
||||
}
|
||||
if (!typ || !['options', 'freitext'].includes(typ)) {
|
||||
res.status(400).json({ success: false, message: 'Typ muss "options" oder "freitext" sein' });
|
||||
return;
|
||||
}
|
||||
const eigenschaft = await ausruestungsanfrageService.upsertArtikelEigenschaft(artikelId, {
|
||||
id: eigenschaft_id,
|
||||
name: name.trim(),
|
||||
typ,
|
||||
optionen: optionen || undefined,
|
||||
pflicht: pflicht ?? false,
|
||||
sort_order: sort_order ?? 0,
|
||||
});
|
||||
res.status(eigenschaft_id ? 200 : 201).json({ success: true, data: eigenschaft });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.upsertArtikelEigenschaft error', { error });
|
||||
res.status(500).json({ success: false, message: 'Eigenschaft konnte nicht gespeichert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteArtikelEigenschaft(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const id = Number(req.params.eigenschaftId);
|
||||
await ausruestungsanfrageService.deleteArtikelEigenschaft(id);
|
||||
res.status(200).json({ success: true, message: 'Eigenschaft gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('AusruestungsanfrageController.deleteArtikelEigenschaft error', { error });
|
||||
res.status(500).json({ success: false, message: 'Eigenschaft konnte nicht gelöscht werden' });
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Requests
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -131,7 +249,7 @@ class AusruestungsanfrageController {
|
||||
async createRequest(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const { items, notizen, bezeichnung, fuer_benutzer_id } = req.body as {
|
||||
items?: { artikel_id?: number; bezeichnung: string; menge: number; notizen?: string }[];
|
||||
items?: { artikel_id?: number; bezeichnung: string; menge: number; notizen?: string; eigenschaften?: { eigenschaft_id: number; wert: string }[] }[];
|
||||
notizen?: string;
|
||||
bezeichnung?: string;
|
||||
fuer_benutzer_id?: string;
|
||||
@@ -179,7 +297,7 @@ class AusruestungsanfrageController {
|
||||
const { bezeichnung, notizen, items } = req.body as {
|
||||
bezeichnung?: string;
|
||||
notizen?: string;
|
||||
items?: { artikel_id?: number; bezeichnung: string; menge: number; notizen?: string }[];
|
||||
items?: { artikel_id?: number; bezeichnung: string; menge: number; notizen?: string; eigenschaften?: { eigenschaft_id: number; wert: string }[] }[];
|
||||
};
|
||||
|
||||
// Validate items if provided
|
||||
@@ -209,8 +327,8 @@ class AusruestungsanfrageController {
|
||||
// Check permission: owner + status=offen, OR ausruestungsanfrage:edit
|
||||
const groups = req.user?.groups ?? [];
|
||||
const canEditAny = groups.includes('dashboard_admin') || permissionService.hasPermission(groups, 'ausruestungsanfrage:edit');
|
||||
const isOwner = existing.anfrager_id === req.user!.id;
|
||||
if (!canEditAny && !(isOwner && existing.status === 'offen')) {
|
||||
const isOwner = existing.anfrage.anfrager_id === req.user!.id;
|
||||
if (!canEditAny && !(isOwner && existing.anfrage.status === 'offen')) {
|
||||
res.status(403).json({ success: false, message: 'Keine Berechtigung zum Bearbeiten dieser Anfrage' });
|
||||
return;
|
||||
}
|
||||
@@ -253,11 +371,11 @@ class AusruestungsanfrageController {
|
||||
|
||||
// Notify requester on status changes
|
||||
if (['genehmigt', 'abgelehnt', 'bestellt', 'erledigt'].includes(status)) {
|
||||
const orderLabel = existing.bestell_jahr && existing.bestell_nummer
|
||||
? `${existing.bestell_jahr}/${String(existing.bestell_nummer).padStart(3, '0')}`
|
||||
const orderLabel = existing.anfrage.bestell_jahr && existing.anfrage.bestell_nummer
|
||||
? `${existing.anfrage.bestell_jahr}/${String(existing.anfrage.bestell_nummer).padStart(3, '0')}`
|
||||
: `#${id}`;
|
||||
await notificationService.createNotification({
|
||||
user_id: existing.anfrager_id,
|
||||
user_id: existing.anfrage.anfrager_id,
|
||||
typ: 'ausruestung_anfrage',
|
||||
titel: status === 'genehmigt' ? 'Anfrage genehmigt' : status === 'abgelehnt' ? 'Anfrage abgelehnt' : `Anfrage ${status}`,
|
||||
nachricht: `Deine Ausrüstungsanfrage ${orderLabel} wurde ${status === 'genehmigt' ? 'genehmigt' : status === 'abgelehnt' ? 'abgelehnt' : status}.`,
|
||||
|
||||
Reference in New Issue
Block a user