iFrame

Diese Seite beschreibt, wie das Buchungswidget auf der eigenen Webseite mittels iFrame integriert werden kann und wie Inhalte oder Daten vorbefüllt werden können

Es ist möglich, Daten ans Buchungswidget zu übermitteln um so Inhalte vorzubefüllen oder Einträge vorzuselektieren.

Die jeweiligen IDs können unter https://dashboard.calenso.com nachgeschlagen werden. Klicke dazu auf "Bearbeiten", dann wird die ID des jeweiligen Elementes angezeigt.

iFrames haben den Vorteil, dass sie von der Webseite selber nicht überschrieben werden können.

🖊️ Buchungswidget integrieren

Lade das iFrame an der gewünschten Stelle auf deiner Webseite:

<iframe 
   src="https://widget.calenso.com/?partner=DEIN-CALENSO-BUCHUNGSNAME&type=appointment&isFrame=true&lang=de_CH" 
   frameborder="0" 
   style="height: 700px; width: 100%; max-width: 840px;"
   scrolling="yes"
   loading="lazy">
</iframe>

Du findest deinen Calenso Buchungsname unter https://dashboard.calenso.com/app/settings (Buchungslink)

Das Buchungswidget kann per loading="lazy" als Offscreen iFrame nachgeladen werden, damit es erst geladen wird, wenn der Benutzer beim iFrame angelagt ist. Das verbessert folgendes:

  • Dateneinsparung um bis zu 2-3%

  • First Contentful Paint um bis zu 1-2%

  • First Input Delay (FID) um 2%

Mehr dazu hier: https://web.dev/iframe-lazy-loading/.

🏢 Partner-Kontext setzen

Damit das Buchungswidget dich als Partner identifizieren kann, musst du deinen Buchungsname im "partner" Attribut setzen.

partner="calenso"

Wenn kein Partner definiert ist, dann wird ein Fehler ausgegeben.

↔️ Buchungswidget-Typ definieren

Es gibt 2 Buchungswidgets. Einmal für den normalen Terminbuchungsfall, und andererseits für den Gruppenterminbuchungsfall.

Mögliche Werte:

  • any

  • appointment

  • event

Wenn du "any" als Typ definierst, dann wird im Buchungswidget eine Auswahl angezeigt. So kann der Kunde zwischen dem Termin- und Gruppentermin Case wählen.

type="appointment"

Standard-Wert: appointment

🇨🇭Sprache definieren

Das Calenso-Buchungswidget unterstützt 8 Sprachen. Du kannst die Sprach als Parameter an die Web-Komponente übergeben.

Mögliche Werte:

  • de_CH (Deutsch)

  • fr_CH (Französisch)

  • it_CH (Italienisch)

  • en_US (Englisch)

  • nl_NL (Niederländisch)

  • fi_FI (Finish)

  • po_PO (Polnisch) (ab v4.54.0)

  • es_ES (Spanisch) (ab v4.55.0)

lang="de_CH" 

Standard-Wert: de_CH

⛔ Sprach-Switcher verstecken

Wenn du bspw. die Sprach über den oberen lang-Parameter vorbefüllst, kann es manchmal notwendig sein, dass du den Sprach-Switcher verstecken möchtest.

lang_switcher=false

Standard-Wert: true

↔️ Internes oder externes Buchungswidget

Standardmässig lädt Calenso das externe Buchungswidget, welches für deine Kunden gedacht ist. Es ist jedoch auch möglich, das interne Buchungswidget zu laden. Dies bringt folgende Funktionen:

  • Interne Dienstleistungen werden angezeigt

  • Am Schluss der Buchung kannst du nach bestehenden Kunden suchen und diese auswählen

Um das interne Buchungswidget zu laden, füge bitte folgenden Parameter hinzu:

internal=true

Standard-Wert: true

Aus Sicherheitsgründen benötigt das interne Buchungswidget einen Verifizierungstoken. Dieser kann wie folgt definiert werden:

token=906e6397-49b0-4c7f-b3f4-317b17b6141d

Du bekommst deinen Verifizierungstoken vom Calenso Support.

🏢 Filiale vorselektieren

Es ist möglich, die zu buchende Filiale über deren Postleitzahl zu vorzuselektieren.

store_zip=6203

