Aufträge L5: Portal-Routen für Aufträge (eigene gesendete ABs, PDF, Bestätigen)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6cb5bfa6c7
commit
503337d7ae
2 files changed
+224
-4
No files matched your search
@@ -1,12 +1,89 @@
|
||||
/**
|
||||
* Gerüst von Strang L0: Aufträge des angemeldeten Kunden. Mount: /api/auftraege. requireSession schützt jede später
|
||||
* ergänzte Route (fail-closed). L5 ergänzt GET /, GET /:id/pdf, POST /:id/bestaetigen; das Bestätigen sperrt der
|
||||
* Wächter der Kundenansicht von selbst, es kommt kein Eintrag in KUNDENANSICHT_ALLOWED.
|
||||
* 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 { requireSession } from '../middleware/session.js'
|
||||
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
|
||||
Reference in new issue
Block a user