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.

The Challenge

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.

Methods for Generating Service Catalog Requests

Here are the commonly used methods:

Example 1: Create Request from UI Action

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.

Example 2: Create Requested Items from Inbound Action using Cart API

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 new Cart 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.

Example 3: Create Requested Items from Inbound Action without Cart

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.

Example 4: Create Requested Item from Business Rule

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.

Example 5: Create Requested Item from Transform Script

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.

Example 6: Setting Variables from a JSON Object (Cart API)

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().
    • 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.

Example 7: Creating Multiple Requested Items in a single Request (Cart API)

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.

Example 8: Using a Script Include for Reusable Cart API Logic

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.
    • Use Case: This promotes code reuse and makes it easier to maintain and update common cart-related logic.

Example 9: Handling Variable Types

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.

Example 10: Setting Options and Attachments

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 and GlideSysAttachment.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.

Best Practices

  • 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() or gs.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.

Conclusion

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.

⚠️ **GitHub.com Fallback** ⚠️