/** * Auftragsbestätigungen (Admin), Mount: /api/admin/finanzen/auftraege (vor dem Finanzen-Router, Übersicht V5 „L3“). * GET / (?kunde=), POST /, GET|PATCH|DELETE /:id, GET /:id/pdf, POST /:id/projekt, /:id/senden, /:id/erinnern, * /:id/neue-fassung, /:id/stornieren. Nur dünne HTTP-Schicht: Kunde laden, Schalter prüfen, Dienst aufrufen, Fehler über * sendeFehler. Ist der Schalter für den Kunden aus, antworten alle Routen 404 mit SCHALTER_AUS_MELDUNG. */ import { Router } from 'express' import { requireAppwriteStaff } from '../../middleware/appwriteStaff.js' import { auftraegeAktiv } from '../../services/auftraege/schalter.js' import { SCHALTER_AUS_MELDUNG } from '../../services/auftraege/konstanten.js' import { AuftragError, sendeFehler } from '../../services/auftraege/fehler.js' import { auftragFuerTeam } from '../../services/auftraege/auftragSicht.js' import { listAuftraege } from '../../services/auftraege/auftragStore.js' import { aendereEntwurf, erinnereAuftrag, ladeAuftrag, ladeGespeichertesPdf, ladeKunde, legeEntwurfAn, loescheEntwurf, neueFassung, ordneProjektZu, sendeAuftrag, storniereAuftrag, vorschauPdf, } from '../../services/auftraege/auftraege.js' const router = Router() router.use(requireAppwriteStaff) async function ladeKundeMitSchalter(kundenId) { const kunde = await ladeKunde(kundenId) if (!auftraegeAktiv(kunde)) throw new AuftragError(404, SCHALTER_AUS_MELDUNG) return kunde } async function ladeMitSchalter(id) { const auftrag = await ladeAuftrag(id) await ladeKundeMitSchalter(auftrag.kundenId) return auftrag } const vonAdmin = (req) => req.appwriteUser?.email router.get('/', async (req, res) => { try { const kundenId = req.query.kunde if (typeof kundenId !== 'string' || kundenId === '') return res.status(400).json({ error: 'Kunde fehlt.' }) await ladeKundeMitSchalter(kundenId) return res.json({ auftraege: (await listAuftraege({ kundenId })).map(auftragFuerTeam) }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigungen laden', err) } }) router.post('/', async (req, res) => { try { const kundenId = req.body?.kundenId if (typeof kundenId === 'string' && kundenId !== '') await ladeKundeMitSchalter(kundenId) return res.json({ auftrag: auftragFuerTeam(await legeEntwurfAn(req.body, { von: vonAdmin(req) })) }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung anlegen', err) } }) router.get('/:id', async (req, res) => { try { return res.json({ auftrag: auftragFuerTeam(await ladeMitSchalter(req.params.id)) }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung laden', err) } }) router.patch('/:id', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json({ auftrag: auftragFuerTeam(await aendereEntwurf(req.params.id, req.body ?? {})) }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung ändern', err) } }) router.delete('/:id', async (req, res) => { try { await ladeMitSchalter(req.params.id) await loescheEntwurf(req.params.id) return res.json({ ok: true }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung löschen', err) } }) router.get('/:id/pdf', async (req, res) => { try { const auftrag = await ladeMitSchalter(req.params.id) const entwurf = auftrag.status === 'entwurf' const buffer = entwurf ? await vorschauPdf(auftrag.id) : await ladeGespeichertesPdf(auftrag) const name = entwurf ? 'Auftragsbestaetigung-Entwurf.pdf' : /^AB-\d{4}-\d{4}$/.test(auftrag.nummer) ? `${auftrag.nummer}.pdf` : 'Auftragsbestaetigung.pdf' res.set({ 'Content-Type': 'application/pdf', 'Content-Disposition': `inline; filename="${name}"`, 'Cache-Control': 'no-store' }) return res.send(buffer) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung-PDF laden', err) } }) /** Antwort der Aktionen, die eine Mail auslösen: { auftrag, mailFehler }. */ const mitMail = ({ auftrag, mailFehler }) => ({ auftrag: auftragFuerTeam(auftrag), mailFehler }) router.post('/:id/senden', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json(mitMail(await sendeAuftrag(req.params.id, { von: vonAdmin(req) }))) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung senden', err) } }) router.post('/:id/erinnern', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json(mitMail(await erinnereAuftrag(req.params.id))) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung erinnern', err) } }) router.post('/:id/neue-fassung', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json({ auftrag: auftragFuerTeam(await neueFassung(req.params.id, { von: vonAdmin(req) })) }) } catch (err) { return sendeFehler(res, 'Neue Fassung anlegen', err) } }) router.post('/:id/stornieren', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json({ auftrag: auftragFuerTeam(await storniereAuftrag(req.params.id)) }) } catch (err) { return sendeFehler(res, 'Auftragsbestätigung stornieren', err) } }) router.post('/:id/projekt', async (req, res) => { try { await ladeMitSchalter(req.params.id) return res.json({ auftrag: auftragFuerTeam(await ordneProjektZu(req.params.id, req.body?.projektId)) }) } catch (err) { return sendeFehler(res, 'Projekt zuordnen', err) } }) export default router