Es ist möglich, die zu buchende Filiale über die Filialen-ID vorzuselektieren.

store_id=100

Nebst der Filialen-ID ist es auch möglich, die Filiale über den Namen vorzuselektieren.

store_name=Office&20Sempach%20Station

Bitte achte darauf, dass die Werte URL-encodiert sind (z.B. Abstände = %20)

⬇️ Dienstleistungskategorien vorselektieren

Es ist möglich, eine oder mehrere Dienstleistungskategorien vorzuselektieren, bzw. zu aktivieren. Nicht angegebene Dienstleistungskategorien werden für den jeweiligen Link nicht angezeigt.

category[]=100,101,102

Die ID einer Dienstleistungskategorie kann in den Einstellungen gefunden werden, öffne dazu "Dienstleistungskategorie bearbeiten".

🔠 Dienstleistungen vorselektieren

Es ist möglich, eine oder mehrere Dienstleistungen vorzuselektieren.

service[]=100,101,102

Mehrere Werte werden Komma-separiert.

🧑 Buchbare Mitarbeiter oder Ressourcen vorselektieren

Es ist möglich, eine buchbare Ressource oder einen Mitarbeiter vorzuselektieren.

worker_id=100

or

worker-email=john.smith@apple.com

🙋 Buchungsfragen vorbefüllen

Es ist möglich, eine oder mehrere Buchungsfragen am Ende des Buchungsvorganges vorzubefüllen.

custom_field[100]=Ich%20habe%20euch%20via%20Google%20gefunden&custom_field[101]=Zweiter%20Wert

🧑 Kunden-Informationen vorbefüllen

Es ist möglich, Kundendaten im letzten Buchungsschritt vorzubefüllen.

Vorname:

customer[prename]=John

Nachname:

customer[lastname]=Smith
customer[title]=1

Mögliche Werte:

  • 0 = Keinen Titel

  • 1 = Dr.

  • 2 = Dr. med.

  • 3 = Prof.

customer[company]=Calenso

E-Mail Adresse:

customer[email]=john.smith@gmail.com

Telefonnummer:

customer[mobile]=+41797896541

Geschlecht:

customer[gender]=m

Mögliche Werte:

  • m = Mann

  • f = Frau

  • o = Andere

Strasse:

customer[street]=Mainstreet

Postleitzahl:

customer[zip]=8000

Stadt:

customer[city]=Zurich
customer[country]=1

Mögliche Werte:

  • 1 = Schweiz

  • 2 = Deutschland

  • 3 = Frankreich

  • 4 = Italien

  • 5 = Spanien

  • 6 = Portugal

  • 7 = USA

  • 10 = Österreich

  • 11 = England

  • 12 = Finnland

  • 13 = Norwegen

  • 14 = Schweden

  • 15 = Estland

  • 16 = Russland

  • 17 = Tschechien

  • 18 = Griechenland

  • 19 = Ägypten

  • 20 = Brasilien

  • 21 = Zypern

  • 22 = Liechtenstein

  • 23 = Belgien

  • 24 = Niederlande

  • 25 = Luxenburg

Bemerkung (Kommentar):

customer[comment]=Lorem%20Ipsum

Benachrichtigungseinstellung:

customer_notification_preference=email

Mögliche Werte:

  • email = E-Mail

  • sms = SMS

  • both = E-Mail & SMS

Meeting-Anbieter:

meeting_type_id=3

Mögliche Werte:

  • 1 = Vor Ort (Filiale)

  • 2 = Zoom-Meeting

  • 3 = Calenso Meeting

  • 4 = Telefon

  • 5 = Beim Kunden

  • 6 = Unblu

  • 7 = Microsoft Teams

  • 8 = Google Meet

  • 9 = GoTo Meeting

  • 10 = Cisco Webex

  • 11 = Wir rufen sie an

Interner Kommentar: (URL encoded)

internal_comment=Lorem%20ipsum%20dolor%20sit%20amet%2C%20consetetur%20sadipscing%20elitr%2C%20sed%20diam%20nonumy%20eirmod%20tempor%20invidunt%20ut%20labore%20et%20dolore%20magna%20aliquyam%20erat. 

🔐 Übergebene Werte Base64 encodieren

Damit die übergebenen Werte nicht direkt in der URL sichtbar sind, können diese mit Base64 encodiert werden. Das Buchungswidget dekodiert diese Werte anschliessend und verarbeitet sie.

