Name

global.PlannedTaskUtilsV2

Description

Planned Task utility functions, commonly called from business rules

Script

var PlannedTaskUtilsV2 = Class.create();

/*
* Restart children when parent is restarted (active changes to true)
*/
PlannedTaskUtilsV2.reactivateChildren = function(parent, previousState) {
  var plannedTaskStateUtil = new PlannedTaskStateUtil(parent);
  var defaultSkipped = plannedTaskStateUtil.getDefaultSkippedState();
  gs.log("PlannedTaskUtilsV2.restartChildren");
  var api = new SNC.PlannedTaskAPI();
  var stateBucket = plannedTaskStateUtil.getBucketForState(parent.state);
  /*if(stateBucket != null){
      var children = api.getDescendants(current, false);
      var percentCompleteHelper = new PercentCompleteHelper();
      percentCompleteHelper.clearStack(parent);
      var childStateUtil;
      var childDefaultOpen;
      var childDefaultSkipped;
      while (children.next()) {
          childStateUtil = new PlannedTaskStateUtil(children);
          childDefaultOpen = plannedTaskStateUtil.getDefaultOpenState();
          childDefaultSkipped = plannedTaskStateUtil.getDefaultSkippedState();
          if (previousState != defaultSkipped && children.state == childDefaultSkipped)
              continue;
          children.active = true;
          if (stateBucket != PlannedTaskStateUtil.WORK_IN_PROGRESS)
              children.state = childStateUtil.getValidStateForBucket(stateBucket, parent.state);
          else if (previousState == defaultSkipped && stateBucket == PlannedTaskStateUtil.WORK_IN_PROGRESS)
              children.state = childDefaultOpen;
          children.work_start = "";
          children.work_end = "";
          children.percent_complete = 0;
          percentCompleteHelper.process(children);
          children.update();
          gs.log(" PlannedTaskUtilsV2.restartChildren:: " + children.getDisplayValue() + " restarted " + children.state);
      }
      percentCompleteHelper.rollup(parent);
      percentCompleteHelper.clearStack(parent);
  }*/
  // Else For Perfomance - Call below
  if(parent.getValue('sys_id') != parent.getValue('top_task') && parent.instanceOf("pm_project"))
  	api.updateSubProjectState(parent, {}, plannedTaskStateUtil.getDefaultPendingState());
  else
  	api.updateProjectState(parent, {}, plannedTaskStateUtil.getDefaultPendingState());
};


/*
* Set children when parent state is changed to Open/Pending
*/
PlannedTaskUtilsV2.setChildrenState = function(parent, bucket, state) {
  gs.log("PlannedTaskUtilsV2.setChildrenState");
  // var treeNavigator = new SNC.NestedIntervalUtilities("planned_task");
  // var children = treeNavigator.getDescendants(current, false);
  var plannedTaskStateUtil = new PlannedTaskStateUtil(parent);
  var projectMgmtApi = new SNC.PlannedTaskAPI();
  if(parent.getValue('sys_id') != parent.getValue('top_task') && parent.instanceOf("pm_project"))
  	projectMgmtApi.updateSubProjectState(parent, {}, plannedTaskStateUtil.getDefaultPendingState());
  else
  	projectMgmtApi.updateProjectState(parent, {}, plannedTaskStateUtil.getDefaultPendingState());
//     var children = projectMgmtApi.getDescendants(current, false);
//     var childStateUtil;
//     var childState;
//     while (children.next()) {   
//         childStateUtil = new PlannedTaskStateUtil(children);
//         childState = childStateUtil.getValidStateForBucket(bucket, state);
//         children.active = true;
//         children.state = childState;
//         children.work_start = "";
//         children.work_end = "";
//         children.percent_complete = 0;
//         children.update();
//     }
};

