export type OrderStatus = | "neu" | "uebermittelt" | "telefonisch" | "nicht_uebermittelt" | "rueckruf" | "storniert" | "fake"; export type OrderType = "vorbestellung" | "direktanruf"; /** Alles, was eine Bearbeiterin an einer Bestellung auslösen kann. */ export type OrderAction = | "uebermittelt" | "gastronom_voice" | "gastronom_anruf" | "kunde_anrufen" | "nicht_uebermittelt" | "rueckruf" | "storno" | "fake" | "stornieren" | "sos" | "telefonisch_uebermittelt"; /** Protokolleintrag einer ausgelösten Aktion, treibt die Timeline. */ export type OrderEvent = { type: OrderAction; at: string }; export type PaymentMethod = "bar" | "ec" | "paypal" | "kreditkarte"; export type Restaurant = { name: string; city: string; /** Öffnungszeiten, z. B. "10:00 bis 23:00" */ hours: string; phone1: string; phone2?: string; mobile?: string; mobile2?: string; orderUrl: string; /** Zeitfenster für den Heimservice, z. B. Mittags- und Abendschicht. Zweites Fenster optional. */ heimserviceWindows: [string, string | undefined]; }; export type Customer = { name: string; email: string; phone: string; }; export type Order = { id: string; /** Fortlaufende Bestellnummer, wird in der Liste als erste Spalte gezeigt */ number: number; status: OrderStatus; type: OrderType; restaurant: Restaurant; customer: Customer; /** Zeitpunkt des Bestelleingangs, ISO-String */ receivedAt: string; /** Gewünschte Liefer- bzw. Abholzeit, ISO-String */ dueAt: string; total: number; itemCount: number; payment: PaymentMethod; pdfUrl: string; /** Bestellung im externen Backoffice, öffnet in neuem Tab. */ externalUrl: string; note?: string; /** Zeitpunkt, zu dem der Gastronom die Bestellung bestätigt hat. */ confirmedAt?: string; /** Manuell ausgelöste Schritte, ältester zuerst. */ events: OrderEvent[]; }; export const STATUS_LABEL: Record = { neu: "Neu", uebermittelt: "Übermittelt", telefonisch: "Telefonisch übermittelt", nicht_uebermittelt: "Nicht übermittelt", rueckruf: "Rückrufhinweis", storniert: "Storniert", fake: "Fake", }; export const TYPE_LABEL: Record = { vorbestellung: "Vorbestellung", direktanruf: "Direktanruf", }; export const PAYMENT_LABEL: Record = { bar: "Bar", ec: "EC-Karte", paypal: "PayPal", kreditkarte: "Kreditkarte", }; /** Abstand zwischen den drei automatischen Übermittlungsversuchen. */ export const ATTEMPT_INTERVAL_MS = 5 * 60 * 1000; export const ATTEMPT_COUNT = 3; /** Nach dieser Zeit ohne Bearbeitung gilt eine Bestellung als nicht übermittelt. */ export const UNDELIVERED_AFTER_MS = 15 * 60 * 1000; /** * Eine unbearbeitete Bestellung kippt nach {@link UNDELIVERED_AFTER_MS} automatisch auf * `nicht_uebermittelt`. Sobald jemand eine Aktion ausgelöst hat, bleibt der echte Status stehen. */ export function effectiveStatus(order: Order, now: number): OrderStatus { const overdue = now - new Date(order.receivedAt).getTime() >= UNDELIVERED_AFTER_MS; return order.status === "neu" && overdue ? "nicht_uebermittelt" : order.status; }