I‘ve written before about some customizations that can be made to the catalog checkout screen in ServiceNow. The catalog checkout screen gives users one last opportunity to review their order and provide some additional details about the overall request before submitting an order. One common customization request I’ve heard before is to add additional fields to this checkout screen.

This article is an extension of an idea presented on the ServiceNow wiki that shows one way to approach this problem. The solution described here overcomes some of the problems with the wiki solution and gives a little bit more detail about how the solution works so that it’s easier for you to customize on your own. I’ll also include some formatting examples and show how you can add more than one additional field to the checkout screen.

This article describes an advanced customization that requires edits to an out-of-box UI Page and UI Macro. While it is possible (and often necessary) to make these types of edits, you should be aware that modifying these records prevents ServiceNow from upgrading them in the future.

Please note that in order to use this solution you must enable the two-step catalog checkout in your instance.

Add your new field(s) to the checkout screen

1Modify the ‘servicecatalog_cart_template’ UI Macro as follows…
Look for the section of code that has hidden input elements (designated by ‘input type=”HIDDEN”‘) and insert the following line directly after the other hidden elements. This line of code is used to store the unique cart ID for the user session. This ID will be referenced later on in a UI Page client script.

<input type="HIDDEN" name="cart_id" id="cart_id" value="$[sc_cart.sys_id]" />

Next, find the section of code that looks like this…

<tr class="header">
<td width="30%" >
${gs.getMessage('Requested for')}:
</td>
<td width="70%">
<label for="requestor_location">${gs.getMessage('Deliver to')}:</label>
</td>
</tr>
<tr><td>$[SP]</td></tr>
<tr>
<td valign="top">
<j2:if test="$[jvar_can_delta_rf == false]">
$[sc_cart.requested_for.getDisplayValue()]
</j2:if>
<j2:if test="$[jvar_can_delta_rf != false]">
<g2:catalog_requested_for />
</j2:if>
</td>
<td>
<textarea id="requestor_location" style="width: 100%" rows="4"
name="requestor_location" wrap="soft" onChange="catDeliveryAddress('$[sc_cart.sys_id]', 'requestor_location');" >
$[sc_cart.delivery_address]
</textarea>
</td>
</tr>
<tr>
<td>$[SP]</td>
</tr>

And insert the following code directly below it. This sample code adds a ‘Company’ reference field to your checkout form. You’ll need to customize this code to add your own field(s).

<tr class="header">
   <td colspan="2">Company:</td>
</tr>
<tr>
   <td>$[SP]</td>
</tr>
<tr>
   <td colspan="2">
      <g2:ui_reference name="core_company" table="core_company" onchange="setCartValue()"/>
   </td>
</tr>
<tr>
   <td>$[SP]</td>
</tr>

If you need to add multiple fields you can do so by adding the appropriate html. It’s also pretty simple to change the layout of the fields and their columns if you understand a little bit about html tables. Here’s an example that shows how to add two fields (Company and Requested Date) to the checkout form in a 2-column layout.

<tr class="header">
   <td width="30%">Company:</td>
   <td width="70%">Requested Date:</td>
</tr>
<tr>
   <td>$[SP]</td>
</tr>
<tr>
   <td width="30%">
      <g2:ui_reference name="core_company" table="core_company" onchange="setCartValue()"/>
   </td>
   <td colspan="2">
      <g2:ui_date name="requested_date" onchange="setCartValue()"/>
   </td>
</tr>
<tr>
   <td>$[SP]</td>
</tr>

You may have noticed the ‘ui_reference’ and ‘ui_date’ lines in the code above. These lines actually reference UI Macros by those names. The UI Macros are a great way to set up fields on a UI Page like this without having to set up all the specific pieces of the field element. There are several UI Macro field elements you can utilize out-of-box. These can be found by searching the UI Macros table for elements that start with ‘ui_’.

Passing the field values to the catalog cart and request

