Service catalog Archives - ServiceNow Guru https://servicenowguru.com/tag/service-catalog/ ServiceNow Consulting Scripting Administration Development Tue, 07 Jan 2025 16:24:53 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png Service catalog Archives - ServiceNow Guru https://servicenowguru.com/tag/service-catalog/ 32 32 Be a Choice List “Thief” https://servicenowguru.com/system-definition/be-a-choice-list-thief/ Tue, 07 Jan 2025 16:24:53 +0000 https://servicenowguru.com/?p=17201 Do you find yourself duplicating the same choices across different forms and tables in ServiceNow? Manually updating these lists can be a real time-consuming hassle. Here's the good news! In my second article about powerful dictionary configurations, I will showcase a time-saving technique to reuse choice list values across your instance. This saves you time

The post Be a Choice List “Thief” appeared first on ServiceNow Guru.

]]>
Do you find yourself duplicating the same choices across different forms and tables in ServiceNow? Manually updating these lists can be a real time-consuming hassle.

Here’s the good news! In my second article about powerful dictionary configurations, I will showcase a time-saving technique to reuse choice list values across your instance. This saves you time and ensures consistency in your data management. This approach is particularly beneficial for multilingual environements, as you only need to translate the main choice list.

Use case 1: Linking Catalog Variables to existing Choice Options

There is a Choice field on a table, and we need to replicate this field on a Catalog Item or Record Producer form with the same choices.

For example, adding the Incident Category drop-down to the “Create Incident” Record Producer. On the left of the screenshot below is the Incident Category field as displayed in the Service Operations Workspace, and on the right is the Create Incident Record Producer in the Employee Service Center Service Portal.

  • To get these values onto the “Create Incident” Record Producer Form, create a new Select Box Variable to hold the values that need to be displayed.

  • Next, instead of creating mirror Choice options in the Question Choices Related List, navigate to the “Type Specifications” section on the Variable form. Enter the following values and save the variable:
    • Choice table: Incident [incident]
    • Choice field: Category

  • Now when we navigate back to the form in the Service Portal, we can see that there is a new Category field on the form, and it already has Choice values that exactly match the Incident Category selections. Now if you change the available Choices for the Incident Category field, the Variable drop-down values will automatically reflect those changes without have to repeat the configuration on the Variable record.

Use case 2: Reuse Choice List values in another field

Sometimes you need to replicate a choices options across several tables and fields to create consistency as data moves from one record to another, like Asset and CI attributes that exist on both records. –OR– You have several fields on the form with the same set of Choice options. For example, a design decision to use Yes/No Choice fields instead of Checkbox fields.

  • First, choose which table and field will drive the other fields options. The example will use Incident Category.
  • Navigate to the Dictionary record for the other field(s) that will be driven by the Incident Categories.
  • Find the Choice List Specification tab. If you don’t see the Choice table field, you may have to switch to Advanced view.
  • Enter the following values and save the Dictionary record:
    • Choice table: Incident [incident]
    • Choice field: Category

That’s it! Now, when you change the main field’s list, all of the other choice lists will reflect the change.

Summary

This article explored two simple ways to reuse choice list values in the ServiceNow platform. If you are a customer that supports multiple language, you’ve exponentially saved yourself some time, because you only have to translate the main field’s Choices and those changes will also be reflected everywhere as well.

By leveraging these techniques, you can streamline your ServiceNow configuration and save valuable time!

The post Be a Choice List “Thief” appeared first on ServiceNow Guru.

]]>
Identify which ServiceNow Record Producer was used to create a record https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/ https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/#comments Thu, 22 Jan 2015 16:42:42 +0000 https://servicenowguru.wpengine.com/?p=5518 Record producers are a great piece of ServiceNow functionality that allows for the creation of records in any table via the standard Service Catalog interface. This capability has been around for quite a while and odds are that you’re already using it in your system to allow end-users to create new incidents…among other things. Over

The post Identify which ServiceNow Record Producer was used to create a record appeared first on ServiceNow Guru.

]]>
Record producers are a great piece of ServiceNow functionality that allows for the creation of records in any table via the standard Service Catalog interface. This capability has been around for quite a while and odds are that you’re already using it in your system to allow end-users to create new incidents…among other things.

Over the years I’ve worked with ServiceNow, I’ve seen several requests to be able to report on or identify the record producer used to create a particular record. This would allow for easier identification of the entry point for record producer transactions. Unfortunately, ServiceNow doesn’t give us a simple way of accomplishing this. Even though there is a record producer ‘Script’ field and a ‘producer’ script object to work with, nothing is built to be able to dynamically identify the record producer used. This means that you’re stuck hard-coding values in a script or adding unnecessary variables to your record producer forms for every single record producer in your system. Read on for a fairly simple solution to this problem!

Record Producer Populated

