Buchungskalender: Bestellung auf Anfrage, Freischaltung und Ticket
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
827ee54875
commit
9d01d38a45
7 files changed
+799
-15
No files matched your search
@@ -10,6 +10,7 @@ import { kontoAnlegen, kontoStatus, onboardingLink, statusAusKonto } from '../se
|
||||
import * as ablauf from '../services/unterkunft/ablauf.js'
|
||||
import { istFrei } from '../services/unterkunft/belegung.js'
|
||||
import { istTag, naechte } from '../services/unterkunft/datum.js'
|
||||
import { anfrageAnsicht as funktionAnfrageAnsicht, stelleAnfrage, zieheZurueck } from '../services/unterkunft/anfrageFunktion.js'
|
||||
import { UkFehler } from '../services/unterkunft/fehler.js'
|
||||
import { ladeFuerProjekt } from '../services/unterkunft/kontext.js'
|
||||
import { berechnePreis, preiseVollstaendig, summiere } from '../services/unterkunft/preis.js'
|
||||
@@ -22,7 +23,7 @@ import * as vw from '../services/unterkunft/verwaltung.js'
|
||||
* Antwortformen: ui-erwartungen.md). Jede Route: Sitzung, eigenes Projekt (403), Funktion vorhanden und nicht off (409 nicht_aktiv).
|
||||
* Schreibende Routen zusaetzlich: nur der Kunde selbst (nicht Kundenansicht/"Ansehen als"), Zustand setup|active, Schreibgrenze
|
||||
* (300 je Kunde und Stunde). Alle IDs aus dem Pfad werden vor jedem Zugriff geprueft und gehoeren zum Projekt (sonst 404).
|
||||
* Fehler: { fehler: code, felder? }; Texte von Appwrite oder Stripe verlassen den Server nie. Die Anfrage-Funktion (/anfrage-funktion) folgt in Task 11.
|
||||
* Fehler: { fehler: code, felder? }; Texte von Appwrite oder Stripe verlassen den Server nie. Die Anfrage der Funktion (/anfrage-funktion, nur solange sie off ist) hat eine eigene Grenze (20 je Kunde und Stunde).
|
||||
*/
|
||||
const router = Router()
|
||||
// Jede Route hier braucht eine Sitzung; Kunden-Pruefung je Route (nurKunde)
|
||||
@@ -33,6 +34,7 @@ router.use((_req, res, next) => {
|
||||
})
|
||||
|
||||
const MAX_WRITES_PER_HOUR = 300
|
||||
const MAX_ANFRAGE_WRITES_PER_HOUR = 20
|
||||
const MELDUNG = {
|
||||
kundenansicht: 'In der Kundenansicht kann das nicht geändert werden.',
|
||||
zuViele: 'Zu viele Änderungen in kurzer Zeit. Bitte versuch es in einer Stunde wieder.',
|
||||
@@ -42,9 +44,12 @@ const MELDUNG = {
|
||||
}
|
||||
|
||||
const schreibLimiter = createWriteLimiter({ max: MAX_WRITES_PER_HOUR })
|
||||
const anfrageLimiter = createWriteLimiter({ max: MAX_ANFRAGE_WRITES_PER_HOUR })
|
||||
const limitAnfrage = anfrageLimiter.middleware((req) => getSessionCustomerId(req), MELDUNG.zuViele)
|
||||
const limitWrites = schreibLimiter.middleware((req) => getSessionCustomerId(req), MELDUNG.zuViele)
|
||||
export function resetUnterkunftRoutesForTests() {
|
||||
schreibLimiter.reset()
|
||||
anfrageLimiter.reset()
|
||||
}
|
||||
|
||||
const nurKunde = (req, res, next) => {
|
||||
@@ -227,7 +232,12 @@ router.get('/status', route(async (req, res) => {
|
||||
const doc = await getFeatureDoc(customerId, projectId, 'unterkunft')
|
||||
const state = doc?.state ?? 'off'
|
||||
const antwort = { state, stripe: { status: 'keins', vorhandenesShopKonto: false }, onlineZahlung: false, unterkuenfte: 0, rechnungenVorhanden: false }
|
||||
if (!doc || state === 'off') return res.json(antwort)
|
||||
if (state === 'off') {
|
||||
// Anfrage der Funktion: offen | abgelehnt | angenommen (zurueckgezogen und keine zaehlen als keine)
|
||||
const ansicht = doc ? funktionAnfrageAnsicht(await sp.ladeEinstellungen(doc.$id)) : null
|
||||
antwort.anfrage = ansicht && ansicht.status !== 'zurueckgezogen' ? ansicht : null
|
||||
return res.json(antwort)
|
||||
}
|
||||
const [einst, unterkuenfte, rechnungen, shop] = await Promise.all([
|
||||
sp.ladeEinstellungen(doc.$id),
|
||||
sp.listeUnterkuenfte(doc.$id),
|
||||
@@ -244,6 +254,37 @@ router.get('/status', route(async (req, res) => {
|
||||
res.json(antwort)
|
||||
}))
|
||||
|
||||
// ---- Anfrage der Funktion (nur solange sie off ist; kein mitProjekt)
|
||||
|
||||
/** Fehler des Anfrage-Dienstes (status, Text, body.code, fehler je Feld) in { fehler: code, felder? }. */
|
||||
function anfrageFehler(err) {
|
||||
if (err instanceof UkFehler || err?.status === 403 || err?.fachlich || !(err?.status >= 400 && err.status < 500)) return err
|
||||
if (err.fehler) return new UkFehler(400, 'ungueltig', err.fehler)
|
||||
return new UkFehler(err.status, err.body?.code || (err.status === 400 ? 'ungueltig' : 'anfrage'), err.status === 400 ? { projectId: err.message } : {})
|
||||
}
|
||||
const anfrageKunde = (req) => ({ name: req.session.name || '', email: req.session.email || '' })
|
||||
|
||||
router.post('/anfrage-funktion', nurKunde, limitAnfrage, route(async (req, res) => {
|
||||
const projectId = projectIdOf(req)
|
||||
if (!projectId) throw ungueltig({ projectId: 'Bitte wähle ein Projekt.' })
|
||||
try {
|
||||
const anfrage = await stelleAnfrage({ customerId: getSessionCustomerId(req), projectId, eingabe: body(req), person: anfrageKunde(req) })
|
||||
res.json({ anfrage })
|
||||
} catch (err) {
|
||||
throw anfrageFehler(err)
|
||||
}
|
||||
}))
|
||||
|
||||
router.post('/anfrage-funktion/zurueckziehen', nurKunde, limitAnfrage, route(async (req, res) => {
|
||||
const projectId = projectIdOf(req)
|
||||
if (!projectId) throw ungueltig({ projectId: 'Bitte wähle ein Projekt.' })
|
||||
try {
|
||||
res.json({ anfrage: await zieheZurueck({ customerId: getSessionCustomerId(req), projectId, person: anfrageKunde(req) }) })
|
||||
} catch (err) {
|
||||
throw anfrageFehler(err)
|
||||
}
|
||||
}))
|
||||
|
||||
// ---- Einstellungen
|
||||
|
||||
async function einstellungenAntwort(ctx, einst) {
|
||||
|
||||
Reference in new issue
Block a user