W

hen implementing the Change management process in ServiceNow you’ll probably encounter a scenario where your entire change workflow (including all tasks and approvals) needs to be reset.  The first option to consider (assuming you’re using the graphical workflow engine to manage the tasks and approvals) is the Rollback workflow activity.  The rollback activity works great for a lot of scenarios, but what if you don’t have a defined point in the workflow where everything should be rolled back?  What if the rollback (or reset) can happen at any point in time?  There’s not really an easy way to handle this within the workflow itself since you would need to check for a rollback condition at an infinite number of places.

I recently encountered this scenario while working with a client and used the ‘SNC Approval – Reset conditions‘ business rule to solve the problem.  By using a business rule, you can allow the end user (which in this case would typically be a member of the Change Advisory Board) to indicate when a full workflow reset should be done.  Users can force a reset by setting the value of a field on the Change request ticket itself. The ‘SNC Approval – Reset conditions’ business rule gives you 3 different options for how the approval reset should happen.

1 – Cancel all existing approvals and reset
2 – Delete all existing approvals and reset
3 – Leave all existing approvals alone and reset

I chose to use option 1 so that we would have a record of any previous approval activity that had taken place. Depending on the situation and your organization’s audit requirements, option 2 might be a good alternative as well. I can’t think of a scenario where option 3 would be a good thing but it’s there if you need it.

The solution I used was to set up a UI action button that I named ‘Reset change workflow’.  The sole purpose of the UI action is to set some value on the change request ticket to trigger the ‘SNC Approval – Reset conditions’ business rule.  I chose to create a new choice value in the ‘Approval’ field called ‘Reset’.  My business rule checks before any update to see if the value of the ‘Approval’ field is ‘Reset’.  If it is, then the workflow attached to the change request gets reset.  Here’s the step-by-step guide to implement this type of reset functionality…

1Personalize the choices for the ‘Approval’ field on the change request form and add an option called ‘Reset’.

2Create a new UI action with the following parameters:

Name: Reset change workflow
Table: Change request
Client: True
OnClick: setApprovalReset()
Condition: gs.hasRole(‘itil’)
Form button: True
Script:

function setApprovalReset(){
   var con = confirm('Performing this action will reset the associated workflow including all approvals. Are you sure you want to continue?');
   if(con){
      g_form.setValue('approval', 'Reset');
      gsftSubmit(gel('sysverb_update_and_stay'));
   }
   else{
      return con;
   }
}

3Modify the ‘SNC Approval – Reset conditions’ business rule as follows:

Name: SNC Approval – Reset conditions
Table: Change request
Active: True
Condition: current.approval.changesTo(‘Reset’) && gs.hasRole(‘itil’)
Script:

// these are the conditions under which the change request approvals need to be canceled and reset
// steps to activate
// 1. enable this business rule
// 2. add some comments so the reset will be noted in the approval history
// 3. uncomment the code for restart or reset based on your requirements
// 4. define the reset condition in checkResetConditions function below
// 5. you must set doReset once you capture the change(s) you are interested in

var comment = 'Approval reset by ' + gs.getUserDisplayName(); //written to the approval_history
if (checkResetConditions()) {
   // create a global variable lock on the current record
   // this will prevent triggering a second reset while the first reset is still in progress
   // lock will be release in a late running business rule called 'Workflow Release Lock'
   if (typeof GlideRecordLock != 'undefined')
      chg_wf_lock = GlideRecordLock(current);
   else
      chg_wf_lock = new Packages.com.glide.script.RecordLock(current);
   chg_wf_lock.setSpinWait(50); //wait for lock
   if (chg_wf_lock.get()) {
      gs.print('SNC Approval conditions business rule is locking the ' + current.getDisplayValue() + ' during the workflow reset');

      // The following options are available for resetting the approvals:
      //
      // 1. Mark all existing approvals for the change as 'cancelled' and restart the workflow to create new approvals
      new WorkflowApprovalUtils().cancelAll(current, comment);
      new Workflow().restartWorkflow(current);
      //
      // 2. Delete all of the existing approvals for the change and restart the workflow to create new approvals
      // new WorkflowApprovalUtils().reset(current, comment);
      // gs.addInfoMessage('Workflow has been reset since key fields have been modified');
      //
      // 3. Leave the approvals for the change in their current state and restart the workflow.
      // (so that any new approvals that are required will be created)
      // if (comment)
      //    current.setDisplayValue('approval_history', comment);
      //    new Workflow().restartWorkflow(current, true);
      //

   }

   //Use this section to reset any necessary information on the Change request
   current.work_notes = 'Change approvals and workflow reset due to material change by ' + gs.getUserDisplayName();
   current.approval = 'not requested';

   //Use this section to reset any necessary information on any associated Change tasks
   var tsk = new GlideRecord('change_task');
   tsk.addQuery('change_request', current.sys_id);
   tsk.query();
   while(tsk.next()){
      tsk.work_notes = 'Change request workflow reset.';
      tsk.update();
   }
   gs.addInfoMessage('Change approvals and workflow reset for ' + current.number + '.');
}

function checkResetConditions() {
   var doReset = false; //default to no reset
   //add reset conditions here such as:
   //if (current.assigned_to.changes())
   doReset = true; //enable the reset

   return doReset;
}