This configuration can be accomplished in a few simple steps as shown below…

    1. Create a new field to store the value of the record producer used.

      We’ll want to store the record producer value on each target record that is created. As such, you’ll need a field to store that value in. I think the best solution is simply to create a new reference field referencing the ‘Record producer’ [sc_cat_item_producer] table named ‘Record producer’ [u_record_producer] on the ‘task’ table. That way, you can have one shared field that will be available to almost everything that you’ll usually use with record producers. If you’ve got additional tables that don’t extend ‘task’, just repeat the same step there as well.

 

    1. Create a new business rule on the ‘Record Producer [sc_cat_item_producer]’ table.

      The purpose of the business rule is to overcome the issue this article is about. We do this by leveraging the record producer ‘Script’ field to populate the ‘Record producer’ [u_record_producer] field created in the previous step. The business rule simply populates the record producer sys_id value into the record producer ‘Script’ field every time the record producer is inserted or updated and then the standard record producer script/creation process takes over and writes the producer Sys ID to the field per normal operations. If you need this to work for non-task tables, you can simply create a duplicate business rule there.

‘Force population of record producer used’ Business rule
Name: Force population of record producer used
Table: Record producer [sc_cat_item_producer] When: Before
Insert: True
Update: True
Advanced: True
Order: 1100
Condition: current.script.indexOf(‘Force population of record producer’) == -1
Script:

/***There is no dynamic way to record the record producer used so we can force it here
by modifying the script field entry on the record producer. Record producer will be
populated in a reference field on the target record named 'u_record_producer' (which
will need to be created).***/current.script = current.script + '\n\n\n' + '/***DO NOT REMOVE OR MODIFY THIS SECTION!!! Automatically added by "Force population of record producer used" business rule. \nForces population of this record producer sys_id into the target record for reporting purposes.***/\n' + 'current.u_record_producer = ' + '"' + current.sys_id + '";';

 

Please note that you will need to manually update every record producer in the system that you want this to work with in order for the producer script to be updated as necessary!

If you’ve done all of the above steps correctly, you should end up with a nicely-populated ‘Record producer’ reference field on each generated record. This value can then be used for reporting or other purposes in your system!

Record Producer Populated

The post Identify which ServiceNow Record Producer was used to create a record appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/reporting/identify-servicenow-record-producer-create-record/feed/ 22
Prevent Redundant Approval Requests in ServiceNow https://servicenowguru.com/business-rules-scripting/prevent-redundant-approval-requests-servicenow/ https://servicenowguru.com/business-rules-scripting/prevent-redundant-approval-requests-servicenow/#comments Tue, 17 Dec 2013 13:18:45 +0000 https://servicenowguru.wpengine.com/?p=5084 If you’re like many of the customers I’ve worked with, you may have dealt with the frustration of having excess or redundant approval requests come to you from ServiceNow. This happens very often simply because the same user may be responsible for various different tasks in the system. For example, on a change request, I

The post Prevent Redundant Approval Requests in ServiceNow appeared first on ServiceNow Guru.

]]>
If you’re like many of the customers I’ve worked with, you may have dealt with the frustration of having excess or redundant approval requests come to you from ServiceNow. This happens very often simply because the same user may be responsible for various different tasks in the system. For example, on a change request, I may be asked to approve as the ‘Requested by’ person’s manager, then again because I own one of the affected CIs, and then again because I’m a member of the Change Advisory Board! While this behavior may be desirable in certain situations, most of the time it’s completely redundant and annoying to end users. If I’ve already indicated my approval on a change as a manager, why should I be asked to approve again later? I’ve come up with what I think is a pretty effective solution to this problem that I’ll share here in this article.

Redundant Approvals

The Solution…

At least in my mind, in order for this solution to be successful, it needs to meet a few criteria…

  1. First and foremost, the user should not be notified of an approval request if they’ve already approved a record.
  2. We need to maintain the history of the approval record for audit purposes and accurately reflect what happened to the redundant approval requests. This means that deleting or aborting record insertion is out of the question!
  3. We cannot negatively impact the approval workflow by interrupting the normal approval process.

The first two criteria need to be met at the same time. Preventing the approval request could be done in a couple of different ways. One way would be to somehow manipulate the workflow activity to check if the user has previously approved. The drawback to this approach is that it requires hacking the workflow approval activities…which would be a significant upgrade risk, or adding custom code to every single approval activity in every single workflow…which would be a maintenance nightmare.

That leaves us with intercepting the creation/update of the approval records in a business rule. Using a ‘before’ insert/update business rule we can evaluate every ‘requested’ approval record, run a script to determine if the approval is for a user that has already approved this item, and then adjust the approval record by setting the approval state to ‘No Longer Required’…all before we trigger any update or notification to the approving user. We can also add some approval comments so that we can accurately reflect why the approval isn’t required anymore. Adding the following business rule to the ‘Approval [sysapproval_approver]’ table accomplishes that for us.

‘Duplicate Approval Requests Not Required’ Business Rule
Name: Duplicate Approval Requests Not Required
Table: Approval [sysapproval_approver] When: Before
Insert/Update: true
Condition: current.state.changesTo(‘requested’)
Script:

//Check to see if user has previously approved
approveDuplicateApproval();function approveDuplicateApproval(){
//Must have link to record being approved
if(current.document_id || current.sysapproval){
//Query for approval records for this user/record
var app = new GlideRecord('sysapproval_approver');
//Handle empty document_id and sysapproval fields
if(!current.document_id.nil()){
app.addQuery('document_id', current.document_id);
}
else if(!current.sysapproval.nil()){
app.addQuery('sysapproval', current.sysapproval);
}
app.addQuery('approver', current.approver);
app.addQuery('state', 'approved');
//Optionally restrict to current workflow
//app.addQuery('wf_activity.workflow_version', current.wf_activity.workflow_version);
app.query();
if(app.next()){
//If previous approval is found set this approval to 'approved'
current.state = 'not_required';
current.comments = "Approval marked by system as 'Not Longer Required' due to a previous approval on the same record by the same user.";
}
}
}