q=c3RvcmVfaWQ9MjgzNSZzZXJ2aWNlW109NDQ5MyZ3b3JrZXJfaWQ9Mzg4NDcmY3VzdG9tX2ZpZWxkWzM1NzFdPTEyMzQ1Njc4OSZjdXN0b21lcltwcmVuYW1lXT1tYXgmY3VzdG9tZXJbbGFzdG5hbWVdPW11c3RlciZjdXN0b21lcltlbWFpbF09bWF4QG11c3Rlci5jaCZjdXN0b21lclttb2JpbGVdPSs0MTc2NDE3MTI5Mw==

📅 Auswählbare Tage einschränken

Es ist möglich, die buchbaren Tage einzuschränken, indem ein Kontext-Datum übergeben wird inkl. wieviele Tage davor und danach selektierbar sind.

date_context=2020-10-31
date_context_start=5
date_context_end=14

👩 Mitarbeiter speichern, welcher Buchung vorgenommen hat

Wenn gespeichert werden soll, welcher eingeloggte Mitarbeiter den Termin gebucht hat, dann kann man booker_worker_id setzen. Im Fall des internen Buchungswidget wird dieser Wert automatisch gesetzt, sobald ein Mitarbeiter eingeloggt ist. Andernfalls muss dieser Wert manuell als Parameter gesetzt werden.

booker_worker_id=1000

⬇️ UTM-Parameter (Analyse)

UTM-Parameter (Urchin Traffic Monitor) sind spezielle URL-Parameter (z. B. utm_source und utm_medium), die am Ende einer URL hinzugefügt werden können, um die Leistung einer Internetseite in Analysewerkzeugen wie z. B. Google Analytics zu verfolgen. Wenn ein Link mit UTM-Parametern aufgerufen wird, werden die Parameter an Google Analytics zurückgesendet, wo sie verwendet werden können, um die Quelle, das Medium und andere Aspekte des Verweisverkehrs auf die Website zu verfolgen. Diese Informationen können verwendet werden, um den Inhabern der Internetseite und/oder Werbetreibenden beim Verstehen, woher Besucher kommen, welche Arten von Inhalten oder Kampagnen am effektivsten sind und wie die Leistung der Seite verbessert werden kann, zu helfen (Quelle: Wikipedia).

Die UTM-Parameter sind im Terminexport (Excel) und in Webhooks für weitere Auswertungen verfügbar.

utm_source=google.com
utm_medium=cpc
utm_campaign=summersale24
utm_term=appointment
utm_content=textlink

🦘 Ersten Buchungsschritt überspringen (direkt zur Kalenderauswahl)

Es ist möglich, den ersten Schritt zu überspringen, indem man die Filiale, den Mitarbeiter und die zu buchende Dienstleistung vorbefüllt:

store_id=100&worker_id=100&service[]=100

🖼️ Anzeige-Modus im Gruppentermin-Widget ändern

Das Gruppentermin-Widget unterstützt die Listen und die Raster Ansicht. Mit folgendem Parameter kann zwischen der Ansicht gewechselt werden:

ui_mode=grid
ui_mode=list

🔀 Anzeige-Modus Switcher im Gruppentermin-Widget deaktivieren

Der Switcher, welcher es ermöglicht von "Liste" zu "Raster" zu wechseln, kann wie folgt deaktiviert werden:

hide_grid_switcher=true

🗓️ Datum vorselektieren

Der Datumsparameter ermöglicht es, eine spezifischen Tag im Kalender vorzuselektieren, so dass dein Kunde nur noch das jeweilige zu buchende Zeitfenster auswählen muss.

Voraussetzungen:

  • Mitarbeiter ist vorselektiert

  • Dienstleistung ist vorselektiert

date=2023-06-30

🎨 Vorlage definieren

Wenn benutzerdefinierte CSS-Vorlagen vorhanden sind, dann können diese über diesen Parameter gesetzt werden. Das Buchungswidget wird anschliessend mit dem jeweiligen definierten CSS dargestellt. Die Template UUID findest du hier raus.

Voraussetzungen:

  • Business- oder Enterprise Abonnement

template="b201dd38-9bdc-4b8f-b993-dd0bc06ad53c"

