line

Location Booking & Deposit Process

A workflow that manages the booking confirmation and deposit process for a marketplace where users can book event spaces at restaurants. The workflow launches when the customer requests a booking and triggers emails or SMS messages to manage the booking reservation and deposit processes between the location owner and customer. It also sends Slack notifications to the customer success teams keeping them updated on each step. It is not possible to book a place less than 1 day and half before. Notifications are sent using third party APIs such as Sendgrid and Twilio.

Visual of Workflow

This flowchart shows a visual representation of the workflow tasks.
line

Workflow Code

Workflow Input

A workflow instance is triggered when a user requests a booking. The user details and booking details are included in the workflow input: booking_day, booking_date, owner_id and owner_place.

The workflow will be launch with those user's input parameters:

{
  id: "1f2a0f5c-cfb5-44a2-a081-67d74a60af62",
  place_id: 23696,
  booking_day: "2019-12-01",
  booking_date: "2019-12-31",
  user: {
    email: "user@example.com",
    phone: "+33611223344"
  },
  owner: {
    email: "owner@the-best-restaurant.com"
    phone: "+33799887766"
  },
  deposit: true
}

Send Events To Booking Workflow

The OwnerReplyEvent event is sent to the workflow when the owner validates the booking request in the application.

Through the event, we send parameters about the need of a deposit:

{
  "name": "OwnerReplyEvent",
  "data": [
    {
      "status": "accepted",
      "deposit_amount": 235.98,
      "deposit_url": "http://..."
    }
  ]
}

The workflow will handle the event through the wait function that will receive the event name as a parameter.

this.wait.event("OwnerReplyEvent").for(24 * 3600);

The DepositReceivedEvent event is sent to the workflow when the user has paid the deposit:

{
  "name": "DepositReceivedEvent",
  "data": []
}

Structure of the workflow

This workflow is the code that orchestrates tasks (through the Zenaton workflow engine) and executes them on your servers.

const ​sendgridConnectorId = "";
const slackConnectorId = "";
const twilioConnectorId = "";

/* Workflow for booking validation with notifications to user, owner's place and customer success team  */
module.exports.handle = {
  *handle(booking) {
    // send email to the owner
    this.sendEmail(booking.owner.email, "request_to_owner");// wait for the owner's reply for up to 1 day
    const ownerReplyEvent = yield this.wait.event("OwnerReplyEvent").for(24 * 3600);// if the owner replies
    if(ownerReplyEvent) {
      // Get the owner's response from the event's data
      const [eventName, eventData] = ownerReplyEvent;

      // if the owner accepted
      if (eventData.status === 'accepted') {
        // Create a booking and save it to the database
        yield this.run.task("CreateBooking", booking);
      } else {
        // if the owner refused
        // alert the user about the cancellation
        this.sendEmail(booking.user.email, "owner_cancellation");
      }
    } else {
      // if the owner doesn't replied
      // send him an SMS reminder
      this.sendSms(booking.owner.phone, 'Hey, you have a pending resquest ...');
      // alert the customer success team
      this.slackTheCustomerSuccessTeam(`#${booking.id} is waiting for the owner's reply...`);

      // stops the workflow execution
      return;
    }

    // if the restaurant asked for a deposit
    if(booking.deposit) {
      // send a deposit request email to the user
      this.sendEmail(booking.user.email, "deposit_request");
      // notify the customer success team about the deposit request
      this.slackTheCustomerSuccessTeam(`#${booking.id} waiting for user deposit...`);

      // calculate the deposit deadline
      const waiting_time = yield this.run.task("CalculateWaitingTimeForDeposit", booking);
      // wait to receive the deposit up to it's deadline
      const deposit_received = yield this.wait.event("DepositReceivedEvent").for(duration.hours(waiting_time));

      if (deposit_received) {
        // send a confirmation text to the user
        this.sendSms(booking.user.phone, `Your booking #${booking.id} is complete !`);
        // update the booking record in the database
        yield this.run.task("SaveBookingMYSQL", booking);
      } else {
        yield this.run.task("CancelBookingRequest", booking);
        this.sendSms(booking.user.phone, `Your booking #${booking.id} has been canceled ...`);
        this.slackTheCustomerSuccessTeam(`#${booking.id} canceled: no deposit...`);
      }
    } else {
      // if the restaurant did not ask for a deposit
      // notify the user about the confirmation by SMS and email
      this.sendSms(booking.user.phone, `Your booking #${booking.id} is complete !`);
      this.sendEmail(booking.user.email, "user_confirmation");

      // Notify the customer success team about the new booking completion
      this.slackTheCustomerSuccessTeam(`#${booking.id} booking complete.`);
      // Update the booking record in the database
      yield this.run.task("SaveBookingMYSQL", booking);
    }
  },
  sendSms(phone, message) {
    const twilio_sms = this.connector('twilio_sms', twilioConnectorId);

    sms_params = {
      // build the payload that specifies the 'from', the 'to'
      // and the content of the sms depending on your sms provider.
    };

    twilio_sms.post('/Messages.json', sms_params);
  },
  sendEmail(booking, template) {
    const sendgrid = this.connector('sendgrid', sendgridConnectorId);

    mail_template_params = {
      // build the payload that specifies the 'from', the 'to'
      // and the content of the mail depending on your email provider.
    };

    sendgrid.post('/mail/send', mail_template_params);
  },
  slackTheCustomerSuccessTeam(message) {
    const slack = this.connector('slack', slackConnectorId);

    slack_message = {
      // build the payload of the slack message: title, message, ...
    };

    slack.post('/api/chat.postMessage', slack_message);
  }
};

Workflow Steps

Workflow is launched when the user creates a booking at a place with parameters location, deposit requirement (Y/N) and number of people.

  • Send a booking request email via Sendgrid to the location owner with the date, time and number of people.
  • Wait for the owner to respond (replyEvent) from the owner until 1 day.
  • If the owner refuses the booking, send an email via Sendgrid to the customer
  • If the owner does not reply within the wait time period:
    – send an SMS reminder to the owner via Twilio
    – send a slack notification to customer success team.
  • If the owner accepts the booking request:
    – Create the booking in the database with the booking data (date, time, number of people, location data, etc) in a task
    – Cancel other booking requests for other locations from the user in a task.
    – Send confirmation email via sendgrid to the location-owner with booking details

Check the workflow parameters to see if the location requires a deposit in the workflow parameters.

  • If the location does not require a deposit,
    – send the customer a confirmation SMS and email with booking and location details,
    – send a slack message to customer success that the a booking is confirmed,
    – update booking record in the database with confirmation details.
  • If the location requires a deposit,
    – send a booking confirmation email to the customer with details on how to make a deposit,
    – send a slack notification to customer success that a deposit has been requested,
    – execute a task to calculate the time to wait for the deposit - 36 hours from the date of request email or 6 hours before the event if the event is earlier than 36 hours. Learn more about idempotency in documentation.
    – Wait for the customer to pay the deposit (deposit event) until the amount of time (hours)that is calculated in the formula.

    • If the deposit is received within the wait period:
      – Send a confirmation SMS to the customer,
      – Update the booking record in the database with confirmation and deposit details.
  • If the deposit is not received within the wait period:
    – Execute a task to cancel the booking,
    – Send an email to the customer with cancellation details,
    – Send an email to the location owner with cancellation details.
    – Send a slack message to the team that the booking has been cancelled.

Workflow Executions

View real-time execution data for each workflow step on the dashboard. Drill down to see event data, task output and error messages and log files.
line