/** * Aufträge des angemeldeten Kunden (Übersicht V3/V5, Strang L5). Mount: /api/auftraege. requireSession schützt jede * Route (fail-closed). Ein Kunde sieht und bestätigt nur eigene, gesendete Auftragsbestätigungen (keine Entwürfe); * in der Kundenansicht ist Bestätigen nie angeboten, und der Wächter der Kundenansicht sperrt den POST von selbst * (es gibt keinen Eintrag in KUNDENANSICHT_ALLOWED). */ import { Router } from 'express' import { config } from '../config.js' import { getSessionCustomerId, requireSession } from '../middleware/session.js' import { getDocument } from '../services/appwriteAdmin.js' import { isKundenansicht } from '../services/kundenansicht.js' import { getAuftrag, listAuftraege } from '../services/auftraege/auftragStore.js' import { oeffentlicheAnsicht } from '../services/auftraege/auftragSicht.js' import { bestaetigeAuftrag, GESPERRT_MELDUNG } from '../services/auftraege/bestaetigung.js' import { AuftragError, sendeFehler } from '../services/auftraege/fehler.js' import { auftraegeAktiv } from '../services/auftraege/schalter.js' import { sendePdf } from './auftrag.js' const NICHT_GEFUNDEN = 'Auftragsbestätigung nicht gefunden.' const HAEKCHEN = 'Bitte bestätigen Sie den Auftrag mit dem Häkchen.' const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$/ const router = Router() router.use(requireSession) router.use((_req, res, next) => { res.set('Cache-Control', 'no-store') next() }) const ansicht = (a, req) => ({ ...oeffentlicheAnsicht(a), id: a.id, kannBestaetigen: !isKundenansicht(req.session) && (a.status === 'versendet' || (a.status === 'abgerechnet' && !a.bestaetigtAm)), }) /** Eigene, gesendete AB laden; sonst ist 404 schon gesendet und das Ergebnis `null`. */ async function ladeEigene(req, res) { const nichtGefunden = () => { res.status(404).json({ error: NICHT_GEFUNDEN }) return null } if (!ID_RE.test(String(req.params.id))) return nichtGefunden() const kundenId = getSessionCustomerId(req) const kunde = await getDocument(config.collections.customers, kundenId) if (!auftraegeAktiv(kunde)) return nichtGefunden() const a = await getAuftrag(req.params.id) if (!a || a.kundenId !== kundenId || a.status === 'entwurf') return nichtGefunden() return a } router.get('/', async (req, res) => { try { const kundenId = getSessionCustomerId(req) const kunde = await getDocument(config.collections.customers, kundenId) if (!auftraegeAktiv(kunde)) return res.json({ aktiv: false, auftraege: [] }) const liste = await listAuftraege({ kundenId }) res.json({ aktiv: true, auftraege: liste.filter((a) => a.status !== 'entwurf').map((a) => ansicht(a, req)) }) } catch (err) { sendeFehler(res, 'auftraege', err) } }) router.get('/:id/pdf', async (req, res) => { try { const a = await ladeEigene(req, res) if (a) await sendePdf(res, a) } catch (err) { sendeFehler(res, 'auftraege', err) } }) router.post('/:id/bestaetigen', async (req, res) => { try { const a = await ladeEigene(req, res) if (!a) return if (GESPERRT_MELDUNG[a.status]) return res.status(410).json({ error: GESPERRT_MELDUNG[a.status] }) const body = req.body && typeof req.body === 'object' ? req.body : {} if (body.bestaetigt !== true) return res.status(400).json({ error: HAEKCHEN }) const neu = await bestaetigeAuftrag(a, { ueber: 'portal', fruehbeginn: body.fruehbeginn === true }) res.json({ auftrag: ansicht(neu, req) }) } catch (err) { if (err instanceof AuftragError && err.status === 409 && Object.values(GESPERRT_MELDUNG).includes(err.message)) { return res.status(410).json({ error: err.message }) } sendeFehler(res, 'auftraege', err) } }) export default router