PlannedTaskUtilsV2.startSuccessors = function(task, bucket) {
  
  gs.print("PlannedTaskUtilsV2.startSuccessors - " + task.getValue('sys_id'));
  // var tree = new SNC.NestedIntervalUtilities("planned_task");
  // var sysIdsToStart = tree.getLeafNodesForStateChange(task.getUniqueValue(), true); //true : leaves of successor nodes
  var projectMgmtApi = new SNC.PlannedTaskAPI();
  var sysIdsToStart = projectMgmtApi.getLeafNodesForStateChange(task.getUniqueValue(), true); //true : leaves of successor nodes
  var stateUtil;
  gs.print("PlannedTaskUtilsV2.startSuccessors - sysIdsToStart : " + sysIdsToStart);
  for (var i = 0; i < sysIdsToStart.length; ++i) {
      var taskToStart = new GlideRecord('planned_task');
      var sysId = sysIdsToStart[i];
      taskToStart.get(sysId);
      stateUtil = new PlannedTaskStateUtil(taskToStart);
  	if(stateUtil.isStatePending(taskToStart.getValue('state'))) {
  		var state = stateUtil.getDefaultStateForBucket(bucket);
  		taskToStart.state = state;
  		taskToStart.update();
  	}
  }
};


/*
* schedule a lag task for some time in the future
*/
PlannedTaskUtilsV2.triggerTask = function(task, startState) {
  // Search for a pre-existing trigger
  var trigger = new GlideRecord("sys_trigger");
  trigger.addQuery("document_key", task.getUniqueValue());
  trigger.query();
  if (trigger.next()) {
      // You found a trigger...update it with the new start time
      trigger.next_action = task.start_date;
      trigger.update();
  } else {
      // You didnt find a trigger...create one
      var newTrigger = new GlideRecord("sys_trigger");
      newTrigger.name = 'Start planned task ' + task.short_description;
      newTrigger.next_action = task.start_date;
      newTrigger.document = 'planned_task';
      newTrigger.document_key = task.getUniqueValue();
      newTrigger.script = "var taskGr = new GlideRecord('planned_task'); if (taskGr.get('" + task.getUniqueValue() + "')) {taskGr.state = " + startState + "; taskGr.update();}";
      newTrigger.job_id.setDisplayValue('RunScriptJob');
      newTrigger.trigger_type = 0;
      newTrigger.insert();
  }
};

/*
* Close parent when all child tasks are closed
*/
PlannedTaskUtilsV2.closeParent = function(task, closeState) {
  // get active tasks with same parent
  var sibling = new GlideRecord('planned_task');
  sibling.addQuery('parent', task.parent);
  sibling.addNullQuery('orig_sys_id');
  sibling.addQuery('sys_id', '!=', task.sys_id);
  sibling.addActiveQuery();
  sibling.query();
  if (sibling.hasNext()) {
      // parent still has active task, do nothing
      return;
  }
  
  // all of the parent's children are closed, so close parent
  var parent = new GlideRecord("planned_task");
  if (!parent.get(task.parent))
      return;
  
  parent.state = closeState;
  parent.update();
};

/*
* Changes the parent state according to the child states
*/
PlannedTaskUtilsV2.setParentState = function(task, isDeleted) {
  gs.log("PlannedTaskUtilsV2.setParentState " + task.getDisplayValue());
  
  var parent = new GlideRecord("planned_task");
  if (!parent.get(task.parent))
      return;
  
  if (parent.sys_class_name.toString() === 'sn_cim_register')
  	return;
  
  var ptRollupApi = new PlannedTaskRollupApi();
  if(!(ptRollupApi.isValidRollUp(task.getValue('sys_class_name'), parent.getValue('sys_class_name') , 'state'))) 
  	return;
 
  
  	var lookupTable = parent.sys_class_name;
  	var tempGr = new GlideRecord(parent.sys_class_name);
  	if(tempGr.instanceOf('pm_project') || tempGr.instanceOf('pm_project_task')){
  		lookupTable = tempGr.instanceOf('pm_project') ? 'pm_project' : 'pm_project_task';
  	}
  	
  	var sysClassExclusions = ptRollupApi.getRollupExclusions(lookupTable,'state');
  	var siblings = function(){
      var gr = new GlideRecord('planned_task');
      gr.addQuery('parent', task.parent);
  	if(sysClassExclusions.length >0 )
  		gr.addQuery('sys_class_name', 'NOT IN', sysClassExclusions.join(','));   
      gr.addNullQuery('orig_sys_id');
      gr.addQuery('sys_id', '!=', task.sys_id);
      gr.query();
      return gr;
  	
  };
  
  var stateUtil = new PlannedTaskStateManagement(task, parent, siblings);
  var state = stateUtil.manageStateChange(isDeleted);
  if ( state != parent.getValue('state') ) {
  	gs.log("-->Log parent state updating.." +state);
      parent.setValue('state', state);
      parent.update();
  }
  
};


