03 Nov 2020

Using DayBack with Salesforce Lightning Scheduler Part 2 – Appointment Availability

This is the second in a series of posts integrating DayBack Calendar with the Salesforce Lightning Scheduler app. In part one, we looked at how to customize DayBack to reflect Lightning Scheduler’s data model. This article will examine how to display a particular Service Resource’s availability in DayBack when scheduling a Service Appointment.

With this integration complete, you can do visual scheduling in DayBack Calendar while respecting the resource availability set up in Lightning Scheduler. (If you’re new to resource scheduling in DayBack, the overview video here demonstrates what’s possible.)

Need help? The instructions and example code that follows is designed to show you how this customization works and to let developers add this to their own deployments. If you’d rather we deploy this for you, we can customize this feature and add it to your DayBack as part of an implementation package. Just get in touch.

Lightning Scheduler’s Availability Objects

Lightning Scheduler provides three objects for determining when a particular resource is available for scheduling. The first two are Operating Hours and Time Slots. These are related objects: Operating Hours is a rule associated with a particular resource, and the Time Slots are child records that represent the days and times the resource is available.

Lightning Scheduler Appointments

Lightning Scheduler’s Operating Hours and Time Slots

The third object is Resource Absences. This object designates when a certain Service Resource is unavailable on a specific date and time. Unlike Operating Hours and Time Slots, resource absences denote unavailable blocks, where Time Slots denote available blocks.

Resource Availability in Salesforce

Resource Absences for date and time-specific unavailability

Setting Up Resource Absences

Since Resource Absences represent unavailable time and have specific starting and ending times, they can be set-up as a source in DayBack with the “Show As Unavailable” setting enabled as documented here.

A little bit of customization is required for this source since the Service Resource is a related field. Add a new custom formula field to the Resource Absence object so you can display the Service Resources name. With that name, the Looking Up A Resource ID By Name (Salesforce) example documents here can be added so that the Service Resource can be edited in DayBack. This is a little quicker than setting them up on the native Service Resource page. Once that source is enabled, DayBack will display the absence like this:

Resource Scheduling in Salesforce

Resource Absence blocks out time from 11:00 am until 2:00 pm for LA Exam Room 2 on Tuesday

Setting up Operating Hours and Time Slots

Unlike Resource Absences, which have specific dates and times, Operating Hours and Time Slots are more like rules that will need to be translated to specific dates and times. Time Slots also represent availability, so we’ll calculate the inverse so DayBack can display Time Slots as unavailable. To accomplish this, a Custom App Action will be needed to do the following:

  • Query operating hours and time slots in Salesforce
  • Calculate if the results match resources and days in the current view
  • Calculate those results as unavailability and create virtual DayBack events
  • Add the virtual unavailable events to the existing unavailable calendar source and render them

We’ll do this in the code below.

Leveraging Existing Queries

The new App Action will need to associate a Service Resource with its related Operating Hours record. Since DayBack is already querying Service Resources and Service Territories on start-up in the On Resources Fetched action that was set up in the first article, it makes sense to add the Operating Hours data that’s needed to that query and then write that data to a settings object in DayBack that can be retrieved in the new Custom App Action.

You’ll make some small changes to the original On Resources Fetched action. The Operating Hours Id field needs to be added to the SOQL query. A simple loop is then added to create an object for mapping the Service Resource ids to their related Operating Hours ids. This object is then written to the SeedCodeCalendar config object, where it will remain available for the remainder of the session. Here’s the new version of the On Resources Fetched Action.

The changes are in line 24 and lines 51 through 58.

 

//Purpose:
//Queries the Service Resource and Service Territiory objects to load resoures dynamically
//Resources are Service Resources and folders are their related Service Territories' names
 
//Action Type: Custom App Action - On Resources Fetched
//Prevent Default Action: Yes
 
//More info on custom event actions here:
//https://docs.dayback.com/article/140-custom-app-actions
 
//retrieve our canvas client object for authentication
var client = fbk.client();
 
//retrieve our canvas context object for REST links/urls
var context = fbk.context();
 
//this user's profile Id
var profileId = context.user.profileId;
 
//retrieve the query URL from context
var url = context.links.queryUrl;
 
//SOQL Select Statement Fields;
var select = 'SELECT+ServiceResource.ResourceType,ServiceResource.Name,ServiceResource.Id,ServiceTerritory.Name,ServiceTerritory.OperatingHours.Id+FROM+ServiceTerritoryMember+';
 
//SOQL Where Clause
var where = 'WHERE+ServiceResource.IsActive=true';
 
//SOQL query
var query = select + '+' + where;
 
//final URL for GET
var finalUrl = url + '?q=' + query;
 
