L

ately I’ve been doing some service catalog work for a couple of clients and I’ve come across a requirement that I really haven’t had to address before. The requirement deals with order guides…specifically with the ability to control the execution order of individual items within an order guide. You’re probably aware that ServiceNow provides complete control over the ordering of tasks within a catalog item, but what do you do with an order guide that needs to have one item complete before the next 2 items can start? There’s not a simple way to control this behavior by default so I came up with a way and I’ll share it here.

Initial setup

All of this depends on having the ability to identify whether or not an order guide is associated with an item that has been ordered, and which order guide that is. As such, your first step will be to make sure that you are recording the order guide used against the parent request record. This setup is not provided by default but you can add it by following the instructions in this article.

NOTE: This is recorded for you automatically in the Helsinki release and beyond! The instructions below reflect these changes as of the Helsinki release.

Establishing an execution order

Once you’ve validated that the order guide is being populated correctly you’re ready to set up the execution order for your items within that order guide. The solution is actually pretty simple and only requires 2 pieces, both of which are implemented in the workflow for the respective items within an order guide.

Example:
In order to illustrate this setup, I’ll use a simple example. Let’s say that you have an order guide for new hires that includes 2 items; ‘Computer Workstation’ and ‘Computer Software’. Both of these items need to be ordered and delivered as part of the new hire process, but they need to be delivered in a specific order. The ‘Computer Software’ item cannot be started until the ‘Computer Workstation’ item has finished because we need to have a workstation to be able to install the software.

The first step is to modify the graphical workflow associated with item 1 (the ‘Computer Workstation’ catalog item). The workflow should run through the same process whether or not the item is ordered as part of an order guide, but at some point in the workflow (probably right before the end) we need to check if the item is associated with an order guide and then tell the next item to start. The next item in this case is ‘Computer Software’.

We don’t have direct access to the next item, but we can easily set up a ‘Run script’ workflow activity to query for that item and set a value there telling the item that it can start. I’ve found that the simplest way of doing this is to set the ‘State’ field on the next request item record to ‘Work in Progress’. The script below can be used in your ‘Run script’ activity in your workflow. Just replace the name of the ‘Computer Software’ item below with the name of the item in your system.

‘Start next item’ Run script workflow activity
Name: Start next item
Script:

//If item is part of an order guide then start next item(s)
if(!current.order_guide.nil()){ //Change to 'current.request.u_order_guide' for pre-Helsinki
   //Start the 'Computer Software' item next
   itemStart('Computer Software');
}

function itemStart(nextItemName){
   //Query for the item that should start next
   var item = new GlideRecord('sc_req_item');
   item.addQuery('request', current.request);
   item.addQuery('cat_item.name', nextItemName);
   item.query();
   while(item.next()){
      //Set the item to 'Work in Progress' to initiate the item workflow (requires 'Wait for' activity in item workflow)
      item.state = 2;
      item.update();
   }
}


This script works great, but it’s only part of the puzzle! Unless you tell item 2 (Computer Software) to wait for item 1 (Computer Workstation) then your script isn’t going to work the way you need it to. So, the second configuration change you’ll need to make is to add a ‘Wait for’ activity to the graphical workflow associated with item 2 (Computer Software). The ‘Wait for’ activity placement should probably be the first activity in the item 2 workflow, but will depend on your specific workflow. It should only apply if an order guide is associated with the parent request and the state is ‘Work in Progress.

Order Guide Wait For Activity

If you’ve followed the instructions above correctly, you should now be able to order your order guide item and execute the items in the order you’ve specified in the workflows. You can handle any order guide execution order scenario by repeating the same steps in the workflow for each item. If you have multiple items that need to start when item 1 is finished, then simply add those items to the script from item 1 and add the wait for condition to items 2, 3, 4, etc…

Bonus! Copying variable values from one item to another

Because your items are associated under a single order guide, it might also be necessary to pass variable values from one item to another. In order to do this, you’ll need to make sure that each item sharing variable values this way has an identically-named variable to place the value in. Once you’ve got that you could execute the following script inside a workflow ‘Run script’ activity.

copyVariables();

function copyVariables(){
   //Copy the matching variables from this item to the other item(s) in this request
   //Query the item option table for item variables
   var rec = new GlideRecord('sc_item_option_mtom');
   rec.addQuery('request_item', current.sys_id);
   rec.query();
   while(rec.next()){
      //Query for the same variable associated with the parent Request's items
      var itemVars = new GlideRecord('sc_item_option_mtom');
      itemVars.addQuery('request_item', '!=', current.sys_id);
      itemVars.addQuery('request_item.request', current.request);
      itemVars.addQuery('sc_item_option.item_option_new.name', rec.sc_item_option.item_option_new.name.toString());
      itemVars.query();

      //If we find a matching variable in another item update its value
      while(itemVars.next()){
         //Get the variable value record
         var itemVar = new GlideRecord('sc_item_option');
         itemVar.get(itemVars.sc_item_option);
         itemVar.value = rec.sc_item_option.value.toString();
         itemVar.update(); 
      }    
   }
}