/*
* Sets parent's state when child task is deleted
*/
PlannedTaskUtilsV2.handleParentStateOnChildDelete = function(task) {
  //If there is only one child left, need to use that state for the parent
  var parentStateUtil = new PlannedTaskStateUtil(task.top_task);
  if(parentStateUtil.getBucketForState(task.top_task.state) == PlannedTaskStateUtil.WORK_IN_PROGRESS)
      PlannedTaskUtilsV2.startSuccessors(task, PlannedTaskStateUtil.WORK_IN_PROGRESS);
  var parentGr = new GlideRecord("planned_task");
  if (!parentGr.get(task.parent))
      return;
  
  var ptRollupApi = new PlannedTaskRollupApi();
  if(!(ptRollupApi.isValidRollUp(task.getValue('sys_class_name'), parentGr.getValue('sys_class_name') , 'state'))) 
  	return;
  
  var lookupTable = parentGr.sys_class_name;
  var tempGr = new GlideRecord(parentGr.sys_class_name);
  if(tempGr.instanceOf('pm_project') || tempGr.instanceOf('pm_project_task')){
  	lookupTable = tempGr.instanceOf('pm_project') ? 'pm_project' : 'pm_project_task';
  }
  var sysClassExclusions = ptRollupApi.getRollupExclusions(lookupTable,'state');
  var sibling = new GlideAggregate('planned_task');
  sibling.addQuery('parent', task.parent);
  sibling.addNullQuery("orig_sys_id");
  sibling.addQuery('sys_id', '!=', task.sys_id);
  if(sysClassExclusions.length >0 )
  		sibling.addQuery('sys_class_name', 'NOT IN', sysClassExclusions.join(',')); 
  sibling.query();
  var siblingCount = sibling.getRowCount();
  if(siblingCount == 0)
      return;
  if (siblingCount == "1" && sibling.next()) {
      var parent = current.parent.getRefRecord();
      parentStateUtil = new PlannedTaskStateUtil(parent);
      var stateOfTheOnlyRemaininchildState = sibling.state;
      var siblingStateUtil = new PlannedTaskStateUtil(sibling);
      var siblingStateBucket = siblingStateUtil.getBucketForState(sibling.state);
      parent.state = parentStateUtil.getValidStateForBucket(siblingStateBucket, sibling.state);
      parent.update();
  }else{
      var stateUtil = new PlannedTaskStateUtil(task);
      var closeState = stateUtil.getDefaultCloseState();
      PlannedTaskUtilsV2.setParentState(task, true);
  }
};

/*
* Start parent when a child starts
*/
PlannedTaskUtilsV2.startParent = function(task, bucket) {
  if (JSUtil.nil(task.parent))
      return;
  var parent = new GlideRecord("planned_task");
  if (!parent.get(task.parent))
      return;
  
  
  var parentStateUtil = new PlannedTaskStateUtil(parent);
  var state = parentStateUtil.getValidStateForBucket(bucket, task.state);
  if (parent.state == state)
      return;
  
  this.setParentState(task);
  
};

PlannedTaskUtilsV2.isAncestor = function(ancestor, task) {
  if (ancestor.sys_id === task.sys_id) {
      return true;
  }
  
  var path = task;
  var alreadySeen = new Object();
  var i = 0;
  while (!JSUtil.nil(path)) {
      i++;
      if (alreadySeen.hasOwnProperty(path.getValue('sys_id'))) {
          // loop
          break;
      }
      
      if (path.getValue('sys_id') === ancestor.getValue('sys_id')) {
          return true;
      }
      
      alreadySeen[path.getValue('sys_id')] = 1;
      path = path.parent.getRefRecord();
  }
  
  return false;
};

