Documentation

Script Tasks with Triggers

Table of Contents

Script Variables and Examples

Script tasks use QReserve's sneq scripting language. QReserve injects global variables into each script so it can access the event, its associated objects, and results from earlier tasks.

These variables are dictionaries. For example, reservation["reservation_id"] reads a reservation's ID.

Variables Shared Across Trigger Types

Variable Description
workflow Information about the workflow run and the configured trigger condition.
outputs A list of outputs from tasks already executed in the current run. It is empty when no earlier tasks have run.
input_task Input supplied through the script task's Input Script Task ID setting. Only injected when input is supplied.
audit_log The audit entry associated with the triggering event. Available during automatic event runs; it may be absent during manual tests.

The workflow dictionary contains:

  • workflow["manual_run"]: Whether the workflow was started manually.
  • workflow["trigger"]["event_object"]: The configured trigger category, using its internal name.
  • workflow["trigger"]["event_type"]: The configured event type: create, modify, or delete.
  • workflow["trigger"]["subevent_type"]: The configured sub-event filter, or None when no specific filter is selected.

The trigger information describes the configured condition. For example, an approval trigger configured for All Events has a subevent_type of None, even when the particular approval event is an approval or denial.

When a workflow has an assigned user, workflow["user"] contains user_id, display_name, email, and bot. This is the workflow's assigned user; it should not be assumed to be the person who made the booking or caused the event.

workflow["for_date"] is provided for scheduled subscription runs with a run date. Event Hook scripts should not assume it is available.

Example: return the trigger configuration for inspection.

return {
    "category": workflow["trigger"]["event_object"],
    "event": workflow["trigger"]["event_type"],
    "filter": workflow["trigger"]["subevent_type"],
    "manual_run": workflow["manual_run"]
}

Approvals

Injected variables: approval and reservation, plus the shared variables above.

  • approval contains the individual approval record, including approval_id, status, note, approver information, and its linked reservation.
  • reservation contains the associated booking. For an approval attached to a component of a multi-resource booking, this top-level variable refers to the overall parent booking.

approval["approver"] can be None, such as when an approval is assigned to a group. Group information is available through approval["approver_site_user_group_name"].

Example: return the approval decision and associated booking ID.

return {
    "approval_id": approval["approval_id"],
    "approval_status": approval["status"],
    "approval_note": approval["note"],
    "reservation_id": reservation["reservation_id"]
}

The approval's current status can differ from its status when the event occurred. During an automatic approval modification run, the recorded transition is available through:

return {
    "previous_status": audit_log["meta_data"]["approval_status"]["old"],
    "new_status": audit_log["meta_data"]["approval_status"]["new"]
}

This second example applies to approval modifications, rather than approval creation or manual tests.

Maintenance

Injected variable: reservation, plus the shared variables above.

Maintenance bookings use the reservation variable. There is no separate maintenance global.

Useful fields include reservation_id, maintenance, start, end, purpose, and status. The maintenance field identifies the booking as maintenance.

Example: return the maintenance booking's purpose and scheduled times.

return {
    "reservation_id": reservation["reservation_id"],
    "maintenance": reservation["maintenance"],
    "purpose": reservation["purpose"],
    "start": reservation["start"],
    "end": reservation["end"]
}

Requests

Injected variable: reservation, plus the shared variables above.

Requests also use the reservation variable. There is no separate request global.

Useful fields include reservation_id, reservation_type, purpose, and status. When the request has an associated user, their details are available through reservation["reserved_for"].

Example: prepare a summary of the request for a later task.

return {
    "request_id": reservation["reservation_id"],
    "purpose": reservation["purpose"],
    "status": reservation["status"]
}

Resource

Injected variable: reservable, plus the shared variables above.

reservable contains the resource's current properties, including:

  • reservable_id
  • name
  • status
  • status_detail
  • active

Resource modification triggers also provide two additional values:

  • workflow["trigger"]["previous_value"]: The resource's status before the recorded change.
  • workflow["trigger"]["value"]: The resource's status after the recorded change.

These describe the triggering event. reservable["status"] describes the resource's current status when the script runs, which may have changed again.

Example: return the resource name and status transition.

return {
    "resource_id": reservable["reservable_id"],
    "resource_name": reservable["name"],
    "previous_status": workflow["trigger"]["previous_value"],
    "new_status": workflow["trigger"]["value"],
    "current_status": reservable["status"]
}

During a manual test without an actual event, previous_value and value are None.

If several resource status changes occur before processing, intermediate changes may be combined. The previous and new values describe the latest retained event, rather than the entire sequence of changes.

Reservations

Injected variable: reservation, plus the shared variables above.

Useful fields include reservation_id, start, end, purpose, status, cancelled, and is_loan.

For a booking associated directly with one resource, resource details are nested under reservation["reservable"]. For bookings containing multiple resources, component bookings are available through reservation["reservation_children"].

Example: prepare content for a follow-up email.

return {
    "subject": "How was your reservation?",
    "body": "Thank you for using our facilities. Please share any feedback about your booking.",
    "reservation_id": reservation["reservation_id"]
}

To use this content, assign the script a Task ID and select that ID as the input to a later email task. Configure the recipient in the email task. Returning this dictionary does not send an email by itself.

Status Events

Injected variable: reservation, plus the shared variables above.

reservation contains the booking or request associated with the status event. For multi-resource bookings, this may be an individual component or the overall parent, depending on which status changed.

Use reservation["status"] to read the status of the injected booking object.

During an automatic run, the recorded status transition is available through audit_log["meta_data"]["reservation_status"].

Example: return the status transition that caused the workflow to run.

return {
    "reservation_id": reservation["reservation_id"],
    "previous_status": audit_log["meta_data"]["reservation_status"]["old"],
    "new_status": audit_log["meta_data"]["reservation_status"]["new"]
}

For an Initial Status event, the previous status is unset. This example requires an actual event audit entry and should not be used unchanged in a manual test without one.

Templates

Injected variables: reservation, and conditionally template or sub_reservation, plus the shared variables above.

The available objects depend on the template event:

  • reservation is the primary booking object associated with the event. It can represent the template itself or a reservation created from a template.
  • template is injected when the event includes a related reservation template, such as Template is Used. It contains the template's reservation data.
  • sub_reservation is injected when the event includes a related booking that is not itself a template, such as the reservation that consumed a template.

The template global is a dictionary. The similarly named reservation["template"] field is a boolean indicating whether the primary booking object is itself a template.

Example for Templates > Reservation > Template is Used: return the new reservation ID and the template it used.

return {
    "reservation_id": reservation["reservation_id"],
    "template_id": template["reservation_id"],
    "purpose": reservation["purpose"]
}

This example specifically requires a template-use event. Other template events may not inject the template global.

Working With Optional Data

Some variables and dictionary fields are only present when the corresponding data exists. For example:

  • input_task requires configured input from another task.
  • audit_log may be absent during manual tests.
  • template and sub_reservation depend on the template event.
  • reservation["reserved_for"] requires an associated user.
  • reservation["reservable"] is not present on every multi-resource parent booking.

Use examples appropriate to the selected trigger and account for optional fields when extending them.

Injected objects provide data for the script to read. Returning a dictionary makes data available as the script's result; it does not automatically update the booking or resource. Configure subsequent workflow tasks to perform the required actions.