Xander H
ServiceNow Employee
ServiceNow Employee

Introduction

A common use case in Field Service Management is defining when field agents are allowed to fulfill tasks. This can be a specific date range during which the visit has to take place, which is done through the window start and end, but in addition, there are certain times during that window in which the visit can take place.

 

This can have various reasons: locations or sites are only open during those specific times (i.e. structurally), such as being closed on Mondays, or being open only from 9am - 6pm. It can also be that the visiting schedule is completely dynamic and maybe even controlled by the end customer, i.e. only on January 31st between 9:00 - 18:00, on February 2nd between 18:00 - 21:00, on February 16th between X and Y, and so forth. Finally, it can be a combination, i.e. every Mon-Fri between 9 and 18, but in addition, on Fridays 18:00 - 20:00, EXCEPT on January 31st, during which the visit can not take place at all.

 

All of this is captured in the Field Service Management Access Hours Management plugin. This article aims to supplement the official documentation in clarifying some of the use cases that the plugin supports, as it is more flexible than the documentation would have you believe.

 

The basics

After installing the Field Service Access Hours Management plugin (id: com.snc.fsm_access_hours), a new field opens up on the Work Order Task called Access hours (access_hours).

 

This field is a reference to a Schedule [cmn_schedule] entry, which will define the schedule that dynamic scheduling will respect. Manual scheduling can still occur outside of these hours*. This schedule can be configured like any others, with repeating events or with singular events.

 

* There is an obvious use case here for potentially also not allowing manual scheduling outside of this. I will elaborate on this further down below.

 

Creating the schedule

Defining a schedule is fairly well defined in the official documentation and I won't go into too much redundant detail.

 

In general, it's important to understand the FSM understands the notion of:

- Sub-schedules

- Repeat (type), repeat every X days, repeat until...

- Entries types using field Type = Exclude & Show as = Busy or Show as = Free/On call to define availability or exclusion

 

The latter is an important point - in order to support the use case of "blackout hours", or specific times when we are not allowed to visit, we would use Show as = Busy and Type = Excluded.

 

It is important to also note that "Child schedules" m2m record (cmn_other_schedule) should always have Type = Include, even when trying to exclude certain times. In that case, set Show as = Busy on the individual entries in order to exclude those times. When looking at ITSM type schedules (e.g. for use in blackout/maintenance), it is mentioned in the docs that it is also possible to set Type = Exclude, but I did not find this to work in FSM access hours.

 

Thus, we might envision a hierarchy of a schedules and sub-schedules. For one of our projects, access hours per WOT were highly dynamic and we created a flow that automatically created a schedule "Access hours for [WOT1234]" parent schedule record.

 

Through Child schedules, we included a frequently reused schedule as a "base". Such as Weekdays, 24x7, Weekdays 8-5 excluding holidays, etc. In addition, we created a child schedule with recurring and incidental absences, where the site was not available. This child schedule was linked with Type = Include, and each schedule entry had Show as = Busy and Type = Excluded.

 

Finally, we dynamically linked additional schedules depending on other logic in the flow which was dictated by upstream Work Order (Task) and Case fields, such as specific data on the Consumer and Location.

 

Defining access hours preferences (aka standard rules)

It is possible to set standard rules for access hours configuration, so that individual schedules do not have to be recreated where they are just by default shared across specific Accounts, Locations, Assets, Consumers, or any combination of the above.

 

By default, the only combination available is "Account Location", but if any other combinations are needed, it's possible to navigate to Field Service > Access Hours Configuration > Access Hours Levels, and create a new level. The matching criteria can be combined and ordered as desired. It is important to note that at this time, creating a new level is not possible. Script includes are included with the plugin that are set to read-only mode and should not be customized. In the case more flexibility is needed, a flow is recommended.

 

This can be done through Field Service > Access Hours Configuration > Access Hours Preferences. Based on one of the Levels (criteria) set up above, it is possible to define one of those combinations and then either set a static Schedule or use a script to identify one (and return the Access hours ID). The script field can be used when your selection criteria matches a (combination of) the access hour levels available, but some dynamic logic is needed. In case the selection criteria can not be properly captured in the Levels, like in our situation in the previous section, a flow is recommended.

 

Forcing manual scheduling to respect access hours

In order to force manual scheduling to respect access hours, there are 2 ways:

  • FSMAccessHoursUtil script include has a function called "validateAccessHours"
  • Run and validate all dynamic scheduling rules before assignment, which also respects access hours

For both solutions, create a before business rule in wm_task that fires when the state moves to Scheduled or Assigned. 

 

Only check access hours

For the first solution (only access hours), run FSMAccessHoursUtil's validateAccessHours function passing in the task. It will allow true if the access hours were respected. If false, use current.setAbortAction(true) to cancel the update.

 

Check all dynamic scheduling rules

For the second solution (full dynamic scheduling check), the same rough logic applies. The following example BR implements the ability to toggle this on/off per a system property, and also checks whether dynamic scheduling is even turned on at all. Afterwards, it runs the entire dynamic scheduling check for this assignment to see if the agent is included in this list (thus removing any agents that are not available, removes all work blocks not in the access hours, etc):

 

 

 

(function executeRule(current, previous /*null when async*/) {	
	var dispatchMethod = new sn_sm.SMConfiguration().getDispatchMethod(current);
	var enableRuleValidation = gs.getProperty('work.management.validate_rules_before_assign', false);

	if (dispatchMethod != 'dynamic' || !enableRuleValidation) {
		return;
	}

	// Check if agent is in the list of auto-assign rules allowed agents
	var allowedAgents = (new sn_fsm_disp_wrkspc.DynamicSchedulingUtil()).getAllowedAgentIdsForTask(current.getValue('sys_id'));

	// Agent is in list, so proceed.
	if(allowedAgents.indexOf(current.getValue('assigned_to')) >= 0) {
		return;
	}

	current.setAbortAction(true);

	gs.addInfoMessage(gs.getMessage("Agent {0} does not satisfy the scheduling criteria, assignment cancelled.", current.getDisplayValue('assigned_to'))); 
})(current, previous);

 

 

 

 

Conclusion

To summarize, the FSM access hours functionality is powerful and between simple configurations, semi-scripted configurations, and more complex flows, in combination with nested schedules and "Show as"-typed schedule entries to include and exclude, a wide variety of use cases and scenarios is easily covered.

 

Although the official documentation is a bit scarce on examples, I hope this article has helped you figure out how to define your access hour configurations. Happy scheduling!

Version history
Last update:
‎03-11-2025 02:46 AM
Updated by:
Contributors