Blog

Managing Child Tasks in ServiceNow

If you close a parent record in ServiceNow, what is done with the child tasks?  There are multiple ways to deal with these child tasks in ServiceNow.  Depending on your business requirements, you can choose one of these methods to meet your needs.

1. Ignore Child Tasks

This is how it is handled in the ServiceNow base system for Problem Management.  For example, you have a open Problem, and related child problem tasks.  If you close the problem record, the child problem task record is left open.

I prefer the other methods below as this method sometimes leaves tasks open that should be closed sooner.

2. Close Child Tasks

In base Incident Management, if you close an Incident with related child tasks, the child tasks are also closed.  

This is done by the Business Rule, Update Child Incidents.  When the Incident state is set to resolved, this Business Rule closes the related child incidents with close notes, close code, and adds a comment.

This is a good example of a script to close child tasks.  I reuse this script when I need it in a different area of ServiceNow.  I have to modify certain areas of the script to do that, but the concept of this script is a good start for development.

Business Rule: Update Child Incidents
When: before
Advanced: true
Update: true
Condition current.isValidRecord() && (current.incident_state.changesTo(6) || current.comments.changes() || current.work_notes.changes())
Script:

updateChildIncidents();
function updateChildIncidents() {
   if (current.incident_state.changesTo(6))
      resolveChildIncidents();
   else
      commentChildIncidents();
}

function commentChildIncidents() {
   var rec = new GlideRecord("incident");
   rec.addQuery("parent_incident", current.sys_id);
   rec.addQuery("incident_state", "!=", "6");
   rec.addActiveQuery();
   rec.query();
   while (rec.next()) {
      var msg = "Comment copied from Parent Incident";
      if (current.comments.toString().indexOf(msg) == 0)
         rec.comments = current.comments;
      else
         rec.comments = msg + ": " + current.comments;
      msg = "Work note copied from Parent Incident";
      if (current.work_notes.toString().indexOf(msg) == 0)
         rec.work_notes = current.work_notes;
      else
         rec.work_notes = msg + ": " + current.work_notes;
      rec.update();
   }
}

//
// Resolve active, unresolved incidents that are children of the current incident
//
function resolveChildIncidents() {
   var incident = new GlideRecord("incident");
   incident.addActiveQuery();
   incident.addQuery("parent_incident", current.sys_id);
   incident.addQuery("incident_state", "!=", "6");
   incident.query();
   var msg = "";
   while (incident.next()) {
      gs.print("Incident " + incident.number + ' resolved based on resolution of Parent Incident ' + current.number);
      incident.incident_state = 6;
      if (incident.close_notes.nil()) {
         msg = "Close notes copied from Parent Incident";
         if (current.close_notes.toString().indexOf(msg) == 0)
            incident.close_notes = current.close_notes;
         else
            incident.close_notes = msg + ": " + current.close_notes;
      }
      incident.close_code = current.close_code;
      msg = "Resolved based on resolution of Parent Incident.";
      if (current.comments.toString().indexOf(msg) == 0)
         incident.comments = current.comments;
      else
         incident.comments = msg + " " + current.comments;
      incident.work_notes = current.work_notes;
      incident.update();
   }
}

3. Check for Open Child Tasks and Display Error

There isn't a base script for this, but I often add it to ServiceNow systems.  If there are open child tasks, have the user close them first before closing the parent.

Here is a generic script you can use for this.  Replace <your_child_table> with the child table you want to check,  <your_parent_field> with a parent field like "parent", "top_task", or "problem", and <your_close_condition> with a something like current.active.changesTo(false).

Business Rule: Open Child Check
When: before
Advanced: true
Insert: true
Update: true
Condition <your_close_condition>
Script:
checkChildTasks();
function checkChildTasks() {
var grChild = new GlideRecord("<your_child_table>");
grChild.addQuery('<your_parent_field>', current.sys_id);
grChild.addActiveQuery();
grChild.query();
if (grChild.getRowCount() > 0) {
gs.addErrorMessage('Can not close Problem. Please close open Child Tasks first.');
current.setAbortAction(true);
}
}

Example for Change Request

Business Rule: Open Change Task Check
When: before
Advanced: true
Insert: true
Update: true
Table: Change Request [change_request]
Condition current.state.changesTo(3) || current.state.changesTo(4) || current.state.changesTo(7)
Script:
checkChildTasks();
function checkChildTasks() {
var grChild = new GlideRecord("change_task");
grChild.addQuery('change_request', current.sys_id);
grChild.addActiveQuery();
grChild.query();
if (grChild.getRowCount() > 0) {
gs.addErrorMessage('Can not close Change. Please close open Change Tasks first.');
current.setAbortAction(true);
}
}