gratlinie / contao-gratbooking
GratBooking – Termine aus dem Google Kalender buchen, mit automatisch erzeugtem Zoom-Meeting: Bestätigung mit Kalenderdatei, Erinnerung, Absagen und Umbuchen per Link
Package info
github.com/gratlinie/contao-gratbooking
Type:contao-bundle
pkg:composer/gratlinie/contao-gratbooking
Requires
- php: ^8.3
- ext-openssl: *
- contao/core-bundle: ^5.7
- symfony/http-client: ^7.0
- terminal42/notification_center: ^2.7
Requires (Dev)
- contao/manager-plugin: ^2.0
Suggests
None
Provides
None
Conflicts
- contao/manager-plugin: <2.0 || >=3.0
- gratlinie/contao-gratshop: <0.5.2
Replaces
None
README
GratBooking
Termine aus dem Google Kalender buchen – mit automatisch erzeugtem Zoom-Meeting. Für Contao 5.7, PHP ≥ 8.3.
Deine Kunden sehen auf der Website nur die Zeiten, die in deinem Google Kalender frei sind, und buchen direkt. Bei
jeder Buchung legt GratBooking ein Zoom-Meeting an, trägt den Termin samt Zoom-Link in deinen Google Kalender ein und
schickt die Bestätigung mit Zoom-Link und Kalenderdatei. Verschieben oder absagen per Link – Zoom und Google ziehen
mit. Ideal für Coachings, Beratungen und Erstgespräche per Video. Im Stil von GratFrame,
läuft aber auch ohne (Variablen --gb-*, Fallback auf --gf-*).
Funktionen
- Kalender (Backend → Inhalte → Terminarten): Verbindung zu Google (Dienstkonto) und Zoom (Server-to-Server-App), Gastgeber, Fristen für Absagen und Erinnerung, Seite zum Verwalten. Zugangsdaten nur dort, ohne Versionierung; der Google-Schlüssel wird nach dem Speichern nicht mehr angezeigt. Beim Speichern werden beide Verbindungen geprüft.
- Terminarten je Kalender: Dauer, Raster der Anfangszeiten, Puffer davor/danach, Vorlauf, Horizont, Höchstzahl pro Tag, buchbare Zeiten je Wochentag („09:00-12:00, 14:00-18:00“), Zoom ja/nein oder ein Ort.
- Abwesenheiten je Kalender (Urlaub, Fortbildung …): Von–Bis per Datumsauswahl, an diesen Tagen bietet keine Terminart Termine an; bestehende Buchungen bleiben.
- Freie Termine = Wochenzeiten minus Abwesenheiten minus belegte Zeiten aller angegebenen Google-Kalender (Free/Busy, Details bleiben privat) minus eigene Buchungen samt Puffer. Achtung: Ganztägige Termine legt Google standardmäßig als „Verfügbar“ an – die blockieren nur, wenn sie auf „Beschäftigt“ stehen.
- Buchen (Modul Termin buchen): Terminart → Monat → Uhrzeit → Kontaktdaten. Vor dem Speichern wird der Termin frisch gegen Google geprüft und der Kalender gesperrt (keine Doppelbuchung). Dann Zoom-Meeting, Eintrag im Google Kalender (mit Kontaktdaten und Zoom-Link), Mails. Scheitert ein Schritt, wird zurückgerollt.
- Verwalten (Modul Buchung verwalten, Link aus der Mail): verschieben (Zoom und Google werden angepasst) oder absagen (beides wird gelöscht), bis zur Frist des Kalenders. Im Backend: Liste der Buchungen mit „Absagen“ (Mail an den Kunden); „Löschen“ entfernt Google-Eintrag und Zoom-Meeting ohne Mail.
- Mails (Notification Center, Typen Termin gebucht, verschoben, abgesagt, Erinnerung): Tokens zu Termin,
Kontakt, Zoom und Verwaltungs-Link; Kalenderdatei als Anhang (
##booking_ics##in „Anhänge über Tokens“, gleiche UID bei Änderungen,METHOD:CANCELbei Absage). - Blättern ohne Neuladen:
gratbooking.jslädt beim Klick auf Monat, Tag, Uhrzeit, Verschieben oder Absagen nur den Buchungsbereich nach und führt die Adresse mit (Zurück/Neuladen funktionieren). Ohne JavaScript sind es normale Links, das Formular ist ein normales Formular. Antworten werden nie zwischengespeichert.
Google einrichten (je Kunde)
- In der Google Cloud Console ein Projekt wählen oder anlegen, die Google Calendar API aktivieren.
- IAM & Verwaltung → Dienstkonten → Dienstkonto erstellen (keine Rollen nötig), dann beim Dienstkonto Schlüssel → Schlüssel hinzufügen → JSON. Die heruntergeladene Datei öffnen und ihren Inhalt in Contao in Schlüssel des Dienstkontos einfügen, speichern – darunter steht die Adresse des Dienstkontos.
- In Google Kalender beim Kalender für Buchungen Einstellungen und Freigabe → Für bestimmte Personen freigeben: die Adresse des Dienstkontos mit „Änderungen an Terminen vornehmen“ eintragen. Weitere Kalender, die nur blockieren sollen, mit mindestens „Nur Verfügbarkeit (frei/belegt)“ freigeben.
- Kalender-ID eintragen (meist die Gmail-Adresse; sonst Kalender integrieren → Kalender-ID), speichern. Die Meldung „Google Kalender lesbar“ bestätigt die Freigabe.
Ein Dienstkonto ohne Google Workspace verschickt keine Google-Einladungen an Gäste – nicht nötig, die Bestätigung mit Kalenderdatei kommt aus dem Notification Center.
Zoom einrichten
- Im Zoom App Marketplace Develop → Build App → Server-to-Server OAuth App.
- Scopes
meeting:write:meeting:admin(anlegen),meeting:update:meeting:admin(verschieben) undmeeting:delete:meeting:admin(absagen) hinzufügen – ältere Apps:meeting:write:admin–, „Event Subscriptions“ aus lassen, App aktivieren. - Account-ID, Client-ID, Client-Secret in den Kalender eintragen, speichern („Zoom-Anmeldung erfolgreich“).
Im kostenlosen Basic-Konto enden Meetings mit mehreren Teilnehmern nach 40 Minuten.
Cronjob
Erinnerungen verschickt der Contao-Cron (alle 15 Minuten). Zuverlässig mit einem Cronjob beim Hoster auf
vendor/bin/contao-console contao:cron oder https://<domain>/_contao/cron.
Test ohne Google und Zoom
GRATBOOKING_GOOGLE_URL und GRATBOOKING_ZOOM_URL ersetzen die Basis-URLs der APIs (Mock-Server); die Anmeldung bei
Google läuft über token_uri aus dem JSON-Schlüssel.
Bezahlte Termine (optional, mit GratShop)
Ist GratShop (gratlinie/contao-gratshop, Stripe Checkout) installiert, bekommt jede Terminart das Feld
Preis (GratShop-Produkt): ein Produkt vom Typ Direktkauf mit Nettopreis. Ohne GratShop bleibt alles kostenlos,
GratBooking braucht es nicht.
- Buchen: Das Modul zeigt den Bruttopreis (Steuersatz aus
gratlinie_grat_shop.vat_rate), fragt zusätzlich die Zustimmung zum Beginn vor Ablauf der Widerrufsfrist ab (Dienstleistung, § 356 Abs. 4 BGB; Text und Seite der Widerrufsbelehrung im Modul) und leitet zu Stripe weiter. Der Termin ist so lange reserviert (Status wartet auf Zahlung, 32 Minuten), die Checkout-Session endet eine Minute früher. - Nach der Zahlung (Rückkehr von Stripe oder Webhook, je Session nur einmal): Zoom-Meeting, Google-Eintrag,
Bestätigung mit
##booking_amount##. Wer abbricht, landet wieder im Kalender mit vorausgewähltem Termin; die Reservierung wird frei und die Stripe-Session geschlossen. Abgelaufene Reservierungen blockieren nichts, der stündliche Cron setzt sie auf abgesagt. - Verwalten: Bezahlte Termine lassen sich online nur verschieben. Absagen und erstatten regelt der Gastgeber (Backend „Absagen“ löscht Zoom und Google, die Erstattung läuft im Stripe-Dashboard).
- Zahlarten stellt man im Stripe-Dashboard ein (Checkout nutzt die dort aktiven). PayPal: Einstellungen → Zahlungsmethoden → PayPal aktivieren und das PayPal-Geschäftskonto verbinden; bei der Auszahlung lässt sich wählen, ob das Geld im Stripe-Guthaben oder auf dem PayPal-Konto landet. Zahlarten, die erst Tage später bestätigt werden (SEPA-Lastschrift, Überweisung u. Ä.), blendet GratBooking im Checkout aus – die Reservierung wäre dann längst abgelaufen.
- Einrichtung von Stripe (Schlüssel in
.env.local, Webhook/_gratshop/stripe/webhook): siehe GratShop. Kunden werden als Mitglieder angelegt, die Bestellung steht in GratShop.