//build settings object for Ajax call to Salesforce
var settings = {};
settings.client = client;
settings.contentType = 'application/json';
settings.success = processResult;
 
//Use canvas function to query
Sfdc.canvas.client.ajax ( finalUrl , settings );
 
//callback for ajax call
function processResult(data) {
  if(data.status===200 && data.payload && (data.payload.totalSize > 0)){
    var records = data.payload.records;
    var newResources = [];
    var folderIndex = {};
 
    //capture Operating Hours data here
    //and store in seedcodeCalendar object
    var operatingHours = {};
    for ( var i = 0 ; i < records.length ; i++){
      name = records[i].ServiceResource.Name;
      operatingHours[name] = records[i].ServiceTerritory.OperatingHours.Id;
    }
    seedcodeCalendar.init('operatingHours',operatingHours);
 
    //create resource folders;
    for ( var f = 0 ; f < records.length ; f++){
      var folderName = records[f].ServiceTerritory.Name;
      if(!folderIndex[folderName]){
        var folder = createFolder(folderName);
        folderIndex[folderName] = folder;
        newResources.push(folder);
      }
    }
 
    //create resources
    //create resource folders;
    for ( var r = 0 ; r < records.length ; r++){
      var resourceName = records[r].ServiceResource.Name;
      var resourceId = records[r].ServiceResource.Id;
      var resourceFolderName = records[r].ServiceTerritory.Name;
      var resource = createResource(resourceName,resourceId,resourceFolderName,resourceFolderName);
      newResources.push(resource);
    }
 
    //sort and write to DayBack, overwrites any resources stored in settings
    newResources = dbk.filterFieldSort(newResources);
    seedcodeCalendar.init('resources',newResources);
    action.callbacks.confirm();
  }
  else {
    //continue with saved resources
      action.callbacks.confirm();
  }
 
}
 
 
 
//creates resource object
function createResource(name,Id,folderId,folderName) {
    var newResource = {};
    newResource.name = name;
    newResource.color = "rgba(244, 244, 244, 0.85)";
    newResource.folderID = folderId;
    newResource.folderName = folderName;
    newResource.id = Id;
    newResource.nameSafe = name;
    newResource.shortName = name;
    newResource.status = {
      folderExpanded: false,
      selected: false
    };
    return newResource;
}
 
//creates folder and it's required attributes in the object
function createFolder(folderName) {
  var folder = {};
  folder.folderID = folderName;
  folder.name = folderName;
  folder.folderName = folderName;
  folder.id = folderName;
  folder.color = "rgba(244, 244, 244, 0.85)";
  folder.nameSafe = folderName;
  folder.isFolder = true;
  folder.status = {
    folderExpanded: false,
    selected: false
  };
  return folder;
}

 

Add an After Events Rendered Action

A user can take lots of actions that will change which resources are in view, so an “After Events Rendered” action the best way to update the Unavailable calendar from the Operating Hours and Time Slots. This action will run every time events are reloaded and picks up things like changing the date range or the number of resource columns. Changes to calendars can cause this action to fire more than once, but the code can be written so the body of our action only runs once. Here’s the code for the After Events Rendered action:

LightningSchedulerPart2_AfterEventsRender.js

Once this action is in place, DayBack will display the unavailable time for all resources based on the Operating Hours and Time Slots data.

Availability in Lightning Scheduler

Time blocked out for all resources after 4PM as defined in Operating Hours and Time Slots

Optional: Enforcing Availability

At this point, DayBack is now displaying Service Resource’s unavailability, and depending on the rules of your org, a visual indication might be enough. However, if you want to enforce this and prevent Service Appointments from being scheduled for Service Resources designated as unavailable, a Before Event Save action can be added to DayBack as well. This will check the events blocking out time and see if the attempted edit will overlap with any unavailable time and prevent the edit with an error. Here’s the code for the Before Event Save action:

LightningSchedulerPart2_BeforeEventSave.js

With this action in place, any attempted edits that violate availability will result in an error message from DayBack, and the edit will be reverted.

Resource Availability in Lightning Scheduler

DayBack’s error message: attempted edit will be reverted

Conclusions & Using Timezones

Lightning Scheduler provides a rich data model for expressing availability for its Service Resources. DayBack can provide powerful visual and workflow tools to take full advantage of this data model. These tools can save a huge amount of time for your schedulers and give them the confidence that they’re scheduling Service Resources appropriately and preventing the need for rescheduling.

Note that DayBack can also allow schedulers to work across different timezones regardless of their local settings. Learn how to script the calendar’s timezone depending on which resources are in focus: Enhanced TimeZone Support in DayBack Calendar.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.