While the above script works great in manipulating the approval records on its own, it fails in the third criteria mentioned above…it can negatively impact the workflow in certain situations. This is because the workflow processing that happens after an approval status is changed isn’t seeing the true value of the approval request to process the workflow approval activity correctly. In my testing this couldn’t be done in a ‘before’ or ‘after’ business rule due to the timing of the updates. What is needed is to run the workflow checks one more time, and ensure that it happens after all of the above manipulation happens. The best way I could find to do this is through a separate ‘async’ business rule. The only downside to this async business rule is that it may not process immediately depending on the load on your system. Generally it should process within a few seconds though so for all practical intents and purposes it’s a non-issue.

‘Run parent workflows (Not Required)’ Business Rule
Name: Run parent workflows (Not Required)
Table: Approval [sysapproval_approver] When: async
Priority: 200 (This is important to be set to something greater than 100 to ensure that this runs ASAP!)
Insert/Update: true
Condition: current.state == ‘not_required’
Script:

// Run any workflows for our parent so they can check the approval states
runWorkflow_userApprove();function runWorkflow_userApprove() {
var id = current.sysapproval.nil() ? current.document_id : current.getValue('sysapproval');
var table = current.source_table.nil() ? 'task' : current.source_table;
if (id != null && table != null ) {
var gr = new GlideRecord(table);
if (gr.get(id)) {
new Workflow().runFlows(gr, 'update');
}
}
}

With the above solution in place, you should have created a very effective way to prevent the issue of redundant approval requests for the same user against the same record in ServiceNow.

The post Prevent Redundant Approval Requests in ServiceNow appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/business-rules-scripting/prevent-redundant-approval-requests-servicenow/feed/ 29
Show a Task Workflow Timeline https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/ https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/#comments Wed, 16 May 2012 11:04:29 +0000 https://servicenowguru.wpengine.com/?p=4420 Having a blast from Knowledge 12 this week! It’s been fun this year being able to relax a little bit more and take some more time to talk with people. I look forward to meeting more of you over the next couple of days. Today, I’m writing in response to a user on the ServiceNow

The post Show a Task Workflow Timeline appeared first on ServiceNow Guru.

]]>
Having a blast from Knowledge 12 this week! It’s been fun this year being able to relax a little bit more and take some more time to talk with people. I look forward to meeting more of you over the next couple of days.

Today, I’m writing in response to a user on the ServiceNow community, and a few users in the advanced admin course I was observing earlier in the week. In the advanced admin class, they show how you can click a UI action on the change form to show a workflow in progress. They also show you how you can view a timeline for a workflow context. These UI actions (and corresponding popups) can provide valuable information to both administrators and technicians to determine the status and process of a particular workflow. The only problem (in the case of the timeline) is that it can’t be accessed from the change directly. You have to navigate to the workflow context record first.

In this post I’ll show you how to create a UI action script to display a workflow timeline popup directly from any task form in the system.

Change Request Timeline

If you’re familiar with the default UI action in the system, the code below should look familiar. It is initiated from the client, gets the sys_id of the workflow context, constructs a URL to the timeline, and then pops a new window up showing the timeline. The real trick in this case is getting the correct sys_id from the workflow context record. You should be able to create the following as a UI action on your task table. It will display for any itil user on a task that has an associated workflow.

‘Show Workflow Timeline’ UI Action
Name: Show Workflow Timeline
Table: Task
Order: 200
Show Insert: False
Client: True
OnClick: showTimeline();
Form link: True
Condition: !current.isNewRecord() && (new Workflow().hasWorkflow(current)) && gs.hasRole(‘itil’)
Script:

function showTimeline() {
var wf = new GlideRecord('wf_context');
wf.addQuery('id', g_form.getUniqueValue());
wf.query();
if(wf.next()){
var url = new GlideURL('show_schedule_page.do');
url.addParam('sysparm_stack', 'no');
url.addParam('sysparm_page_schedule_type', 'workflow_context');
url.addParam('sysparm_timeline_history', wf.sys_id);
var w = getTopWindow();
w.popupOpenFocus(url.getURL(), 'show_workflow_timeline', 950, 700, '', false, false);
}
}

The post Show a Task Workflow Timeline appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/show-task-workflow-timeline/feed/ 4
Exporting Service Catalog Items in One Step https://servicenowguru.com/system-definition/exporting-service-catalog-items-step/ https://servicenowguru.com/system-definition/exporting-service-catalog-items-step/#comments Thu, 26 Jan 2012 17:54:23 +0000 https://servicenowguru.wpengine.com/?p=4277 This post comes in response to a request I received from some of my colleagues at ServiceNow to be able to export a catalog item definition to XML and transport it between instances. I’ve written before about how you can quckly export and import data between ServiceNow instances using the XML export/import context menus. While

The post Exporting Service Catalog Items in One Step appeared first on ServiceNow Guru.

]]>
This post comes in response to a request I received from some of my colleagues at ServiceNow to be able to export a catalog item definition to XML and transport it between instances. I’ve written before about how you can quckly export and import data between ServiceNow instances using the XML export/import context menus. While this works great for a lot of situations, it doesn’t work so great for data that resides in multiple tables, but really makes sense to be exported as a single unit. The components that make up a Catalog item definition are actually stored in over 21 separate tables! It is possible to export a catalog item but you have to do at least 21 separate exports to do it. In this post, I’ll show you how you can set up a UI action to export information from all 21+ tables that make up a catalog item definition…in one click!

Export Full Catalog Item

21+ tables worth of information…in ONE click!

The catalog item export will work for any table extending the ‘sc_cat_item’ table…catalog items, record producers, content items, and order guides! It DOES NOT export associated workflows, delivery plans, or wizard definitions. Workflows can be exported by following the instructions in the Graphical Workflow Export article. The following table information is included.

  • Variables (including question choices)
  • Variable sets (including associated variables, client scripts, and UI policies
  • Client scripts
  • UI policies
  • Additional categories
  • Approved by user and group
  • Available for/Not Available for lists
  • Order guide rule base

The first step is to set up a ‘Processor’ record to handle the export. ServiceNow actually has some built-in code to handle exports like this. You just have to know how to leverage it. Here’s how you would set up a processor for the catalog item export.

‘ExportCatalogItem’ Processor
Name: ExportCatalogItem
Type: Script
Path: export_catalog_item
Script:

(function process(g_request, g_response, g_processor) {
var sysid = g_request.getParameter('sysparm_sys_id');
gs.log('** Exporting Catalog Item ' + sysid);//Name all the related lists
var exporter = new ExportWithRelatedLists('sc_cat_item', sysid);
exporter.addRelatedList('item_option_new', 'cat_item');
exporter.addRelatedList('catalog_script_client', 'cat_item');
exporter.addRelatedList('catalog_ui_policy', 'catalog_item');
exporter.addRelatedList('sc_cat_item_category', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_catalog', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_user_criteria_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_user_criteria_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_group_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_group_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_company_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_company_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_dept_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_dept_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_location_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_location_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_user_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_user_no_mtom', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_app_group', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_app_user', 'sc_cat_item');
exporter.addRelatedList('sc_cat_item_guide_items', 'guide');
exporter.addRelatedList('pc_vendor_cat_item', 'product_catalog_item');

var catalogID = '';
var categoryID = '';
var vsrelID = '';
var vsID = '';
var vID = '';
var qcID = '';
var uipID = '';
var actID = '';
var csID = '';

//Query for Catalogs
var catalog = new GlideRecord('sc_cat_item_catalog');
catalog.addQuery('sc_cat_item', sysid);
catalog.query();
while(catalog.next()){
//Get Catalog IDs
catalogID = catalogID + ',' + catalog.sc_catalog.sys_id.toString();
}

//Query for Categories
var category = new GlideRecord('sc_cat_item_category');
category.addQuery('sc_cat_item', sysid);
category.query();
while(category.next()){
//Get Category IDs
categoryID = categoryID + ',' + category.sc_category.sys_id.toString();
}

//Query for variables to get question choices
var item = new GlideRecord('item_option_new');
item.addQuery('cat_item', sysid);
item.query();
while(item.next()){
//Query for question choices
var qc = new GlideRecord('question_choice');
qc.addQuery('question', item.sys_id.toString());
qc.query();
while(qc.next()){
//Add the variable question sys_id to the variable question string
qcID = qcID + ',' + qc.sys_id.toString();
}
}

//Query for ui catalog ui policies to get policy actions
var catpol = new GlideRecord('catalog_ui_policy');
catpol.addQuery('catalog_item', sysid);
catpol.query();
while(catpol.next()){
//Query for ui policy actions
var uipact = new GlideRecord('catalog_ui_policy_action');
uipact.addQuery('ui_policy', catpol.sys_id.toString());
uipact.query();
while(uipact.next()){
//Add the ui policy action sys_id to the ui policy action string
actID = actID + ',' + uipact.sys_id.toString();
}
}

//Query for variable set relationships
var vsrel = new GlideRecord('io_set_item');
vsrel.addQuery('sc_cat_item', sysid);
vsrel.query();
while(vsrel.next()){
//Add the item set relationship sys_id to the item set string
vsrelID = vsrelID + ',' + vsrel.sys_id.toString();
//Get the variable set
var vs = vsrel.variable_set.getRefRecord();
if(vs){
//Add the variable set sys_id to the variable set string
vsID = vsID + ',' + vs.sys_id.toString();
//Query for variables in the set
var v = new GlideRecord('item_option_new');
v.addQuery('variable_set', vs.sys_id);
v.query();
while(v.next()){
//Add the variable sys_id to the variable string
vID = vID + ',' + v.sys_id.toString();
//Query for variable question choices
var vqc = new GlideRecord('question_choice');
vqc.addQuery('question', v.sys_id.toString());
vqc.query();
while(vqc.next()){
//Add the variable question sys_id to the variable question string
qcID = qcID + ',' + vqc.sys_id.toString();
}
}

//Query for ui policies in the set
var uip = new GlideRecord('catalog_ui_policy');
uip.addQuery('variable_set', vs.sys_id.toString());
uip.query();
while(uip.next()){
//Add the ui policy sys_id to the ui policy string
uipID = uipID + ',' + uip.sys_id.toString();
//Query for ui policy actions
var uipa = new GlideRecord('catalog_ui_policy_action');
uipa.addQuery('ui_policy', uip.sys_id.toString());
uipa.query();
while(uipa.next()){
//Add the ui policy action sys_id to the ui policy action string
actID = actID + ',' + uipa.sys_id.toString();
}
}

//Query for client scripts in the set
var cs = new GlideRecord('catalog_script_client');
cs.addQuery('variable_set', vs.sys_id.toString());
cs.query();
while(cs.next()){
//Add the client script sys_id to the client script string
csID = csID + ',' + cs.sys_id.toString();
}
}
}

exporter.addQuerySet('sc_catalog', 'sys_idIN' + catalogID);
exporter.addQuerySet('sc_category', 'sys_idIN' + categoryID);
exporter.addQuerySet('io_set_item', 'sys_idIN' + vsrelID);
exporter.addQuerySet('item_option_new_set', 'sys_idIN' + vsID);
exporter.addQuerySet('item_option_new', 'sys_idIN' + vID);
exporter.addQuerySet('question_choice', 'sys_idIN' + qcID);
exporter.addQuerySet('catalog_ui_policy', 'sys_idIN' + uipID);
exporter.addQuerySet('catalog_ui_policy_action', 'sys_idIN' + actID);
exporter.addQuerySet('catalog_script_client', 'sys_idIN' + csID);
exporter.exportRecords(g_response);
})(g_request, g_response, g_processor);

Once you have your processor set up, you just need to call it. The processor above is called by its path name ‘export_catalog_item’ followed by ‘.do’. It also needs to know what to export so you need to pass it the sys_id of the top-level record that you want to export…in this case, the sys_id of the ‘Catalog item’ record.

‘Export Catalog Item’ UI Action
Name: Export Catalog Item
Table: Catalog Item (sc_cat_item)
Order: 200
Form link: True
Show insert: False
Show update: True
Client True
Hint: Export catalog item definition to .xml file
Onclick callExportCatalogItem();
Condition: gs.hasRole(“admin”)
Script:

function callExportCatalogItem() {
var url = new GlideURL('export_catalog_item.do');
url.addParam('sysparm_sys_id', gel("sys_uniqueValue").value);
var frame = top.gsft_main;
if (!frame){
frame = top;
}frame.location = url.getURL();
}

Once you’re done with this, you should have an ‘Export Catalog Item’ UI action context menu item on your ‘Catalog Item’ forms that you can use to transport catalog items, record producers, and order guides in the event that they don’t get captured in an update set.

The post Exporting Service Catalog Items in One Step appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/exporting-service-catalog-items-step/feed/ 44
Control the Execution Order of Request Items in an Order Guide https://servicenowguru.com/system-definition/order-request-items-order-guide/ https://servicenowguru.com/system-definition/order-request-items-order-guide/#comments Tue, 23 Aug 2011 12:43:18 +0000 https://servicenowguru.wpengine.com/?p=3952 Lately 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

The post Control the Execution Order of Request Items in an Order Guide appeared first on ServiceNow Guru.

]]>
Lately 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();
}
}
}