📄 Komplettes Beispiel für die Integration eines iFrames


 <iframe 
   src="https://widget.calenso.com/
   ?partner=braincept
   &type=appointment
   &internal=true
   &isFrame=true
   &lang=de_CH
   &worker_id=23
   &service[]=374
   &category[]=100,101,102
   &store_id=2835
   &date_context=2020-10-31
   &date_context_start=5
   &date_context_end=14
   &worker_uuid=1234-1234-1242-1241-1424
   &booker_worker_id=23
   &store_name=Office%20Sempach%20Station
   &utm_source=instagram
   &customer[prename]=John
   &customer[lastname]=Smith
   &customer[gender]=m
   &customer[email]=john.smith@gmail.com
   &customer[street]=Mainstreet
   &customer[zip]=8000
   &customer[city]=Zurich
   &customer[mobile]=+417912345567
   &customer[comment]=Lorem%20Ipsum
   &customer[title]=1
   &customer[country]=1
   &customer[company]=Calenso
   &customer_notification_preference=sms
   &meeting_type_id=3
   &custom_field[100]=Ich%20habe%20euch%20via%20Google%20gefunden
   &custom_field[101]=Zweiter%20Wert
   &hide_grid_switcher=true
   &ui_mode=grid
   &token=906e6397-49b0-4c7f-b3f4-317b17b6141d
   &date=2023-06-30
   &lang_switcher=false
   &q=c3RvcmVfaWQ9MjgzNSZzZXJ2aWNlW109NDQ5MyZ3b3JrZXJfaWQ9Mzg4NDcmY3VzdG9tX2ZpZWxkWzM1NzFdPTEyMzQ1Njc4OSZjdXN0b21lcltwcmVuYW1lXT1tYXgmY3VzdG9tZXJbbGFzdG5hbWVdPW11c3RlciZjdXN0b21lcltlbWFpbF09bWF4QG11c3Rlci5jaCZjdXN0b21lclttb2JpbGVdPSs0MTc2NDE3MTI5Mw==" 
   frameborder="0" 
   style="height: 700px; width: 100%; max-width: 840px;"
   scrolling="yes"
   loading="lazy">
</iframe>

↕️ Automatische Höhenanpassung des iFrames

Die iFrame-Integration ist meist sauberer als die Integration via Web-Komponente bzw. sicherer, hat aber den Nachteil, dass sich die Höhe des Buchungswidget nicht automatisch anpasst, wenn der Inhalt des Widget ändert. Aus diesem Grund haben wir das iFrame-Resizer Script im Buchungswidget implementiert. Mit einem entsprechenden Gegenstück auf deiner Webseite können die zwei Scripts miteinander kommunizieren und Höhenänderungen werden an deine Webseite weitergeben.

Das Plugin ist auf folgender Seite dokumentiert: https://github.com/davidjbradshaw/iframe-resizer

Voraussetzungen für die Integration:

  • jQuery ist verfügbar. Wenn jQuery nicht verfügbar ist, dann kann es mit dem untenstehenden Script geladen werden.

  • Das iFrame-Resizer Script muss geladen werden.

Der folgende Code zeigt das Buchungswidget in Aktion:

 <!DOCTYPE html>
 <html>
 <head>
   <style>
     iframe {
       width: 1px;
       min-width: 100%;
     }
   </style>
 
   <!-- Load jQuery (only if it is not yet loaded on your website) -->
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
 
   <!-- Load the iFrame-Resizer script that communicates with the Calenso booking widget -->
   <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.6.2/iframeResizer.min.js" charset="utf-8"></script>
 
   <script>
       // wait until jQuery is ready
       jQuery(document).ready(function() {
         // initialize the iFrame-Resizer
         iFrameResize({ log: true }, '#calenso-booking-widget')
       });
   </script>
 </head>

 <body>
   <!-- replace partner name with your booking name -->
   <iframe 
     id="calenso-booking-widget" 
     src="https://widget.calenso.com/?partner=DEIN-CALENSO-BUCHUNGSNAME&type=appointment&isFrame=true&lang=de_CH" 
     frameborder="0" 
     style="width: 100%;" 
     scrolling="no">
   </iframe>
 </body>
 </html>

Das Projekt ist als lauffähiges Beispiel auf jsFiddle verfügbar:

