Files
hotel/modules/casposbridge/README.md
DanielS b6eebfcb90 Add casposbridge: post hotel nights to CASPOS tables via OrderApp API
On check-in (actionBookingStatusAfter -> checked in) and hourly via the
QloApps Cron Task Manager or modules/casposbridge/cron.php, every night of
a checked-in stay is posted to the CASPOS table named after the room
number: registerClient -> waiter login -> tables/openByName ->
orderLines/add -> tables/finalizeOrder (API derived from the CASPOS
OrderApp client, lib/api/api.dart).

- one job per booking and night; pending -> added -> done, so a retry
  only commits and never books lines twice; half-added lines are
  cancelled; POS offline keeps jobs queued (max 10 attempts)
- mapping per room type: ARTICLE[*qty|erwachsene|kinder|gaeste][@preis]
- optional HTTPS with pinned SHA1 certificate fingerprint, checked
  before credentials are sent
- undoing a check-in drops unsent nights and logs posted ones for a void
- config page with connection test (lists service areas and articles)
  and the last 50 jobs with retry
- docker/caspos-mock: stand-in POS for the used endpoints and error
  codes; docker/test-casposbridge.php: 23 end-to-end checks

Not yet verified against a real CASPOS: enteredPrice unit, auto-creation
of tables, client activation, finalizeOrder/TSE behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 23:07:28 +01:00

4.5 KiB
Raw Blame History

CASPOS Kassenanbindung (casposbridge)

Bucht die Übernachtungen eingecheckter Gäste auf den CASPOS-Tisch mit der Zimmernummer (Zimmer 1001 → Tisch 1001). Abrechnung, Beleg und TSE bleiben in CASPOS; QloApps erstellt dafür keine eigenen Rechnungen.

Check-in in QloApps ──> Auftrag je Nacht ──> OrderApp-API der Kasse
                                              registerClient → Kellner-Login
                                              → tables/openByName/1001
                                              → orderLines/add (Übernachtung, Frühstück …)
                                              → tables/finalizeOrder
Check-out ──> Gast zahlt an der Kasse wie gewohnt

Ablauf

  • Check-in (Buchungsstatus → „eingecheckt“): Aufträge für alle Nächte von der Anreise bis heute werden angelegt und sofort gesendet. Ein Fehler an der Kasse blockiert den Check-in nie.
  • Jede Stunde (Cron): für alle eingecheckten Gäste wird die jeweils neue Nacht gebucht; offene oder fehlgeschlagene Sendungen werden wiederholt (max. 10 Versuche).
  • Keine Doppelbuchung: pro Zimmer-Buchung und Nacht gibt es genau einen Auftrag. Stehen die Positionen schon auf dem Tisch und nur der Abschluss fehlt, wird beim nächsten Versuch nur abgeschlossen. Schlägt das Hinzufügen mittendrin fehl, werden die halben Positionen per cancelOrder verworfen.
  • Check-in zurückgenommen: noch nicht gesendete Nächte werden gelöscht; bereits gebuchte müssen an der Kasse storniert werden (Hinweis im QloApps-Log).

Einrichtung

  1. In CASPOS: Zimmer als Tische im eigenen Tischbereich anlegen (Name = Zimmernummer), Artikel für Übernachtung/Frühstück/Kurtaxe anlegen, einen Kellner „Hotel“ mit Passwort anlegen, OrderApp-API aktivieren.

  2. In QloApps: Zimmernummern (Hotel Reservation System → Zimmertypen → Zimmer) auf die Tischnamen setzen.

  3. Module → CASPOS Kassenanbindung → Konfigurieren: IP und API-Port der Kasse (wie in der OrderApp), bei HTTPS den SHA1-Fingerabdruck, Kellner-Nummer und Passwort.

  4. Verbindung testen – zeigt Tischbereiche und Artikel mit IDs. Meldet die Kasse „Gerät nicht freigeschaltet“, das Gerät (Name/ID wie im Formular) in der OrderApp-Verwaltung der Kasse freigeben.

  5. Tischbereich-ID eintragen und je Zimmertyp die Artikel pro Nacht:

    Eingabe Bedeutung
    A-UEB-DZ 1 × Artikel pro Nacht
    A-FRUEH*erwachsene Menge = Erwachsene (auch kinder, gaeste oder eine Zahl)
    A-LOGIS@preis Artikel mit Preiseingabe, Preis = Zimmerpreis pro Nacht (brutto)
    A-UEB-DZ, A-FRUEH*erwachsene mehrere Artikel mit Komma

    Für die Mehrwertsteuer (Übernachtung 7 %, Frühstück 19 %) getrennte CASPOS-Artikel verwenden.

  6. Anbindung aktiv einschalten.

Zeitsteuerung

  • Mit dem Modul QloApps Cron Task Manager läuft die Aufgabe casposbridge_post_nights stündlich.

  • Ohne Cron (z. B. Windows Server, Docker): Windows-Aufgabenplanung stündlich ausführen lassen (im Repo-Ordner):

    docker compose -f docker-compose.yml -f docker-compose.server.yml exec -T -u www-data app php modules/casposbridge/cron.php
    

    Rückgabewert 0 = alles gebucht, 2 = etwas wartet noch oder ist fehlgeschlagen.

Die Seite Konfigurieren zeigt die letzten 50 Aufträge mit Status, Positionen und Fehlermeldung der Kasse; fehlgeschlagene lassen sich dort erneut senden. Mit Jetzt buchen läuft der Abgleich sofort.

Entwickeln und testen ohne Kasse

docker/caspos-mock/server.php bildet die benötigten OrderApp-API-Aufrufe nach (inkl. Fehlercodes 403, 401/1001, 401/1002). docker/test-casposbridge.php legt eine Testbuchung an, checkt ein und prüft Buchung, Wiederholung, Ausfall der Kasse, unbekannte Artikel und das Zurücknehmen des Check-ins:

docker compose -f docker-compose.yml -f docker-compose.server.yml exec -d -u www-data app php -S 127.0.0.1:8088 docker/caspos-mock/server.php
docker compose -f docker-compose.yml -f docker-compose.server.yml exec -u www-data app php docker/test-casposbridge.php

Gegen eine echte Kasse noch zu prüfen

Die API ist aus dem Quellcode der CASPOS OrderApp (lib/api/api.dart) abgeleitet, nicht aus einer Doku:

  • Einheit von enteredPrice (Annahme: Cent) – nur relevant für @preis.
  • Legt openByName unbekannte Tische an oder müssen sie existieren?
  • Muss der Client einmalig in der Kasse freigeschaltet werden?
  • Verhalten von finalizeOrder gegenüber TSE und Bonausgabe (Bestellbon für Zimmer-Tische ggf. abschalten).