The post Control the Execution Order of Request Items in an Order Guide appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/order-request-items-order-guide/feed/ 15
Hide Empty Variables on a Standard Form https://servicenowguru.com/client-scripts-scripting/hide-empty-variables-standard-form/ https://servicenowguru.com/client-scripts-scripting/hide-empty-variables-standard-form/#comments Thu, 16 Jun 2011 16:31:17 +0000 https://servicenowguru.wpengine.com/?p=3826 Service catalog variables can be a challenge to deal with on standard forms when they are displayed in a variable editor. I’ve written before about different ways that you can solve one of these challenges…making the variables read only, so that they can’t be modified after the initial submission through the service catalog interface. Another

The post Hide Empty Variables on a Standard Form appeared first on ServiceNow Guru.

]]>
Service catalog variables can be a challenge to deal with on standard forms when they are displayed in a variable editor. I’ve written before about different ways that you can solve one of these challenges…making the variables read only, so that they can’t be modified after the initial submission through the service catalog interface. Another common problem I’ve seen is that you can end up with a lot of variables that end up empty in the variable editor on your request item or task because they were optional or hidden on the front-end catalog form. If the variables are empty and you aren’t going to have users interact with them on the standard forms then there isn’t much use in having these variables show up at all in the variable editor.

Until now there really hasn’t been a good way to deal with this issue because of the challenges of dealing with so many different variable types in client-side JavaScript. A couple of days ago one of my colleagues, Jacob Kimball, suggested to me that we might be able to overcome this issue by using a ‘display’ business rule to collect the blank variable information at the server and then pass those variable names to the client. So, you can thank Jacob Kimball for the brilliance of this solution. I’m just spreading the love. :)