/*
* Set all leaf nodes with no predecessors to same start state as parent based on time constraint
*/
PlannedTaskUtilsV2.startLeaves = function(gr, bucket) {
  
  gs.print("PlannedTaskUtilsV2.startLeaves");
  //var nestedInterval = new SNC.NestedIntervalUtilities("planned_task");
  //var sysIdsToStart = nestedInterval.getLeafNodesForStateChange(gr.sys_id, false); //true : leaves of successor nodes
  var projectMgmtApi = new SNC.PlannedTaskAPI();
  var sysIdsToStart = projectMgmtApi.getLeafNodesForStateChange(gr.sys_id, false);
  gs.print(" PlannedTaskUtilsV2.startLeaves:: is starting " + sysIdsToStart.length + " | leaves - " + bucket + 
      " | sysIds- " + sysIdsToStart.join(","));
  for (var i = 0; i < sysIdsToStart.length; ++i) {
      var taskToStart = new GlideRecord('planned_task');
      var sysId = sysIdsToStart[i];
      taskToStart.get(sysId);
      var taskStateUtil = new PlannedTaskStateUtil(taskToStart);
      var state = taskStateUtil.getValidStateForBucket(bucket, gr.state);
      taskToStart.state = state;
      taskToStart.update();
  }
};

/*
* Set all leaf nodes with no predecessors to same start state as parent based on time constraint
*/
PlannedTaskUtilsV2.closeChildren = function(gr, state, includePercentComplete) {
  gs.log("PlannedTaskUtilsV2.closeChildren");
  // var nestedInterval = new SNC.NestedIntervalUtilities("planned_task");
  var projectMgmtApi = new SNC.PlannedTaskAPI();
  var nowTime = gs.nowDateTime();
  gs.print(" PlannedTaskUtilsV2.closeChildren:: Now time " + nowTime);
  var taskKeyVals = {
      "state": state,
      //"work_end": nowTime,
      //"percent_complete": "100",
      "active": "false",
  	"closed_by": gs.getUserID(),
  	"closed_at": new GlideDateTime()
  };
  if(includePercentComplete)
      taskKeyVals["percent_complete"] = "100"
  // nestedInterval.closeWholeProject(gr, taskKeyVals);
  if(gr.getValue('sys_id') != gr.getValue('top_task') && gr.instanceOf("pm_project"))
  	 projectMgmtApi.closeWholeSubProject(gr, taskKeyVals);
  else
  	projectMgmtApi.closeWholeProject(gr, taskKeyVals);
};

/*
* Open the Project and Its Children
*/
PlannedTaskUtilsV2.openProject = function(gr) {
  gs.log("PlannedTaskUtilsV2.openProject");
  var api = new SNC.PlannedTaskAPI();
  var plannedTaskStateUtil = new PlannedTaskStateUtil(gr);
  if(gr.getValue('sys_id') != gr.getValue('top_task') && gr.instanceOf("pm_project"))
  	api.updateSubProjectState(gr, {}, plannedTaskStateUtil.getDefaultOpenState());
  else
  	api.updateProjectState(gr, {}, plannedTaskStateUtil.getDefaultOpenState());
};

PlannedTaskUtilsV2.getParentStartOnBehavior =  function(parentGr){
  PPMDebug.log('PlannedTaskUtilsV2.getParentStartOnBehavior evaluating '+ parentGr.getUniqueValue())
  var parentCannotBeStartOn = false; // default behavior
  var preEngineHandler = new PreEngineHandlers();
  var enginePreferences = preEngineHandler.getEnginePreferencesJSON(parentGr.getValue('sys_class_name'));
  if (enginePreferences != null && enginePreferences.hasOwnProperty('parent_cannot_be_start_on')) {
  	parentCannotBeStartOn = enginePreferences.parent_cannot_be_start_on;
  }	
  PPMDebug.log('parentCannotBeStartOn value is '+ parentCannotBeStartOn);
  return parentCannotBeStartOn;
};

Sys ID

d5938c22eb810100b749215df106fe9c

Offical Documentation

Official Docs: