Generating Service Catalog Requests Programmatically - ben-vargas/servicenow-wiki GitHub Wiki
This article outlines several methods for programmatically generating Service Catalog requests in ServiceNow. While Related Lists are often sufficient for creating simple record relationships, there are situations where you need to generate Requests, Requested Items, and Catalog Tasks using Inbound Actions, Business Rules, or other server-side scripts.
Creating a new Incident is straightforward with a single GlideRecord insert. However, Service Catalog requests involve multiple records (Request, Requested Item, and potentially Catalog Tasks), making the process more complex when generated through code. This article provides examples and best practices for these scenarios.
Here are the commonly used methods:
This method creates a Request record from an existing record (e.g., an Incident) using a UI Action. It redirects the user to the Service Catalog homepage, pre-populating the parent field on the new Request.
UI Action Configuration:
-
Name: Create Request
-
Table:
<your_table>
(e.g.,incident
) -
Form context menu:
true
-
Condition:
<your_condition_here>
(e.g.,state=='3'
) -
Script:
// Update saves the record before going to the catalog homepage current.update(); gs.addInfoMessage('You will need to navigate back to record ' + current.number + ' upon request completion. www.servicenowelite.com'); var url = "catalog_home.do?sysparm_view=catalog_default&sysparm_processing_hint=setfield:request.parent="; url += current.sys_id; action.setRedirectURL(url);
Explanation:
-
current.update()
saves the changes on the originating record before redirecting. -
gs.addInfoMessage()
provides a message to the user about returning to the original record. - A URL is constructed that takes the user to the service catalog homepage. This url sets the
parent
field of the request with the sys_id of the original record (e.g. Incident). -
action.setRedirectURL()
redirects the user to the constructed catalog homepage URL.
Use Case: This method is suitable when you want to allow a user to initiate a Service Catalog request directly from an existing record.
This method uses an Inbound Action to create a Requested Item based on an incoming email, using the Cart
API.
Inbound Action Configuration:
-
Name: Create Requested Item
-
Table:
sc_req_item
-
Condition:
<your condition here>
(e.g.,email.subject.indexOf('Request') > -1
) -
Script:
createRequest(); function createRequest() { var cart = new Cart(); // Add in cart, substitute your cat item sys_id var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with your catalog item sys_id // Set requested for, substitute your requested for // Set Variables in your Cart Item cart.setVariable(item, 'requested_for', 'USER_SYS_ID'); // Replace with your requested for user sys_id cart.setVariable(item, 'request_short_description', email.subject.toString()); cart.setVariable(item, 'request_description', email.body_html); cart.setVariable(item, 'request_type', 'others'); var cartmsg = "received from: " + email.origemail + "\n\n" + email.body_text; cart.setVariable(item, 'comments', cartmsg); var rc = cart.placeOrder(); }
Explanation:
-
var cart = new Cart();
creates a newCart
object for placing the order. -
cart.addItem('CATALOG_ITEM_SYS_ID')
adds the specified catalog item to the cart (replace with a valid sys_id). -
cart.setVariable()
sets the variables for the item (replace with appropriate values). -
cart.placeOrder()
places the order.
Use Case: This method is suitable when you want to create a request from an email or other incoming data. It leverages the cart API which provides proper record linkage and workflow execution.
This method creates a Request and Requested Item directly in an Inbound Action, bypassing the Cart API. This method is not recommended, as it requires manually linking records and triggering workflows. This method is here for comparison purposes only.
Inbound Action Configuration:
-
Name: Create Requested Item
-
Table:
sc_req_item
-
Condition:
<your condition here>
(e.g.,email.subject.indexOf('Request') > -1
) -
Script:
createRequest(); function createRequest() { // Create Request var grRequest = new GlideRecord("sc_request"); grRequest.initialize(); // Substitute your requested for grRequest.requested_for = 'USER_SYS_ID'; // Replace with the requested for user sys_id grRequest.short_description = email.subject.toString(); grRequest.description = "received from: " + email.origemail + "\n\n" + email.body_text; var requestSysId = grRequest.insert(); // Create Request Item, substitute your requested for current.requested_for = 'USER_SYS_ID'; // Replace with the requested for user sys_id current.short_description = email.subject.toString(); current.description = "received from: " + email.origemail + "\n\n" + email.body_text; // substitute your cat item current.cat_item = 'CATALOG_ITEM_SYS_ID'; // Replace with your catalog item sys_id current.parent = requestSysId; current.request = requestSysId; current.insert(); // Workflow Trigger // More information http://wiki.servicenow.com/index.php?title=Workflow_Script var w = new Workflow(); wfSysId = w.getWorkflowFromName("PUT_YOUR_WORKFLOW_NAME_HERE"); // Replace with your workflow name w.startFlow(wfSysId, current, current.operation()); }
Explanation:
- Creates a Request record directly using
GlideRecord
. - Creates the Requested Item record directly using
GlideRecord
. - Manually sets parent and request fields to link records.
- Uses the Workflow API to start the associated workflow.
Use Case: This method is more complex and less maintainable, as it requires manually managing record linkages and workflows. It is generally better to use the Cart API (Example 2) if possible.
This method uses a Business Rule to create a Requested Item based on some conditions.
Business Rule Configuration:
-
When:
after
-
Insert/Update/Delete:
true
-
Condition:
<your_condition_here>
(e.g.,current.assigned_to.changes()
) -
Script:
createRequest(); function createRequest() { // Create Request var cart = new Cart(); // substitute your cat item var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with your catalog item sys_id // Set Variables in your Cart Item // substitute your requested for cart.setVariable(item, 'requested_for', 'USER_SYS_ID'); // Replace with your requested for user sys_id cart.setVariable(item, 'request_short_description', 'Created from Business Rule'); cart.setVariable(item, 'request_description', 'Created from Business Rule'); cart.setVariable(item, 'request_type', 'others'); var rc = cart.placeOrder(); gs.addInfoMessage('Request Item Created: ' + rc.number); }
Explanation:
- Uses the
Cart
API to create and place the request. -
cart.setVariable()
sets variables in the requested item. - This method demonstrates creating an RITM based on a different business event.
Use Case: This method is useful when you need to automatically create a Service Catalog request based on a change or specific condition on a different table.
This method uses a transform script to create a requested item while processing data from an import set.
Transform Map Configuration:
-
When:
onBefore
-
Script:
var cart = new Cart(); // add in cart, substitute your cat item sys_id var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with your catalog item sys_id //Set Variables in your Cart Item var cartmsg = "Import Set: " + source.sys_import_set.table_name + ', Datasource:' + source.sys_import_set.data_source; cart.setVariable(item, 'comments', cartmsg); var rc = cart.placeOrder();
Explanation:
- Uses the
Cart
API to create and place the request. -
cart.setVariable()
sets variables in the requested item. - The source import set and data source are added to the comments field of the RITM.
Use Case: This is useful when loading data from an external source, you also want to create a request.
This method shows how to set variables in the cart by passing in a JSON object which is parsed and then added using setVariable
.
-
Script (modifying Example 2 and 4):
function createRequestFromJSON(variableJSON) { var cart = new Cart(); var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with actual sys_id var variables = JSON.parse(variableJSON); for (var variable in variables) { cart.setVariable(item, variable, variables[variable]); } var rc = cart.placeOrder(); return rc; } var jsonString = '{"requested_for": "USER_SYS_ID", "short_description": "JSON Example", "comments": "Data From JSON"}'; var request = createRequestFromJSON(jsonString); gs.info('Request Created: ' + request.number);
-
Explanation:
- This example receives a json string, parses it, and iterates over the object and populates the variables in the cart using
cart.setVariable()
.
- This example receives a json string, parses it, and iterates over the object and populates the variables in the cart using
- Use Case: This is useful when dealing with integrations where the catalog item data might come as a JSON payload. It improves the maintainability of the code, as it does not rely on hard coding the variable names.
-
Explanation:
This method iterates through an array of cat item sys ids and adds them all to a single request using the cart API.
-
Script (modifying Example 4):
function createMultipleItems(catItemSysIds, requestedFor) { var cart = new Cart(); var reqItems = []; for (var i = 0; i < catItemSysIds.length; i++) { var item = cart.addItem(catItemSysIds[i]); //add item to cart cart.setVariable(item, 'requested_for', requestedFor); //set the requested for field reqItems.push(item); } var rc = cart.placeOrder(); return rc; } var itemsToAdd = ['CATALOG_ITEM_SYS_ID_1', 'CATALOG_ITEM_SYS_ID_2']; var createdRequest = createMultipleItems(itemsToAdd, 'USER_SYS_ID'); gs.info("Created request number " + createdRequest.number);
-
Explanation:
- Iterates through an array of catalog item sys_ids, adding each item to the cart and setting the requested for user.
- Use Case: This is useful when you need to create multiple items in a single request based on some sort of trigger event.
-
Explanation:
This method abstracts out the cart logic into a Script Include for reusability.
-
Script (Script Include -
CartHelper
):var CartHelper = Class.create(); CartHelper.prototype = { initialize: function() { }, placeOrderWithVariables: function(catItemSysId, variables) { var cart = new Cart(); var item = cart.addItem(catItemSysId); for (var variable in variables) { cart.setVariable(item, variable, variables[variable]); } var rc = cart.placeOrder(); return rc; }, type: 'CartHelper' };
-
Business Rule or Inbound Action using Script Include
var cartHelper = new CartHelper(); var cartVariables = { 'requested_for': 'USER_SYS_ID', 'short_description': 'Created with Helper Class', 'comments': 'Testing' }; var order = cartHelper.placeOrderWithVariables('CATALOG_ITEM_SYS_ID', cartVariables); gs.info('Request Item Created: ' + order.number);
-
Explanation:
- The
CartHelper
Script Include class provides a method to create items and sets their variables to make it reusable in multiple other scripts.
- The
-
Use Case: This promotes code reuse and makes it easier to maintain and update common cart-related logic.
-
This example shows how to ensure variables have the correct data type when setting them using the Cart API
-
Script (modifying example 2 and 4):
function createRequestWithVariableTypes() { var cart = new Cart(); var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with valid sys_id var requestedForUser = new GlideRecord('sys_user'); if(requestedForUser.get('USER_SYS_ID')){ //Replace with valid sys_id cart.setVariable(item, 'requested_for', requestedForUser.sys_id); } cart.setVariable(item, 'short_description', 'Example of Variable Types'); cart.setVariable(item, 'checkbox_value', true); // Sets a checkbox value cart.setVariable(item, 'single_line_text_value', 'Example string'); var rc = cart.placeOrder(); return rc; } var request = createRequestWithVariableTypes(); gs.info("Request Created with proper variable types : " + request.number);
-
Explanation:
- Explicitly handling different variable types to ensure data integrity. This example shows how to handle reference and boolean values.
- Use Case: This example shows how to properly set data values based on their data type, making it useful for most situations where different values need to be set.
-
Explanation:
This example shows how to set options and copy attachments when creating a request using the cart API.
-
Script:
function createRequestWithAttachments() { var cart = new Cart(); var item = cart.addItem('CATALOG_ITEM_SYS_ID'); // Replace with valid sys_id var options = { 'option1': 'value1', 'option2': 'value2' }; cart.setVariable(item, 'requested_for', 'USER_SYS_ID'); // Replace with the requested for user sys_id for (var option in options) { cart.setVariable(item, option, options[option]); } var rc = cart.placeOrder(); // Copy Attachments from the source record (current) to the request GlideSysAttachment.copy('YOUR_TABLE', current.sys_id, 'sc_request', rc.sys_id); return rc; } var request = createRequestWithAttachments(); gs.info("Request Created with attachments: " + request.number);
Explanation:
- Uses
cart.setVariable
to set various options on the requested item andGlideSysAttachment.copy
to copy attachments to the request.
Use Case:
- This is useful for when you want to set additional options, or copy source attachments onto a request.
-
Use the Cart API: Whenever possible, use the
Cart
API (examples 2, 4, 5, 6, 7, 8, 9, and 10) to create Service Catalog requests as it automatically handles record relationships, workflow, and data consistency. -
Error Handling: Include
try...catch
blocks in your scripts to handle errors gracefully and log them for troubleshooting. -
Logging: Use
gs.info()
orgs.error()
to log important events. - Comments: Add comments to your code to explain your logic.
- Security: Be careful when passing user data in your scripts, and adhere to security best practices.
- Test: Thoroughly test your methods in a non-production environment before deploying to production.
- Avoid direct insert for RITMs: Avoid directly inserting data into the RITM table unless you have a very specific reason to bypass the cart. Directly creating RITMs like this can cause issues with record relationships, workflows, and data consistency.
- Reusable Logic: Use Script Includes for reusable logic, such as cart variable setting, as it improves maintainability.
This article provides a comprehensive overview of several methods for programmatically generating Service Catalog Requests in ServiceNow. While UI Actions are suitable for simple redirections, the Cart
API is the preferred approach when creating new requests and items from within the platform due to its robustness, workflow integration, and flexibility. By understanding these methods and following best practices, you can automate and streamline request creation in your ServiceNow environment. Always remember to test all code in a non-production environment first.