As explained above, the key to making this work is a ‘display’ business rule. The business rule runs before the display of any record in the table (tasks in this case) and queries the ‘sc_item_option_mtom’ and ‘question_answer’ tables to collect any variable names for empty variables. Then it passes this information in the ‘g_scratchpad’ object to the client to hide the variables on the form.

Here is how you could set up the business rule. The script is designed to hide any empty variables for any task records whether they are generated from a record producer or as a catalog item.

‘Hide Empty Variables’ Business Rule
Name: Hide Empty Variables
Table: Task
When: display
Condition: !RP.isPopup()
Script:

//Initialize the scratchpad variable
g_scratchpad.emptyVars = '';

//Check to see if a variable pool exists
var count = 0;
for(vars in current.variable_pool){
   count++;
   break;
}

//If a variable pool exists then collect empty variable names
if(count > 0){
   var emptyVars = [];
   var table = current.getTableName();
   //Query for the empty variables for this record
   //Catalog item and task variables pull from 'sc_item_option_mtom' table
   if(table == 'sc_req_item' || table == 'sc_task'){
      var itemVars = new GlideRecord('sc_item_option_mtom');
      if(table == 'sc_req_item'){
         itemVars.addQuery('request_item', current.sys_id);
      }
      if(table == 'sc_task'){
         itemVars.addQuery('request_item', current.request_item.sys_id);
      }
      itemVars.addNullQuery('sc_item_option.value');
      //Exclude Label and Container variables
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 11);
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 19);
      itemVars.addQuery('sc_item_option.item_option_new.type', '!=', 20);
      itemVars.query();
      while(itemVars.next()){
         //Add variable names to the emptyVars array
         emptyVars.push(itemVars.sc_item_option.item_option_new.name.toString());
      }
   }
   else{
      //All other variables pulled from 'question_answer' table
      var producerVars = new GlideRecord('question_answer');
      producerVars.addQuery('table_sys_id', current.sys_id);
      producerVars.addNullQuery('value');
      //Exclude Label and Container variables
      producerVars.addQuery('question.type', '!=', 11);
      producerVars.addQuery('question.type', '!=', 19);
      producerVars.addQuery('question.type', '!=', 20);
      producerVars.query();
      while(producerVars.next()){
         //Add variable names to the emptyVars array
         emptyVars.push(producerVars.question.name.toString());
      }
   }

   //Store the result in the scratchpad
   g_scratchpad.emptyVars = emptyVars.join();
}

Once you’ve got the empty variable names collected all you have to do is set up a client script to grab the ‘g_scratchpad’ variable, split out any empty variable names, and hide each one. The client script is pretty simple since the heavy lifting is being done in the business rule. Just make sure that you check the ‘Inherited’ checkbox if you decide to set this up on the task table!

‘Hide Empty Variables’ Client Script
Name: Hide Empty Variables
Type: OnLoad
Table: Task
Inherited: True
Script:

function onLoad() {
   //Hide all empty variables using the scratchpad object passed from 'Hide Empty Variables' business rule
   if(g_scratchpad.emptyVars != ''){
      var emptyVars = g_scratchpad.emptyVars.split(',');
      for(i = 0; i < emptyVars.length; i++){
         g_form.setDisplay('variables.' + emptyVars[i], false);
      }
   }
}

The post Hide Empty Variables on a Standard Form appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/client-scripts-scripting/hide-empty-variables-standard-form/feed/ 75
Populate Order Guide on Request Ticket https://servicenowguru.com/system-definition/populate-order-guide-request-ticket/ https://servicenowguru.com/system-definition/populate-order-guide-request-ticket/#comments Thu, 24 Feb 2011 15:25:46 +0000 https://servicenowguru.wpengine.com/?p=3396 UPDATE: As of the Helsinki ServiceNow release, this is tracked for you automatically in a new ‘Order Guide’ field on the ‘Requested Item’ table! This solution should be discontinued in Helsinki releases and beyond. Order guides are a service catalog concept that allow you to set up an initial form to ask the user certain

The post Populate Order Guide on Request Ticket appeared first on ServiceNow Guru.

]]>
UPDATE: As of the Helsinki ServiceNow release, this is tracked for you automatically in a new ‘Order Guide’ field on the ‘Requested Item’ table! This solution should be discontinued in Helsinki releases and beyond.

Order guides are a service catalog concept that allow you to set up an initial form to ask the user certain questions in order to determine a collection of catalog items they need to order. The classic use case for an order guide is the ‘New Employee Hire’ item that ServiceNow provides in the out-of-box demo data. While order guides are really a front-end routing concept, it can sometimes be useful to report on requests that were generated for a particular order guide. This functionality doesn’t exist out-of-box in ServiceNow, but it is very easy to add. Here’s a good tip that I recently learned from Sean Grison and Valor Poland about how to populate the order guide used to generate a particular request.

While this solution gets you as close as possible to populating the correct order guide used to generate a request, you may still notice some false positives due to system behavior we can’t control. Any time people click on an order guide item in the catalog (even if they don’t end up completing the order guide), the order guide is populated on the cart and will be populated on the next request. Another issue is that people can work through an order guide and then delete certain contents of the request on the confirmation screen, and then go back to the catalog and add more items unrelated to the order guide. Unfortunately, there’s not any way to guarantee that the order guide will be populated correctly 100% of the time because of these factors.

