ServiceNow Checklist Automation: Simplifying Catalog Task Management
Automating checklist creation for tasks in ServiceNow can save significant time and ensure consistency across your IT processes. This guide will show you how to implement this using a Script Include, Business Rule (or Flow Designer), and System Properties.
You will use the checklist and checklist_item tables to automatically create and manage checklists for catalog tasks. The system property stores checklist configurations in a JSON format, allowing you to customize checklist items and define their mandatory status for different catalog items.
If you need to manage a large number of checklists, you can create a custom table in your scoped application to store the configurations. A custom table will help you manage the data more easily and offer better flexibility for future updates. In this case, you will need to modify the Script Include to retrieve checklist data from the new table instead of the system property.
The automation is triggered by a Business Rule in the Global Scope, which ensures that tasks cannot be closed unless all mandatory checklist items are completed. By automating this process, you can maintain consistency and reduce manual work, especially in IT service management workflows.
Key Components
System Property
The system property, catalogTask.checklists, stores the configuration for the checklists. This property uses a JSON structure to define which checklists and items are associated with specific catalog items. Each catalog item in the configuration includes the following:
- Country or Catalog: You can group the checklist by Catalog or Country at the highest level.
- Catalog Item Sys ID: Each catalog item is linked to specific service request tasks, and each task can have its own checklist.
- Checklist Name: The name of the checklist associated with the catalog item.
- Items: A list of individual checklist items, where each item includes:
- name: The name of the checklist item.
- order: The display order of the checklist item.
- mandatory: A boolean that determines whether the item must be completed before the task can be closed.
If you are handling many checklists, using a custom table within your scoped application will scale better. The custom table can store the checklist data, and you can modify the Script Include to pull data from that table instead of the system property.
Checklist and Checklist Item Tables
The checklist and checklist_item tables store the checklists and their items for each catalog task. When you create a task, the Business Rule checks the system property to determine if a checklist is required. If the checklist data exists, the script inserts records into the checklist table and adds individual items to the checklist_item table.
The checklist table links the checklist to the specific catalog task using the document field. The checklist_item table stores each checklist item with details such as the name, order, and completed status. The complete field tracks whether each item has been completed.
You can also use the Checklist Template as an alternative, provided that your governance structure allows for easy management of these configurations in production environments. This approach may simplify the process, especially if you’re looking to manage checklist setups more efficiently.
Business Rule in Global Scope
The Business Rule triggers the checklist creation process when you create a new catalog task and validates the checklist completion when the task is updated. The rule queries the checklist and checklist_item tables to make sure that all mandatory items are complete before allowing the task to close.
The Business Rule needs to be in the Global Scope to use the setAbortAction(true) method, which prevents the task from closing if any mandatory checklist items are incomplete. You cannot use this method in scoped applications because they do not allow aborting database transactions directly.
System Property Configuration
Create a system property named catalogTask.checklists and store your JSON configuration defining the checklists and their items.
Example JSON:
{
"checklists": {
"<Country or Catalog>": {
"sys_id_of_Item1": {
"checklistName": {
"items": [
{
"name": "Item1 Name1",
"order": 1,
"mandatory": true
},
{
"name": "Item1 Name2",
"order": 2,
"mandatory": false
},
{
"name": "Item1 Name3",
"order": 3,
"mandatory": true
}
]
}
},
"sys_id_of_Item2": {
"checklistName": {
"items": [
{
"name": "Item2 Name1",
"order": 1,
"mandatory": false
},
{
"name": "Item2 Name2",
"order": 2,
"mandatory": true
}
]
}
}
}
}
}
Script Include
The ChecklistCreator Script Include creates and manages checklists for catalog tasks. It retrieves the checklist configuration from the system property and determines whether to create a checklist for a specific catalog task.
When a checklist needs to be created, the script uses the catalog item sys_id to retrieve the relevant checklist data from the system property. If the data exists, the script automatically creates the checklist and its items for the task.
The system property defines which checklist items are mandatory. The script checks the actual items in the checklist_item table to ensure they are marked as complete. If all mandatory items are complete, the task proceeds. If not, the script blocks the task from closing and displays a message to the user.
Scoped Script Include Name: ChecklistCreator
var ChecklistCreator = Class.create();
ChecklistCreator.prototype = {
initialize: function() {},
/**
* Retrieves the checklist data for a catalog item from the system property.
*
* @param {String} catalogItemSysId - The sys_id of the catalog item.
* @returns {Object|null} - Returns the checklist data as a JSON object if it exists, null otherwise.
*/
getChecklistData: function(catalogItemSysId) {
try {
/* Get the JSON from the system property */
var jsonString = gs.getProperty('x_916860_autocklst.catalogTask.checklists');
if (!jsonString) {
gs.error('System property x_916860_autocklst.catalogTask.checklists is not set or is empty');
return null;
}
/* Parse the JSON string */
var checklists;
try {
checklists = JSON.parse(jsonString);
} catch (e) {
gs.error('Failed to parse JSON from system property: ' + e.message);
return null;
}
/* Retrieve the checklist data for the catalog item */
for (var i = 0; i < checklists.length; i++) {
if (checklists[i].catalog_item_sys_id === catalogItemSysId) {
return checklists[i];
}
}
return null;
} catch (e) {
gs.error('Unexpected error occurred in getChecklistData: ' + e.message);
return null;
}
},
/**
* Creates checklists and items for a catalog task based on the retrieved checklist data.
*
* @param {String} catalogTaskSysId - The sys_id of the catalog task.
* @param {Object} checklistData - The checklist data retrieved from the system property.
*/
createChecklistsForCatalogTask: function(catalogTaskSysId, checklistData) {
try {
if (!checklistData) {
gs.error('No checklist data provided for catalog task: ' + catalogTaskSysId);
return;
}
var items = checklistData.items;
if (!items) {
gs.error('Checklist items not found for the specified catalog task and checklist name');
return;
}
/* Check if a checklist already exists for the catalog task */
var existingChecklistGR = new GlideRecord('checklist');
existingChecklistGR.addQuery('document', catalogTaskSysId);
existingChecklistGR.query();
if (existingChecklistGR.next()) {
gs.info('Checklist already exists for catalog task: ' + catalogTaskSysId);
return;
}
/* Create checklist record */
var checklistSysId;
try {
var checklistGR = new GlideRecord('checklist');
checklistGR.initialize();
checklistGR.document = catalogTaskSysId;
checklistGR.name = checklistData.checklist_name;
checklistGR.table = 'sc_task';
checklistSysId = checklistGR.insert();
} catch (e) {
gs.error('Failed to create checklist record for catalog task: ' + e.message);
return;
}
if (!checklistSysId) {
gs.error('Failed to create checklist record for catalog task: ' + catalogTaskSysId);
return;
}
/* Create checklist items */
try {
items.forEach(function(item) {
var checklistItemGR = new GlideRecord('checklist_item');
checklistItemGR.initialize();
checklistItemGR.checklist = checklistSysId;
checklistItemGR.name = item.name;
checklistItemGR.order = item.order;
checklistItemGR.mandatory = item.mandatory;
checklistItemGR.insert();
});
} catch (e) {
gs.error('Failed to create checklist items: ' + e.message);
return;
}
gs.info('Checklist and items created successfully for catalog task: ' + catalogTaskSysId);
} catch (e) {
gs.error('Unexpected error occurred in createChecklistsForCatalogTask: ' + e.message);
}
},
/**
* Checks if all mandatory checklist items are checked for a given catalog task.
*
* @param {String} catalogTaskSysId - The sys_id of the catalog task.
* @param {String} checklistSysId - The sys_id of the checklist.
* @returns {Boolean} - Returns true if all mandatory checklist items are completed, false otherwise.
*/
areMandatoryChecklistItemsChecked: function(catalogTaskSysId, checklistSysId) {
try {
// Retrieve the catalog task record
var catalogTaskGR = new GlideRecord('sc_task');
if (!catalogTaskGR.get(catalogTaskSysId)) {
gs.error('Catalog task record not found: ' + catalogTaskSysId);
return false;
}
var ritmSysId = catalogTaskGR.getValue('request_item'); // Get the RITM sys_id
var ritmGR = new GlideRecord('sc_req_item');
if (!ritmGR.get(ritmSysId)) {
gs.error('RITM record not found for catalog task: ' + catalogTaskSysId);
return false;
}
var catalogItemSysId = ritmGR.getValue('cat_item'); // Get the catalog item sys_id
// Get checklist data for the catalog item from the system property
var checklistData = this.getChecklistData(catalogItemSysId);
if (!checklistData) {
gs.error('No checklist data found for catalog item: ' + catalogItemSysId);
return false;
}
var items = checklistData.items;
if (!items || items.length === 0) {
gs.error('No checklist items found for catalog item: ' + catalogItemSysId);
return false;
}
// Check if all mandatory checklist items are completed
for (var i = 0; i < items.length; i++) {
var checklistItem = items[i];
if (checklistItem.mandatory) { // Only check mandatory items
var checklistItemGR = new GlideRecord('checklist_item');
checklistItemGR.addQuery('checklist', checklistSysId);
checklistItemGR.addQuery('name', checklistItem.name); // Match the item name from property
checklistItemGR.query();
if (!checklistItemGR.next() || checklistItemGR.getValue('complete') !== '1') { // Use 'complete' field to check completion
gs.info('Mandatory checklist item not completed: ' + checklistItem.name);
return false;
}
}
}
// All mandatory items are completed
return true;
} catch (e) {
gs.error('Unexpected error occurred in areMandatoryChecklistItemsChecked: ' + e.message);
return false;
}
},
type: 'ChecklistCreator'
};
Business Rule
The Global Scope Business Rule runs when a catalog task is created (inserted) or updated (on state change). The ChecklistCreator Script Include is called to manage checklist creation and validation.
- On Insert: When you create a catalog task, the Business Rule retrieves the requested item (RITM) linked to the task. It uses the catalog item sys_id to get the corresponding checklist data from the system property. If the data is found and the short description of the task matches the checklist name, the checklist is created.
- On Update (When Task Is Closing): When the catalog task is updated to a closed state, the Business Rule checks whether all mandatory checklist items are complete. The associated checklist record is queried, and the ChecklistCreator Script Include validates the completion status of mandatory items. If any mandatory item is incomplete, the task closure is blocked, and an error message is shown.
Global Scope Business Rule
Name: Create and Validate Checklists
When: Before INSERT and UPDATE
Table: Catalog Task
Condition: Add appropriate condition so this BR executes for your Catalog items
/**
* Business Rule to create and validate checklists for catalog tasks.
*
* This Business Rule triggers on both insert and update operations:
* - On insert: it creates a checklist for the catalog task if defined in the system property.
* - On update: it validates if all mandatory checklist items are completed before closing the task.
*
* @param {GlideRecord} current - The current record being processed (sc_task).
* @param {GlideRecord} previous - The previous version of the record (null when async).
*/
(function executeRule(current, previous /*null when async*/) {
try {
// Instantiate the ChecklistCreator Script Include from the scoped application
var checklistCreator = new x_916860_autocklst.ChecklistCreator();
/**
* Case 1: Checklist Creation on Insert
*
* If a new catalog task is inserted, the script checks if a checklist needs to be created
* based on the catalog item and the short description of the task.
*/
if (current.operation() == 'insert') {
// Get the associated Requested Item (RITM) record
var ritmGR = current.request_item.getRefRecord();
if (ritmGR.isValidRecord()) {
// Get the catalog item sys_id from the RITM record
var catalogItemSysId = ritmGR.getValue('cat_item');
// Retrieve checklist data from the system property
var checklistData = checklistCreator.getChecklistData(catalogItemSysId);
// If checklist data is found and the short description matches the checklist name, create the checklist
if (checklistData && current.getValue("short_description") == checklistData.checklist_name) {
checklistCreator.createChecklistsForCatalogTask(current.sys_id, checklistData);
}
}
}
/**
* Case 2: Checklist Validation on Update
*
* If the catalog task is being updated to the Closed Complete state, the script checks
* if all mandatory checklist items are completed before allowing the task to close.
*/
if (current.operation() == 'update' && current.state.changesTo('3')) { // '3' represents Closed Complete state
// Retrieve the associated checklist record for the current task
var checklistGR = new GlideRecord('checklist');
if (checklistGR.get('document', current.sys_id)) {
// Validate if all mandatory checklist items are checked
var allChecked = checklistCreator.areMandatoryChecklistItemsChecked(current.sys_id, checklistGR.sys_id);
// If not all mandatory checklist items are checked, abort the closure and show an error message
if (!allChecked) {
gs.addErrorMessage('There are mandatory checklist items that are not completed.');
current.setAbortAction(true); // Prevent closure if mandatory items are not checked
}
}
}
} catch (e) {
// Log any unexpected errors that occur during the execution of the Business Rule
gs.error('Unexpected error in Business Rule Create and Validate Checklists: ' + e.message);
}
})(current, previous);
Summary
By using ServiceNow’s Script Include and Business Rule, you can automate checklist creation and validation for catalog tasks, ensuring consistency and efficiency. You define checklists dynamically in a system property using a JSON format, which allows you to customize checklist items for each catalog task, including the order, mandatory status, and checklist names.
For smaller setups, the system property works well. However, for larger checklist configurations, you can create a custom table in your scoped application to store the checklist data. This makes managing a large number of checklists easier and more flexible.
With this automated process, you prevent task closures until all mandatory checklist items are completed. This reduces manual work, minimizes errors, and ensures consistent task management across your organization.
Date Posted:
October 2, 2024
Share This:
2 Comments
Comments are closed.
Related Posts
Fresh Content
Direct to Your Inbox
Just add your email and hit subscribe to stay informed.







Very nice implementation!
Out of curiosity, why did you choose to utilise sys_property with JSon for the checklist configuration and not checklist templates?
Thank you! Great question!
I chose to use a JSON-based system property over checklist templates mainly for flexibility and control. My use case required both the automation of checklists for specific catalog tasks and the ability to designate certain checklist items as mandatory. Checklist templates have limitations here:
1. Mandatory Field Control: Checklist templates don’t provide a way to set specific items as mandatory, which was essential to ensure that certain tasks couldn’t close without meeting critical requirements.
2. Maintainability: With a JSON structure in a system property (or perhaps a custum table), it’s easier to update or customize checklist configurations centrally without needing to adjust templates. For large-scale environments with many checklists, this approach also allows for a more scalable and governance-friendly setup, making it easier to manage checklist data and updates across environments.
I hope this helps clarify!