- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
It was a dark and stormy night. In the IT department, requests rained down in great torrents - except at occasional intervals, where end users were temporarily content with the assets assigned to them...
How do you handle requests for items such as end user computers? Do you provide a standard catalog of specific items from which the users can select? Or do you just have a generic catalog item for the request and then allow IT or someone else doing the fulfillment select the type of device?
The lifecycle of an asset begins with the request of an item. To facilitate the service catalog's connection to Asset Management, Catalog Items can be created directly from Model records in ServiceNow. This has several benefits:
- Determine if you have an item in stock to fulfill the request instead of purchasing new
- Create the Asset record when it is procured to effect updates to the asset details automatically as part of the receiving and deployment of the item
- Manage details about a model of device in a single location instead of in separate Model and Catalog Item records
But there is a problem (cue thunder and lightning)...
Many companies do not want to give their users a choice of specific device. They want to just give the users more generic options and then fulfill the request with what makes the most sense at the time.
For example, the company standard might be the HP EliteBook 1030 today, but the transition to the newer HP EliteBook 1040 may be in progress. Rather than having users select one model or the other, these companies would rather just have their users select Company Standard Laptop. Then the users either get one of the 1030s in stock or get lucky and receive a 1040.
In the past, I've recommended the use of bundles to achieve this result. You can create a Bundle Model called Company Standard Laptop (or whatever naming is appropriate to the situation), then make the main component of the bundle the device you want to provide at the time. This does achieve the goal of obscuring the actual item from the user. Unfortunately, this approach has a few limitations:
- The main component is fixed and needs to be updated in the Bundle Model to change it - it cannot be changed when the request is fulfilled
- Bundle Models are not Hardware Models by default, so you need to change the Class to be able to publish the Bundle to the Service Catalog for end users to request
- Bundle Models are not maintained in stock as bundles - to source them, you need to break out the main component (it is beyond the scope of this particular post to get into how to handle a bundle that has multiple items)
There must be a better way!
And there is!
Below is an approach that provides the desired result without the negative side effects. This only covers the bare essentials for what you need to do to make this work. You can fill in the rest with other details. At minimum, you need:
- The generic Catalog Item
- A Variable on the Catalog Item
- A Catalog UI Policy to only display the Variable on a task created as part of the fulfillment of the item, NOT on the initial request form
- A Workflow to attach to the generic Catalog Item that creates the task to select the item to use for fulfillment of the request and then runs a script to create the new Requested Item against the Request
- Catalog Items for any Models of device that should be available for selection as part of this process
The first thing you need is a generic Catalog Item. Navigate to Service Catalog > Catalog Definitions > Maintain Items. Click New. Name the Item, select the Catalog and Category, and Save.
Next you need a Variable. This can be part of a Variable Set if you plan to use it in multiple Catalog Items. In fact, I recommend this. The key to the Variable is that it should be a Reference field that points to Catalog Item [sc_cat_item]. This makes later scripts easier and only displays items that have explicitly been published to the catalog. You can apply whatever other filters you deem appropriate for this. For example, maybe only display Certified Models.
The Catalog UI Policy is part of the magic here. This allows you to hide the Variable to the end user making the request, but display it in a later task so the Workflow can take action on it. Create a new Catalog UI Policy. Name the new policy something meaningful, like Hide Catalog Item selection in Catalog and Save it. Under Related Links, click Advanced view. This gives you the option under When to Apply to only apply the UI action on a Catalog Item view. Do not set any other conditions. Add the variable and set the Visible flag to False.
The Workflow takes this information and uses it. Your workflow can contain whatever approvals or other steps you require for your process, but at some point it needs two activities:
- The task that allows the Model of device to be selected
- The script that adds a Requested Item for the Model to the request, thus allowing it to be sourced and handled as if it were directly selected by the end user
The Task should be a Catalog Task (use the Catalog Task activity, not the Create Task activity). Identify the Fulfillment group to do the work and a short description with instructions/details on how to make the appropriate selection. The key in this Task, though, is to be sure to select your variable under the Add Variables section of the Task.
The script to include in a Run Script activity leverages an undocumented Service Catalog API described in several places around the Community (EDIT 29 Sept 2017: Documentation on the API is now available, albeit limited): https://developer.servicenow.com/app.do#!/api_doc?v=jakarta&id=GlideappCalcHelperAPI ). Here is the script to include:
// Script to create new RITM attached to the same REQ to source a Server of the selected Model
// get the sys_id of the Catalog Item from which to create the RITM
var ritmTemplateID = current.variables.server_cat_item;
// undocumented feature - no API definition unfortunately
// appears to do the following:
// - Create new RITM based on template
// - Copy all variables from the template to the new RITM
// - Associate the new RITM to the current RITM
var requestHelper = new GlideappCalculationHelper();
//1)pass in the Request sys_id, 2)Catalog Item sys_id, 3)1 is equal to the quantity times to order this catalog item
requestHelper.addItemToExistingRequest(current.request + '', ritmTemplateID + '', 1);
// This resets the REQ to redo any sourcing steps that need to be performed
requestHelper.rebalanceRequest(current.request + '');
// Find the new RITM (it should be the most recent)
var reqItem = new GlideRecord('sc_req_item');
reqItem.addQuery('request', current.request + '');
reqItem.addQuery('cat_item', ritmTemplateID + '');
reqItem.orderByDesc('number');
reqItem.setLimit(1);
reqItem.query();
if (reqItem.next()) {
// Since the variables are being created by the undocumented API used above
// need to get the original RITM variable values and populate those values
// in the RITM being created.
copyVariables(reqItem.sys_id, current.sys_id);
}
// Copies the variables from original RITM to new RITM
function copyVariables(newRITM, orginalRITM) {
var newRequestedItem = newRITM;
var vars = [];
var itemVars = new GlideRecord('sc_item_option_mtom');
itemVars.addQuery('request_item', orginalRITM);
itemVars.query();
while (itemVars.next()) {
vars.push(itemVars.sc_item_option.toString());
}
for (i = 0; i < vars.length; i++) {
var myOption = new GlideRecord('sc_item_option');
myOption.addQuery('sys_id', vars[i]);
myOption.query();
while (myOption.next()) {
//Catalog Item variable value will contain string/seconds/sys_ids/etc.
//Question //Value //Order //new RITM
createItemOptions(myOption.item_option_new, myOption.value, myOption.order, newRequestedItem);
}
}
}
// Copies the values in the variables from original RITM to new RITM
function createItemOptions(item_option_new, value, Order, newRITM) {
var gr_answers = new GlideRecord('sc_item_option');
gr_answers.initialize();
gr_answers.item_option_new = item_option_new; // Map the answer to its question
gr_answers.value = value;
gr_answers.order = Order;
gr_answers.insert(); // Insert the record
// Now build the relationship between the answer and the request item
var gr_m2m = new GlideRecord('sc_item_option_mtom');
gr_m2m.initialize();
gr_m2m.sc_item_option = gr_answers.sys_id;
gr_m2m.request_item = newRITM;
gr_m2m.insert(); // Create the new relationship
}
The final step is to be sure you have Catalog Items to select as part of this process. Because the purpose of this entire exercise is to not allow end users to select these items, when you publish hardware items to the catalog, be sure to configure them to not display to the end users, either by publishing to an IT only catalog or the use of User Criteria.
Now the user places the request for the item, and in the process, the appropriate group selects the type of device provided to fulfill the request.
With this in place, you can avoid torrential generic requests that are difficult to manage and set the stage for sunny days, happy end users, and even happier IT staff.
- 3,314 Views
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.