Documentation

Reservation Scripts

Overview

Reservation scripts are a powerful tool to implement custom rules for allowing or disallowing reservations and for dynamically modifying reservations on the fly. Reservation scripts will typically either return an Exception when a reservation cannot continue as is or a Result for when a reservation can continue as but, optionally, some additional UI elements may need updating.

Exceptions

Exceptions are the one way to abort a sneq script from anywhere within the script, including nested functions, and return some value.

For reservations and requests, the return value of the Exception determines how a script failure is reported to the user.

As a string

If the Exception is a string, the conflict message will be set to that string.

1return Exception("Hello world")
hello_world_exception.png

Tip: Avoid punctuating the last sentence of your exception with anything other than a period, because by default all conflicts will have a period appended to them if one is not present as the last character.

As a dictionary

The dictionary form of an Exception is used to control behaviour in the reservation/request modal. The dictionary should be in the following form:

1{
2 'conflict'?: <str>,
3 'alert':? {
4 'title': <str>,
5 'text': <str>,
6 'confirmText'?: <str>,
7 'type'?: <str>, # 'error', 'info', 'question', 'success', or 'warning'
8 },
9 'times'?: {
10 'start': <datetime>,
11 'end': <datetime>,
12 'lockStart': <bool>,
13 'lockEnd': <bool>,
14 'lockStartPermanent': <bool>,
15 'lockEndPermanent': <bool>,
16 },
17}

conflict

If the conflict key is set and a string, the conflict will be set in the reservation/request modal.

alert

If the alert key is set to a dictionary as above, an alert will be displayed to the user.

1return Exception({
2 'conflict': 'foo',
3 'alert': {
4 'title': 'Title goes here',
5 'text': 'Text goes here',
6 'confirmText': 'confirmText',
7 'type': 'success',
8 },
9})
alert.png

Date/time manipulation

Exceptions allow you to lock the date and time on your reservation. It also allows you to set them. Care must be taken when setting the start and end datetimes so that the reservation does not go into an infinite loop. For example, two scripts both setting start dates could easily send the booking modal into an infinite loop of conflict checks.

In the times value, start and end refer to datetime objects that are used to set the start and end date.

lockStart and lockEnd are used to lock the start and end times once, until the current conflict is cleared.

lockStartPermanent and lockEndPermanent are used to lock the start and end times indefinitely, and these locks will not change when another conflict check is made, for example, when a user changes the resource.

Below is an example that sets the start and end date to be January 1, 2021 at 12AM and February 1, 2021 at 12 AM, then locks the times to prevent the user from changing them.

1start = datetime.from_date_and_time(
2 year=2021,
3 month=1,
4 day=1)
5end = datetime.from_date_and_time(
6 year=2021,
7 month=2,
8 day=1)
9
10# Do not infinite loop conflict checking if the start and end times
11# are what they should be.
12if reservation['start'] == start and \
13 reservation['end'] == end:
14 return True
15
16# If they aren't what they should be, set them to what they should
17# be and then lock them.
18return Exception({
19 'times': {
20 'lockStartPermanent': True,
21 'lockEndPermanent': True,
22 'start': start,
23 'end': end,
24 },
25})

Upon testing this script, you will see output like this:

testing_exception_times_1.png

Attach the script to a resource, then try on the calendar. You will see that the time has been fixed as per the script.

testing_exception_times_2.png

Resource manipulation

The list of resources can be set by returning an Exception dict that contains the key "reservables".

1return Exception({
2 'reservables': [
3 {
4 'reservable_id': <str>, # Required
5 'units'?: <dec> or <int>, # >= 1, default is 1
6 'rate_id'?: <dec> or <int>, # Integer for the rate ID of choice
7 },
8 ...
9 ],
10})

Note and purpose manipulation

You can set the value of the reservation's note and purpase by returning an Exception dict with "purpose" and "note" fields. Furthermore, you can lock the purpose or note from editing by also returning "lockPurpose" and "lockNote".

1return Exception({
2 'lockNote': <bool>,
3 'lockPurpose': <bool>,
4 'note': <str>,
5 'purpose': <str>,
6})

Return Results

Results of a script may also modify the state of a reservation when no conflict exists. You can access these functions by returning a dictionary.

true

If a reservation script decides that a reservation can proceed as is, simply return True.

disclaimer_resource

String with markdown syntax. Sets a disclaimer below the resource in the reservation booking modal. The first disclaimer found for the resource will be the one shown to the user in the case that there are multiple resource disclaimers present from multiple scripts.

What resource this disclaimer applies to is determined by which resource the script is attached to. For example, if the reservation is for two resources but the script is only attached to one of them, the disclaimer will only show for the one the script is attached to.

Example:

1return { 'disclaimer_resource': '## foo' }

disclaimer_top

String with markdown syntax. Sets a disclaimer above the list of resources in the reservation booking modal. The first script output with disclaimer_top set will be the one shown to the user in the case that there are multiple top-level disclaimers present from multiple scripts.

Example:

1return { 'disclaimer_top': '## foo' }

lockNote and lockPurpose

If you are setting the note or purpase with an exception it can be useful to always lock the value afterwards or when editing. This can be done without throwing an exception by returning an object with one or both of these keys set to true. Typically a reservation script would return an exception with a note or purpose value and a lock if the purpose needs to be set. If the purpose does not need to be changed, simply return the instruction to lock the fields so that no additional editing can take place.

1return {
2 'lockNote': <bool>,
3 'lockPurpose': <bool>,
4}