🔄 Datenaustausch zwischen Webseite und iFrame

Damit das Calenso Buchungswidet mit einer Webseite kommunizieren kann, muss diese mit einem spezifischen Event-Listener versehen werden. Hier ein Beispiele um z.b. Daten der Buchungs auslesen zu können.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title></title>
</head>
<body>
	<iframe
		src="https://widget.calenso.com/?partner=DEIN-CALENSO-BUCHUNGSNAME&type=appointment&isFrame=true&lang=de_CH"
		loading="lazy"
		frameborder="0"
		style="height: 700px; width: 100%; max-width: 840px;"
		scrolling="yes"
	></iframe>
	<script type="text/javascript">
		function handleMessage(event) {
			console.log('[MsgReceived]', event.data); 
		}
		window.addEventListener('message', handleMessage, false);
	</script>
</body>
</html>	

Folgende Informationen werden nach der Buchung vom Buchungswidget an die Webseite übergeben.

{
    "eventName": "APPOINTMENT_BOOKING_DONE",
    "bookingData": [
        {
            "id": 123,
            "start": "2022-06-30T10:45:00+00:00",
            "end": "2022-06-30T11:00:00+00:00",
            "worker_id": 123,
            "category_id": 123,
            "customer_id": 123,
            "url": null,
            "location": null,
            "user_notified": 0,
            "remind_customer": 1,
            "appointment_source_id": 2,
            "cancellation_to": 24,
            "created": "2022-06-21T09:24:02+00:00",
            "read_only": 0,
            "uuid": "UUID",
            "reminded": 0,
            "stripe_charge_id": null,
            "charged_price": -1,
            "stripe_receipt_url": null,
            "after_booking_message_received": 0,
            "price": -1,
            "parent_id": null,
            "smart_action_2_notified": 0,
            "bexio_order_id": null,
            "receipt_url": null,
            "payment_type": "store",
            "bexio_invoice_id": null,
            "coupon_reduction_amount": null,
            "applied_coupon": null,
            "coupon_id": null,
            "original_start": null,
            "original_end": null,
            "rebook_reason": null,
            "remarks": null,
            "payment_type_id": 72004,
            "before_booking_message_received": 0,
            "title": "Ehe/John Smith ",
            "body": "Kundeninformationen: \nName: John Smith \nE-Mail: john@calenso.com \nMobile: +41 41797896541 \n\nGebuchte Dienstleistung: \n- Beratungstermin\n\n  \n\nTermin stornieren oder umbuchen: \nhttps://dashboard.calenso.com/appointments/uuid",
            "title_hash": "ae2114b431ca2dfb8f5",
            "body_hash": "75f3deb7d",
            "booker_worker_id": null,
            "meeting_type_id": 1,
            "stripe_payment_intent_id": null,
            "original_worker_id": null,
            "rebooker_worker_id": null,
            "utm_source": null,
            "unblu_conversation_id": null,
            "unblu_agent_single_view_conversation_link": null,
            "unblu_agent_desk_conversation_link": null,
            "unblu_visitor_desk_conversation_link": null,
            "has_pending_external_event_delete": 0,
            "cancellation_reason": null,
            "paypal_usage_id": null,
            "modified": null,
            "rebook_date": null,
            "rebook_count": 0,
            "external_online_meeting_id": "",
            "unblu_agent_id": null,
            "unblu_bot_id": null,
            "zoom_host_url": null,
            "zoom_conference_password": null,
            "broker_id": null,
            "customer_ics_filename": "Termin_Kunde.ics",
            "partner_ics_filename": "Termin_Partner.ics",
            "saferpay_usage_id": null,
            "join_information": null,
            "calenso_meet_host_url": null,
            "calenso_meet_customer_url": null,
            "internal_comment": null,
            "broker": null,
            "worker": {
                "id": 123,
                "prename": null,
                "lastname": null,
                "avatar": null,
                "partner_id": 123,
                "username": "mitarbeiter@account.com",
                "email": "mitarbeiter@account.com",
                "job_title": null,
                "bookable": 1,
                "store_id": 123,
                "mobile": "",
                "timezone": "Europe/Zurich",
                "uuid": "UUID",
                "booking_label": "Mitarbeiter",
                "store": {
                    "id": 123,
                    "uuid": "UUID",
                    "logo": null,
                    "name": "Standort Filiale",
                    "street": "",
                    "zip": "",
                    "city": "",
                    "lat": "",
                    "lng": "",
                    "place": null,
                    "is_online": 0,
                    "is_multi_language": 0,
                    "email": "filiale@account.com",
                    "phone": null,
                    "country_id": 1,
                },
                "full_name": " ",
                "resource_name": "Mitarbeiter"
            }
        }
    ]
}