2Add the following script to the ‘Client Script’ field on the ‘servicecatalog_checkout_one’ UI Page (note that this sample is for the 2-field checkout addition and you’ll need to modify this script on the ‘var newField1’ and ‘var popVal’ lines if you’re only using one field). Its purpose is to get the values from the new checkout fields as they change and send them to the request ticket when the request is generated. You’ll want to pay attention to the separators used here to designate when a new field/value pair starts. The underlying code reserves some characters in this situation so I made a judgment call based on what I thought would work most of the time. The bottom line is that these need to match what you look for in the business rule in the next step.

If you need to add additional fields to your checkout page you’ll need to customize this function to include those additional field/value combinations.

function setCartValue() {
   var fieldSeparator = '^';  //Cannot be ':' or '='
   var nameValSeparator = 'IS';  //Cannot be ':' or '='

   //Get the new field elements we've added
   var newField = gel('core_company');
   var newField1 = gel('requested_date');

   //Query for the user cart
   var cart_item = new GlideRecord('sc_cart_item');
   cart_item.addQuery('cart.user', g_user.userID);
   cart_item.addQuery('active', 'true');
   cart_item.query();

   //If found, add the field/value pairs to the 'hints' parameter for the cart
   if(cart_item.next()) {
      //Aggregate all of the field-value pairs
      var popVal = 'company' + nameValSeparator + newField.value + fieldSeparator + 'requested_date' + nameValSeparator + newField1.value;
      //Send the values to the request record
      cart_item.hints = "<hints><entry key='sysparm_processing_hint' value='setfield:request.u_cartpop=" + popVal + "'/></hints>";
      cart_item.update();
   }
}

If you’re just adding a single field to the checkout page (and have no plans to potentially add more fields) then you could simply modify the script above to eliminate the ‘u_cartpop’ and ‘popVal’ pieces all together. These pieces exist for the sole purpose of passing multiple field/value pairs on to the request. If you just need a single field, comment out the first ‘popVal’ line, change ‘u_cartpop’ to the name of the field on the request form you need to populate, and use the single field example included in step 1 above.

If you are looking for a more extensible solution that you could add to in the future, or if you already know that you will need more than one field added to the checkout form, read on!

Populating the field values

—This final portion is the major piece that I’ve changed from the solution described on the ServiceNow wiki. The whole purpose of these last steps is to allow you to populate more than one field on the request ticket. The ‘hints’ parameter in the UI Page client script above only accepts a single name/value pair to set. To work around this limitation, the script above concatenates all of the name/value pairs and passes them in as a single string to a custom field you need to create called ‘CartPop [u_cartpop]’.

3Create a new string field on the Request [sc_request] table named ‘CartPop’.
The field will be used to capture the field/value pairs string being passed from the checkout page. It should have a length that is long enough to accommodate all of the field/value pairs being passed in from your checkout page. A 1000 character limit should be more than enough to pass in values from several additional fields. This field can be removed from the request form once it is created.

4Create a new business rule on the Request [sc_request] table with the settings as shown below. The purpose of the business rule is to get the value of the ‘u_cartpop’ field, parse the field/value pairs out of it, and populate those values into the correct field(s) on the request record.

Populate Cart Values Business Rule
Name: Populate Cart Values
Table: Request [sc_request]
When: before
Insert: true
Condition: !current.u_cartpop.nil()
Script:

//Get the values to populate and split into name/value pairs
var popVals = current.u_cartpop.split("^");
for(x in popVals){
   //Split each pair and populate the correct field
   var popVal = popVals[x].split("IS");
   if(popVal.length == 2){
      eval('current.' + popVal[0] + '="' + popVal[1] + '";');
   }
}

If you’ve done everything correctly you should be able to order a catalog item, view and populate your new fields on the checkout form, and see those fields populated on the Request record as shown here…

Validating checkout fields / Making checkout fields mandatory

One last step that you may need to take is to make sure that certain checkout fields are filled out or validated before submission. I’ve written about how to do this in a separate article found here.