Control the Execution Order of Request Items in an Order Guide

//Control the Execution Order of Request Items in an Order Guide

Control the Execution Order of Request Items in an Order Guide

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(); 
      }    
   }
}
By | 2018-07-09T14:59:57-06:00 August 23rd, 2011|Categories: System Definition|Tags: , , |15 Comments

About the Author:

15 Comments

  1. Shane Brazeal August 23, 2011 at 10:08 am - Reply

    I had a similar requirement in the past to be able to choose an existing requested item and copy all the variables into a new request. I used JSON to build a string with all the name/value pairs and then set the form with the client script.

    Script Include (findItemVariables)

    gs.include("JSON");

    var findItemVariables = Class.create();

    findItemVariables.prototype = Object.extendsObject(AbstractAjaxProcessor, {

      findVariables: function() {

        var item = this.getParameter('sysparm_request_item');
        var set = new Packages.com.glideapp.servicecatalog.variables.VariablePoolQuestionSet();
        set.setRequestID(item.toString());
        set.load();
        var vs = set.getFlatQuestions();
        var find = {};
        for (var i = 0; i < vs.size(); i++) {
          if (vs.get(i).getDisplayValue() != "") {
            eval("find." + vs.get(i).getName() + "=" + '"' + vs.get(i).getDisplayValue() + '"');
          }
        }
        var json = new JSON();
        var text = json.encode(find);
        return text;
      }

    });

    Catalog Client Script

    function onChange(control, oldValue, newValue, isLoading) {
       //calls the findItemVariables script include
       var ga = new GlideAjax('findItemVariables');
       ga.addParam('sysparm_name','findVariables');
       ga.addParam('sysparm_request_item', g_form.getValue('request_item'));
       ga.getXMLWait();
       var answer = ga.getAnswer();
       answer = eval("(" + answer + ")");
       for(x in answer){
         if(typeof(answer[x]) == "string"){
         eval('g_form.setValue(' + '"' + x + '"' + ',' + '"' + answer[x] + '"' + ');');
         }
       }
     }
    • Mark Stanger August 23, 2011 at 10:31 am - Reply

      Awesome. Thanks for sharing this. If I needed to populate the variables in a client script I would definitely use something like this. If I needed to populate the variables in a workflow or business rule I could use a script like mine above.

  2. Tony Fugere August 30, 2011 at 3:12 pm - Reply

    This is great. I’m doing something similar, but I’m opening the flood gates after the User Creation RITM is complete on a New Hire. We have to wait for the user to be created in LDAP, sync’d to ServiceNow and update the “Requested For” so it becomes accurate on the Desktop, Software, Phone requested items, etc.

      var ritm = new GlideRecord('sc_req_item');
      ritm.addQuery('request', current.request.sys_id);
      ritm.addQuery('sys_id', '', current.sys_id);
      ritm.query();
      while(ritm.next()) {
         ritm.state = 2;
         ritm.update();
      }
  3. Luis Nunez August 4, 2014 at 3:41 am - Reply

    Hi Mark,

    I implemented this and works perfectly. However, given that the “next items” are waiting for the first one to complete IF approved (in my case), how do I get to cancel the workflows for these “next items” if the first one is not approved, as these others depend on this approval?

    Thanks in advance for your input.

    Cheers,
    Luis

  4. Adam Seeber November 2, 2014 at 10:42 pm - Reply

    Hi Mark,
    This is fantastic, thank you. Any ideas on how to set the variable in Step 2 in the latest Eureka release? request.order guide isn’t a variable I can choose… I can plug in parent.tasktype and use that as a Request, but that assumes that every REQ is going to be part of an order guide… bit messy?

    Cheers,
    -Adam

    • Mark Stanger November 3, 2014 at 7:22 am - Reply

      Have you followed the initial setup listed above? In order to get the ‘request.u_order_guide’ field you have to create it by following the instructions included in the article I link to above.

      • Adam Seeber November 3, 2014 at 11:03 pm - Reply

        Of course not! I’m a user and only half-read everything 🙂 I’ll give it a crack tonight and see how I go, thanks for being polite about it!

        Cheers,
        -Adam

  5. Shane C August 10, 2016 at 5:20 pm - Reply

    Hi Mark,
    Do you know if Geneva or Helsinki has any sort of OOB functionality for this, or are you still using your custom approach with clients?

    Thanks!

    • Mark Stanger August 10, 2016 at 5:20 pm - Reply

      There’s nothing new in Helsinki or Geneva to do this as far as I know.

  6. Scott October 14, 2016 at 8:21 am - Reply

    Just to validate, do all of the request items still get created at the very beginning? Does this just control when certain request item’s states gets set to “work in progress” as dependent items are completed?

    • Mark Stanger October 14, 2016 at 8:46 am - Reply

      All of the requested item records will always get created right at the beginning regardless of what you do. This helps to control the workflow so that they only get opened and put into people’s work queue when they’re supposed to.

  7. Tyson Wenger March 6, 2017 at 3:30 pm - Reply

    Hi Mark,

    I’m a bit confused on the second step. Based on the provided example, it looks like it will wait on the “wait activity” even when the request isn’t made from an Order Guide.

    Are you saying there should be a “conditional if activity” before the “wait activity” checking if the Order Guide is set on the request?

    Thanks,

    -Tyson

    • Mark Stanger March 6, 2017 at 4:20 pm - Reply

      Yes, the example shown above would really only apply if the second item was always part of the order guide. A conditional activity in your second item would allow the flexibility of handling multiple types of flows.

  8. Nivedit May 15, 2017 at 3:29 am - Reply

    Hi Mark,

    The script to pass variables between various catalog item should be written in which workflow..I tried putting it in the 1st Requested item but it didnt work… The other scripts work as expceted.

Leave A Comment