(EN) Dev Guide

This guide is meant to be complementary to the Quick start for service owners guide. It is recommended to read it before this document. It offers a description of the most relevant features and options provided via the two core configuration files. Updated to version R32.

ZWEB telegram booking bot

A simple, fast, hassle-free reservation tool helping structures and services for rent by the hour. Made with love by zorida @ zweb.studio. For any suggestions and issues, take a look at the small forum too (https://forum.zweb-apps.xyz)

Requirements

  • PHP >= 8.2 (mandatory)
  • GD library (graphic library PHP module) installed (if you want to print ticket images, highly recommended)
  • Sqlite3 module for PHP installed. In order to keep things simple and as portable as possible, the bot reservations, users etc. will be saved in a Sqlite single file database.
  • Composer for your OS
  • It may be useful to have the timezone libraries you need, installed on your web server machine. See pages like https://stackoverflow.com/questions/10909911/php-setlocale-has-no-effect for further details.
  • A Google free email account if you want to send your schedules to Google Calendar

Preliminary operations

This is a program meant to be associated with a Telegram bot. In order to create a bot, you must use the bot named Telegram Botfather. We encourage you to take a look at https://core.telegram.org/bots/tutorial or surf the web and get a basic understanding of what is a bot.

Once you create the bot in Telegram, you need to copy the bot's API token and put it in a .env file in the project root folder. To do it, first of all duplicate the .env.dist file, and rename it as .env. The application will read this file automatically (and needs it) when it runs. Paste the API token string inside the TOKEN variable of the env file (in the double quotes at the right of the equal sign).

The program communicates with the Telegram Bot API by using the polling method (mainly meant and recommended for development) or the webhook method. If you set the .env ENVIRONMENT variable as equal to "DEV" in the env file, polling will be used, otherwise webhook will be used. When using a webhook, you must set a WEBHOOK variable in the env file, where you basically tell Telegram how to reach your application, for example https://mysite.com/bot.php. This depends on your hosting and/or web server configuration. The program will try to set the webhook for you, but if you notice that the webhook is not set, you can manually send a HTTP POST message to Telegram API according to the documentation https://core.telegram.org/bots/api#setwebhook. Remember: for the webhook method to work, it is mandatory that your hosting machine has a full chain SSL certificate (either third-party or self-signed) associated to your domain, and the communication must travel the web via HTTPS, or telegram will silently ignore the messages.

Using a webhook you can also decide to use a SECRET text (likely not an easily guessed text), by writing it in the respective .env variable named SECRET; this string is useful to avoid messages coming from outside the bot, and works only when you are in a production environment (i.e. with a webhook, have a look at the Telegram bot API to set the proper communication method with the API), not during development.

To start developing or testing the application

Run composer install in a terminal from the main folder of the project. Create the .env file from the .env.dist file as told before, and set the value "DEV" for the ENVIRONMENT (polling mode).

Create a bot in Telegram and copy/paste the token api in the env TOKEN variable.

Run php bot.php in the command line from the root folder of the project, where the bot.php file is (it requires the 'php' command which, depending on the OS and the specific php installation you are using, may or may not be available globally and automatically: try typing php -v in the terminal to check it, otherwise you should probably add the php executable to your OS PATH or create a link between the command and the executable. There are quite a number of tutorials online explaining PHP installation in depth).

The program is instructed to use a config file to get all the necessary setup. Here, you can customize a lot of things we'll discuss in detail later. The config file is in the project root folder and is by convention named config-xx.json, where 'xx' is replaced with the language code, defined in the .env file. At the current time, 'en', 'es' and 'it' languages are already added to the project, but you can create your own by copying one and customize it, or editing the default configuration file, i.e. config-en.json (better making a backup copy of it). All the human-readable data moving back and forth through the application - such as a thank you message - will appear in that language.

Project structure

The main PHP files are all located in the root folder of the project. They handle all the most important actions involved in communicating with the database, the Telegram Bot API, and so on. Here you will also find the demo config files in english and spanish to help you get started.

The /assets folder will be useful if you want to put custom files for ticket images, fonts, text etc.

Since the bot communication is almost stateless, there are folders like /extras, /reservations and /temp that will be used to store small information files, required to keep track of what is happening, as well as the last excel files generated.

Libraries installed via composer from the command line will be under /vendor folder. It is recommended not to edit this files directly, but rather extend their classes and functionalities outside this folder.

The config file

This file in JSON format provides all the configurable parameters of the bot application, here is the explanation. Some of the JSON properties, especially in the text object, refer to translation strings and are almost self-explanatory, so they won't be shown here. However, it is important to remind that in the text property group, some translation strings contain special character sequences like ::s that the software will replace at runtime with the appropriate data if it finds them. Other config properties or groups of properties (i.e. 'objects') have a significant impact on the application behaviour instead. We suggest to begin with modifying just a few properties, and see the results reflected in the bot behaviour.

Main parameters

  • name: This is the name of the structure or the rental service as a whole. It will appear in some messages or in the pro-forma ticket that shows your reservation.
  • telegram_keeper_id (no default value, it's sensitive information): the numeric telegram ids of the owners. This allows the relative users to access a quantity of reserved text and button commands, allowing to perform special operations like rapidly seeing all the reservations in their structure, or making a reservation for a hidden service, reserved to them. The ids are to be written in the form of a JSON Array of numeric id's, which is comma-separated numbers (one for every service manager telegram id) with square brackets around the sequence (i.e. [ 1234, 5678, 9012 ] ).

How do you discover your telegram account number? Here is two ways to get it:

  1. The easier way. Start the bot in polling/development mode, complete the signup or a reservation, then connect to the file database reservations.sqlite and recover the record with your ID!
  2. The complicated way (from Reddit). Talk to @BotFather in Telegram, and create a bot with some random username. Send it a message, and open the following link https://api.telegram.org/bot[--TOKEN--]/getUpdates. Replace [--TOKEN--] with the bot-token that you got from @BotFather. The page will contain the information of your message to the bot. It should say, amongst a whole lot of other info, ... { message: { ... "from": {... "id": 0123456789 ...} ... } }
  • use_signup (default: true): if set to true, it will make the bot ask the user to share their telegram phone number and provide a full name. After this simple and fast signup, they are allowed to make reservations. If false, users can make reservations directly from the beginning, and those reservations will be saved with their telegram name (if any) instead of the signup name. Other data are saved in any case, like telegram username and id.
  • print_proforma_tickets(default: true): if true, the application will write the reservation infos onto an image, whose path is set in the ticket.file property. The fake ticket printing requires PHP GD library installed and active on the machine.
  • show_reservation_terms_on_ticket (default: true): if set to true, allows to show a short text inside the ticket, as in the chosen service's ticket_terms property (if any).
  • keeper_save_customer_name (default: true): This allows a service manager ("keeper" is the config equivalent for service manager) to insert a name other than theirs in order to make a reservation 'on behalf of someone else' (and keep track of it); while it can be very useful, it adds a text message step to the reservation process, and not everyone should need it, so it is optional.
  • active_reservations_include_cancelled (default: true): if set to true, the excel file will also show cancelled reservations
  • infographics (default: "/assets/logo_example.jpg"): here you can specify a path for an image in jpg format or a .txt text file that will be sent to the user; it is designed to provide general information on the service or the brand and is sent when a user taps the /help command.
  • info_caption (default: "Info board"): A simple caption text for the infographics.
  • help: the text part of the /help command; can be in HTML.
  • reservation_cancel_tolerance_hours: here you can make appear a time limit to cancel the reservation. While this information can be useful, it is just for explaining purposes and by no means will it affect the application behaviour.
  • max_reservations: here you can decide how many active reservations a user can have before the application stops them. It is possible to cancel an active reservation in order to make a new one. The service owner can make reservations like a common user, but without limits.
  • days_reservation_interval: it handles how many days ahead of the present day you want to show to a user making a reservation. For aesthetic reasons related to telegram buttons, whatever the number, the real interval is hard-limited to 14 days inside the code.
  • concurrent_reservations_per_service: this is a very important feature. If set to more than 1 (default), allows multiple users to make a reservation in the same time interval, and it is useful for classes with a limit of subscribers.
  • multiple_reservation_limit: This is made to prevent unwanted excess of reservations made accidentally with the multiple reservation command and puts an upper limit to them.
  • service_based_shifts: If set to true, services can have a pre-defined working time interval
  • users_per_page: The service manager can see this number of users per page of the results when clicking on "Edit Users"; remember however that if this value is above 10, it is ignore, and 10 is used instead for layout reasons.
  • excel_filename_prefix and excel_users_filename_prefix: set the path for excel reservations exports and users excel exports
  • location: it contains three properties: text, which is a description of the place or address; latitude and longitude, specifying the position on the Telegram map. This object is related to the /location command, that shows a Telegram map point.
  • use_google_calendar_events: whether you want to connect your bot with a calendar you have access to. See below for how-to and details.
  • services: here you can make a list of the services you offer; for each service, you need to declare a name property, and optionally a property with a number of concurrent_reservations_per_service; if missing, the general rule with the same name will be applied (see above).
  • duration_options: here you prepare a list of durations of the service for the user to choose from; if the durations is always the same, you can leave just one object in the list; each object must contain a text property and a value property in minutes for the duration, as shown in the default english file.
  • shifts_notes: It is just a note for the developer reminding them that "First day is Sunday" in the week days order, nothing more.
  • shifts_default (default: "7:00/23:30"): this is base for the working hours of the business. This is a fast and handy way of setting a generic rule for all the days of the week that don't need anything more specific. Note: up to 3 intervals can be specified in the form hh:mm/hh:mm,hh:mm/hh:mm etc. without spaces inside.

User roles

It is possible to have a list of user roles in the configuration file, i.e. an array in JS object notation. At the moment, each role object contains only two properties:

  • The name of the role (valid both aesthetically and internally!)
  • The maximum number of reservations for a given role This allows for the service manager to promote user to specific roles based on their level of trust or the user's real life subscription, ideally incrementing the number of reservations available. Promoting a user is a function available both from a text command and from the control panel button (under "Edit Users" sub-command button). There is also a default_user_role main parameter, which defines the role assigned to a new user upon signup.

The time object

  • reservation_hours_before: the numer of hours specified here sets the minimum time gap in hours between the present moment and the first allowed time slot for a reservation. Can be 0.
  • interval_in_minutes: it is the time interval between two consecutive time slots; for now, it must be kept at 30 minutes. In the future, more values will be available.
  • format: whenever possible, date will be formatted in this way, but a weird choice here can lead to unhandled bugs. For now, tested formats are "Y-m-d H:i" and "d-m-Y H:i" only.
  • format_short: same as before, but without the hours and minutes part.
  • locale: it can help set the correct timezone.
  • timezone: the timezone string i.e. "Europe/Paris". This may not be enough to apply a timezone, if the respective timezone library PHP relies on is not installed on your hosting machine.
  • week: here you can change the short names of each day of the week, i.e. Mon for Monday, Tue for Tuesday etc. Simply replace the value with the one in your preferred language, as long as they maintain a fixed length of 3 characters with a capital first letter.

The service object

Each service may use a number of properties, some of which are optional.

  • name example: "Volley court": this is the full name of the service, it is mandatory, and will appear during the reservation process. We recommend to keep it quite short.
  • concurrent_reservations_per_service (default: 1): it allows to reserve multiple times per time slot (such as in a classroom)
  • keeper_reservations_command example "reserv_volley": The text of a button to see a list with all the active reservations for this service; reserved to the service manager. Must contain only alphabetic characters and underscores.
  • keeper_create_button (default: true): if set to true, displays the button as indicated above.
  • short_name example "volley": this is a short name for the service, used in all text commands involving this service and shown in the pro forma ticket. Should contain only alphabetic characters, dashes, points or underscores and must not include spaces!
  • code (example: "SRV"): this is an internal ID of the service, an alternative identifier of the service to allow for even more flexibility of the bot app, by means of virtual services, so it is strongly recommended to specify it and it has to be unique. It should be 3 uppercase characters long.
  • parent (optional): if you want to declare a service as virtual, you have to specify the code of the 'parent' service this virtual services refers to. This way, all the virtual services associated with the same parent service will share with it a single timetable, thus they are concurrent!
  • unicode (example: "🟣"): here you can specify a character, or an emoji that will appear in the reservation text list. It is optional. We recommend to copy and paste it from a desktop version of the application and use an IDE like Visual Studio Code to ensure it is pasted properly.
  • price (example "5€ / hour"): an optional string with a price reminder; keep it small to make it fit in the pro-forma ticket
  • ticket_terms (example: "50% of the cost if you do not cancel at least 6 hours before"): an optional string with a terms reminder; ; keep it small to make it fit in the pro-forma ticket
  • gcolor (default is 1): if you associated the bot with Google Calendar, you can specify a color you want to associate with a reservation of this service. Usually, Calendar colors are represented with numbers spanning from 1 to 10.

Text and button commands

  • keeper_commands: a translatable (localized) list (JSON object) of text commands available to the owner only. It means they are processed only if the user chatting with bot has telegram id equal to the telegram_keeper_id and will be skipped gracefully otherwise. Most commands, according to a recommended practice, start with a dot. Here are the keeper commands:
    • "get_all_csv": ".get all": retrieve, in csv format, a list of all the reservations from day zero (this file may grow large over time, it is meant mainly for debugging purposes)
    • "get_latest_excel": ".get latest {lastreservations}": retrieve a number of latest reservations in excel format (.xslx) specified by the {lastreservations} parameter. As in all commands, the text on the right of the colon is an example, customizable to your liking! The only thing you need is putting one parameter with the named wrapped in curly braces. Parameters can sometimes be more than once.
    • all_active_reservations_xls: this is a special button only available to the owner to immediately get in excel format (.xlsx) all the active and user-cancelled reservations in the future.
    • "reservations_by_month": ".get {yearmonth}": this command allows the owner to retrieve only reservations of a single month. Example: .get 2024-04
    • "enable_registered_user": ".enable user {id}": it could be useful to give enable a registered and banned user once again. The id parameter is required. Example: .enable user 1234. In order to use this kind of commands, the owner (or developer) must know the telegram id of the user, as it is saved in the database, and it can be retrieved with the command specified in the property: get_registered_users.
    • "disable_registered_user": ".disable user {id}": this is equivalent to banning a user. They won't be able to use the service IF the registration system is set to true via the use_signup property. Example: .disable user 1234.
    • "cancel_one": ".cancel {rid}": this allows the owner to cancel a reservation, that is to set a reservation with id equal to the rid numeric parameter to 'cancelled' status (it does not delete the database record).
    • "set_day_shift": ".set rule {weekdayshort} {shifts} {startfrom}": a structure offering services won't be open all the time; this text command allows the owner to set up to 3 working time shifts per specific day of the week. Reservations will be available only during this time intervals on the specified day. Let's say we want to set the shifts for every Monday, from 8 to 11 AM, and from 2 to 8 PM, and we want the rule to be active starting from July the 5th, 2024 and ending August, 22nd, 2024. We'll have to write: .set rule Mon 08:00/11:00,14:00/20:00 2024-07-05 2024-08-22. Among all the rules we set for a day of the week, the last inserted one with a date in the past is the active one. We can also set a generic rule, that applies for all days that do not have a rule, through the JSON property shifts_default. This property also accepts up to 3 time intervals in the same format of the shifts rule, i.e. hh:mm/hh:mm, separated by comma and without spaces in the middle. It is also possible to delete the last inserted rule with the command specified in delete_last_inserted_rule. For more info about the shifts rule, take a look at the quick start guide or go below. Update (from version 0.19Beta): Now there is also a more strict variant of this command, named "set_service_day_shift" in the config file, allowing you to add the short_code of your service at the end of the text, so that the rule will apply ONLY for a specific service. If any such rule is set, it will prevail over the generic rule.
    • multiple_reservation": ".book {x} times {startingday} {shift} {service} {username}": Can be used to book several times starting from a given day and repeating the same reservation on the same day of the week at the same time, on behalf of a customer or to lock some hours of the day
  • user_commands: this object mainly contains the button-commands text strings. Although different strings may work, it is recommended to use only characters and underscores, without spaces in between. One special text pattern is not related to a button, it is the content of write_your_name. This allows to choose the text that lets the bot understand you are inserting your name to complete the signup process. It is translatable as always, provided you preserve the structure with the leading point before the translatable word 'name', and that the word you choose doesn't conflict with any other command in the application.

Media files

You can make further customizations to your application by modifying the media files. There are two media files that you can use: one is the reservation ticket. The application code is packed with a sample blueprint of a ticket, located in assets/ticket_blueprint_generic.png. You can change it to your liking, but since the code will try to print text on top of it, it is recommended to use an image file of the same (or similar) size for the text to fit in the image canvas. You can also have a small overprinted logo on the ticket (appearing on the top right).

The info command, available for all users, is meant to provide general information about your bot. You can put text in simplified html format (only 'inline' tags like b, i, pre are allowed in Telegram) in the help config variable. At the current stage of development, you can also associate an image or a text file if you need to show something different. all you have to do is create that file, and put the file path relative to the project root in a config variable named infographics. Text will be shown inside 'pre' tags, so that it will ben monospace (this is useful if you want to shows some ASCII tables like the example in assets/info.txt but be careful: Telegram has a limit of horizontal characters, then the text will be shown in a new line); instead, the image allows for more flexibility, although it is recommendable to keep the file size as small as possible, so the user will receive a faster response.

Shift rules

In order to show availabile reservation times to a user, the application tries to apply a hierarchy of rules that determine if a certain time of the day is available for reservations or not. Given a specific day of the week, as chosen by the user in the booking process, the code will:

  1. Look for rules of time shifts associated with that day of the week and service, and currently active; these rules are stored in the database.
  2. Look for general rules of time shifts related to that day; these rules are stored in the database.
  3. Look for the general working shifts specified in the config file for that service.
  4. Look for the general working shifts specified in the config file for ANY service.
  5. Make all times of the day available, i.e. 00:00 -> 23:59.

You can specify all of the first four or even none of these types of rules. The fifth rule is a fallback rule set directly inside the code to avoid errors.

Connecting to Google Calendar API

To add reservations as events to a Google Calendar, even if the calendar is not associated with a Google Workspace account, this bot uses Google service credentials. Please follow these steps:

  1. Go to the Google Cloud Console.
  2. Create a new project (or select an existing one).
  3. Enable the Google Calendar API for the project.
  4. Go to APIs & Services > Credentials and create a new credential of type Service Account.
  5. When creating the service account, make sure to download the JSON file with the credentials.
  6. Save the credentials in a folder of the bot software (create a new one if you wish to)
  7. Go to the Calendar (it may belong to any account, not just the one where you activated the G Calendar API) with the service account email (e.g. service-account-name@project-id.iam.gserviceaccount.com), giving it permission to Add events or Edit events.
  8. Put the account email and the relative path to your credentials (without trailing slash) in you ENV variables.
  9. Start the bot and book a service :)

This page was last edited on 2024-09-09 08:40

Powered by Wiki|Docs

This page was last edited on 2024-09-09 08:40

Zweb Studio
(c) 2024 zweb studio all rights reserved

Powered by Wiki|Docs