Das Calenso Buchungswidet erlaubt es, die Navigation innerhalb vom Buchungsprozess über die Webseite (Parent) zu steuern.

  1. eventName muss folgendermassen definiert werden: cwParentToChildNavigation

  2. action akzeptiert die Zeichenfolge der auszuführenden Aktion. Es werden 3 Werte akzeptiert. [next / previous / book]

Beispiel Objekt für die Navigation zur nächsten Seite im Widget

iframeElement.postMessage({
    eventName: 'cwParentToChildNavigation',
	action: 'next'
}, '*');

Gesamtes HTML Beispiel für eine Integration der Webseite zu Widget Navigation

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Widget iFrame</title>
</head>
<body>
	<iframe
		id="booking_widget"
		src="https://widget.calenso.com/?partner=DEIN-CALENSO-BUCHUNGSNAME&internal=true&isFrame=true&type=appointments&locale=de_CH"
		loading="lazy"
		frameborder="0"
		style="height: 80vh; width: 100vw;"
		scrolling="yes"
	></iframe>

	<button onclick="manageWidgetNavigation('next')">Next</button>
	<button onclick="manageWidgetNavigation('previous')">Previous</button>
	<button onclick="manageWidgetNavigation('book')">Book</button>

	<script type="text/javascript">
		var widgetIframe = document.getElementById('booking_widget');
		var manageWidgetNavigation = function(action) {
			if (widgetIframe) {
				widgetIframe.contentWindow.postMessage({
					eventName: 'cwParentToChildNavigation',
					action: action
				}, '*');
			}
		}
	</script>
</body>

Validierung der einzelnen Buchungschritte

Das Objekt für die Fehlermeldung hat zwei Schlüssel, die im Falle einer fehlgeschlagenen Validierung an die übergeordnete Instanz gesendet werden (siehe unten).

  1. eventName - Der Wert von eventName wird jeweils cwValidationFailed sein

  2. controls - Array mit dem Namen des Steuerelements als Konstante, dessen Validierung fehlgeschlagen ist und eine Aktion verhindert. Der Wert der Fehlerkonstante kann entsprechend empfangen werden.

// step 1
CUSTOMER_PROFILE_DISABLED
CUSTOMER_PROFILE

// step 2
STORE
SERVICE

// step 3
WORKER

// step 4
DATE
SLOT

// step 5
PERSONAL_FORM

Beispiel Objekt der Validierung an die Webseite (Parent)

{
  "eventName": "cwValidationFailed",
  "controls": [
      "DATE",
      "SLOT"
  ]
}

❌ Buchungswidget-Fehler

Wenn kein Abonnement gesetzt ist, dann wird folgender Fehler angezeigt. Dieser Fehler kann auch auftauchen, wenn die Kreditkarte 3-mal nicht belastet werden konnte. In dem Fall wird das Abonnement gelöscht und das Buchungswidget wird deaktiviert.

Leider konnte kein Abonnement gefunden werden. Bitte kontaktieren den Calenso-Support.

Der Calenso-Support kann das Buchungswidget deaktivieren, z.B. dann wenn die offenen Rechnungen nicht bezahlt wurden:

Das Buchungswidget wurde deaktiviert. Sobald ein Calenso Abo Upgrade durchgeführt ist, wird das Widget wieder freigeschalten.

Wenn keine buchbare Ressource/Mitarbeiter gefunden werden kann, dann wird folgende Fehlermeldung angezeigt:

Es wurde keine buchbare Dienstleistung erfasst. Bitte stelle sicher, dass mindestens eine Dienstleistung vorhanden ist und diese einer buchbaren Ressource zugewiesen ist (Fähigkeit). Das Erfassen einer Dienstleistungskategorie reicht nicht aus, um buchbar zu sein.

🤝 Brauchst du Hilfe?

Wir sind jederzeit unter support@calenso.com für dich da!

Last updated