The script below mitigates some of these issues by checking to make sure that at least one of the items from the order guide rule base is included in the order if we are populating the Order guide field on the request. It also does a second check to verify that any order guide rule base entry with NO condition (meaning it always ends up being added to the order guide) MUST be included in the order.

Even with these additional checks in place, the system behavior might still result in requests where somebody clicked on an order guide, then ordered one of the items in the guide as a standalone item instead. The best way to guard against this is to make sure you have at least one item with no conditions in the rule base, ensuring that it will always have to be part of the order if we’re going to populate an order guide.

Only three steps are necessary to record the order guide used to generate a request…

  1. Create a new reference field called ‘Order guide’ on the ‘Request (sc_request)’ table. The field needs to reference the ‘Order guide (sc_cat_item_guide)’ table. You may also choose to secure write access to this field using an ACL since it really shouldn’t need to be changed by any user.
  2. Create a new business rule on the ‘Request (sc_request)’ table with the following settings…
    ‘Populate Order Guide’ Business Rule
    Name: Populate Order Guide
    When: Before
    Insert: True
    Script:

    var c = new GlideRecord('sc_cart');
    c.get('user', gs.getUserID());
    if(c.current_guide){
       var isOrderGuide = true;
       var foundItemCount = 0;
       //Query the order guide rule base
       var og = new GlideRecord('sc_cat_item_guide_items');
       og.addQuery('guide', c.current_guide);
       og.query();
       while(og.next()){
          var mustHave = false;
          var foundItem = false;
          //If the condition is empty then item must be ordered
          if(og.condition.nil()){
             mustHave = true;
          }
          //Check to see if the rule matches at least one item in the cart
          var itm = new GlideRecord('sc_cart_item');
          itm.addQuery('cart', c.sys_id);
          itm.addQuery('cat_item', og.item.sys_id.toString());
          itm.query();
          if(itm.hasNext()){
             foundItem = true;
             foundItemCount++;
          } 
          if(mustHave && !foundItem){
             //Do not update order guide
             isOrderGuide = false;
             break;
          }
       }
       if(isOrderGuide && foundItemCount > 0){
          //If actual order guide items are included populate the order guide field
          current.u_order_guide = c.current_guide;
       }
    }
    
  3. Set up a ‘Write’ ACL on your new ‘Order guide’ field to restrict access to the field. This field should only be modified by the system as part of the ordering process so you should set up an ACL to limit those permissions. The simplest way to do this is to set up a write ACL for ‘sc_request.u_order_guide’ with the ‘nobody’ role and un-check the ‘Admin override’ checkbox.

Now when users order an item using a record producer, the record producer will be referenced in the ‘Order guide’ field you created on the request table!

Knowing the order guide used to generate a request allows you to do all sorts of cool things including…

  • Reporting against the request table to see how often each order guide is used
  • Controlling the execution order of requested items within an order guide
  • Using the ‘Order guide’ field value as a key to separate workflow logic for an item that can be ordered as a standalone item or as part of an order guide

Request Order Guide

The post Populate Order Guide on Request Ticket appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/populate-order-guide-request-ticket/feed/ 35
Make Checkbox Variables Mandatory https://servicenowguru.com/client-scripts-scripting/checkbox-variables-mandatory/ https://servicenowguru.com/client-scripts-scripting/checkbox-variables-mandatory/#comments Tue, 25 Jan 2011 13:54:07 +0000 https://servicenowguru.wpengine.com/?p=3337 Mandatory fields are usually pretty simple to work with. ServiceNow provides simple UI policy and client script methods to make fields and variables mandatory. You may have noticed as you have worked with checkbox variables in the service catalog that these methods don’t apply. The reason for this makes perfect sense if you think about

The post Make Checkbox Variables Mandatory appeared first on ServiceNow Guru.

]]>
Mandatory fields are usually pretty simple to work with. ServiceNow provides simple UI policy and client script methods to make fields and variables mandatory. You may have noticed as you have worked with checkbox variables in the service catalog that these methods don’t apply. The reason for this makes perfect sense if you think about it. A checkbox has only two possible values…true or false. When the checkbox variable loads it is already set with a value of false (unchecked). Because of this, there’s never a situation where a checkbox variable wouldn’t satisfy a mandatory check. It will ALWAYS have a value!
What people usually want in these scenarios is to require a user to select a minimum number of options from a certain group of checkbox variables. In these scenarios, this minimum number of items checked really represents the standard for a mandatory check for that group of checkboxes. There’s not a simple way to handle these situations, but I’ve set up some client script solutions that allow you to perform this type of validation if it is needed.


Mandatory Checkboxes

This onLoad script will place a red mandatory indicator next to the label for a set of checkbox variables. Just paste the script into an ‘onLoad’ catalog client script and set the ‘mandatoryLabelName’ variable below with the Name value of the label variable for your group of checkbox variables. NOTE: This script requires an associated ‘Label’ variable to work with your checkbox variables and will not work in Service Portal. For Service Portal you should simply add a form info message as shown in the script below. See this post for details on how to set up label variables with checkboxes.

‘Mandatory checkbox label indicator’ catalog client script
Name: Mandatory checkbox label indicator
Type: onLoad
Applies to: A Variable Set OR A Catalog Item
Script:

function onLoad(){
    try{
        mandatoryLabelName = 'checkbox_variables';
        $('status.' + g_form.getControl(mandatoryLabelName).id).show();
    }catch(e){}
}

This onSubmit script will check a set of checkbox variables to make sure at least some of them are checked. All you have to do is paste the script into an ‘onSubmit’ catalog client script and set the ‘mandatoryVars’ and ‘mandatoryCount’ variable values below with the checkbox variables the script should apply to and the minimum number of checked boxes.

‘Mandatory checkboxes’ catalog client script
Name: Mandatory checkboxes
Type: onSubmit
Applies to: A Variable Set OR A Catalog Item
Script:

function onSubmit() {
    //Set the mandatory checkbox variable names and total mandatory count here
    var mandatoryVars = 'option1,option2,option3,option4';
    var mandatoryCount = 2;
    
    var passed = forceMandatoryCheckboxes(mandatoryVars, mandatoryCount);
    if (!passed) {
        //Abort the submit
        var message = 'You must select at least ' + mandatoryCount + ' options.';
        g_form.addErrorMessage(message);
        return false;
    }
}

function forceMandatoryCheckboxes(mandatory, count) {
    //Split the mandatory variable names into an array
    mandatory = mandatory.split(',');
    var answer = false;
    var varFound = false;
    var numTrue = 0;
    //Check each variable in the array
    for (var x = 0; x < mandatory.length; x++) {
        //Check to see if variable exists
        if (g_form.hasField(mandatory[x])) {
            varFound = true;
            //Check to see if variable is set to 'true'
            if (g_form.getValue(mandatory[x]) == 'true') {
                numTrue ++;
                //Exit the loop if we have reached required number of 'true'
                if (numTrue >= count) {
                    answer = true;
                    break;
                }
            }
        }
    }
    //If we didn't find any of the variables allow the submit
    if (varFound == false) {
        answer = true;
    }
    //Return true or false
    return answer;
}

The post Make Checkbox Variables Mandatory appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/client-scripts-scripting/checkbox-variables-mandatory/feed/ 73
Field Styles for Service Catalog Variables https://servicenowguru.com/system-ui/field-styles-service-catalog-variables/ https://servicenowguru.com/system-ui/field-styles-service-catalog-variables/#comments Fri, 03 Dec 2010 14:45:17 +0000 https://servicenowguru.wpengine.com/?p=3012 ServiceNow allows you to modify the CSS style of any field by adding a personalized style. Instructions for performing this customization are outlined on the ServiceNow wiki. There isn’t a built-in way to do this same thing with the fields (variables) in the Service Catalog. Applying styles to service catalog variables is possible however through

The post Field Styles for Service Catalog Variables appeared first on ServiceNow Guru.

]]>
ServiceNow allows you to modify the CSS style of any field by adding a personalized style. Instructions for performing this customization are outlined on the ServiceNow wiki. There isn’t a built-in way to do this same thing with the fields (variables) in the Service Catalog. Applying styles to service catalog variables is possible however through the use of catalog client scripts. This article shows you how.


This customization really boils down to getting the correct input element on the form and applying the correct CSS style. Because this all needs to be done in javascript, the regular CSS rules you’re used to need to be modified a bit. For example, setting a background color on a field needs to be done with ‘backgroundColor’ instead of ‘background-color’. Hyphens are replaced by a camel-case convention for CSS styles.

To get the form element you can simply use ‘g_form.getControl(VARIABLE_NAME)’. Then you simply apply the correct CSS style like this…

//Set the width of a field
g_form.getControl('').style.width = '150px';

Here are some common styles I’ve seen used in the past…

g_form.getControl('').style.width = '150px'; //Set the width of a field
g_form.getControl('').style.backgroundColor = 'LimeGreen'; //Set the background color of a field
g_form.getControl('').style.color = 'blue'; //Set the text color of a field
g_form.getControl('').style.fontStyle = 'italic'; //Set the text font to italic
g_form.getControl('').style.fontWeight = 'bold'; //Set the text font to bold

Reference fields: A special case

One thing to watch out for is reference fields. The ‘control’ element is actually hidden for all reference fields so using the script above on a reference field will set a style, but that style will be set on an element you’ll never see. For reference fields you need to get the ‘sys_display’ input element. Here’s a sample script that shows how you could do this…

var myVar = $('sys_display.' + g_form.getControl('').id); //Get the correct reference element
myVar.style.width = '350px'; //Set the width

Putting it all together

The result in the image above was produced by the following catalog client script…

function onLoad() {
//Set styles for the 'caller_id' variable
var myVar = $('sys_display.' + g_form.getControl('caller_id').id);
myVar.style.width = '350px';
myVar.style.backgroundColor = 'LimeGreen';
myVar.style.color = 'blue';
myVar.style.fontStyle = 'italic';

//Set styles for the 'impact' variable
var myVar2 = g_form.getControl('impact');
myVar2.style.width = '200px';
myVar2.style.backgroundColor = 'yellow';
myVar2.style.color = 'purple';
myVar2.style.fontWeight = 'bold';
}

The post Field Styles for Service Catalog Variables appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-ui/field-styles-service-catalog-variables/feed/ 43