Name

global.InterProjectTaskDeletionHandler

Description

Called on task deletion - if task and relation is getting deleted, check if relation is shadow relation, then remove the inter project depedency

Script

var InterProjectTaskDeletionHandler = Class.create();
InterProjectTaskDeletionHandler.prototype = {
  initialize: function() {
      this.api = new SNC.PlannedTaskAPI();
  },
  
  _getPayload: function(deletedTasksAndRelations) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler._getPayload -> " + deletedTasksAndRelations);
      var data;
      if ( JSUtil.nil(deletedTasksAndRelations) ) {
          data = {};
          data.tasks = [];
          data.links = [];
          return data;
      }
      data = (new JSON()).decode(deletedTasksAndRelations);
      if ( JSUtil.nil(data.tasks) )
          data.tasks = [];
      if ( JSUtil.nil(data.relations) )
          data.relations = [];
      
      data.notificationFilter = '';
      
      data.relations.forEach(function(relation) {
          if ( JSUtil.notNil(relation.orig_sys_id) ) {
              relation.shadow = true;             
              var result = data.tasks.filter(function(task) { return task.sys_id == relation.child; });
              PPMDebug.log("InterProjectTaskDeletionHandler._getPayload result - child -> " + (new JSON()).encode(result));
              if (  result.length > 0 ) {
                  if ( result[0].shadow == true ) {
                      relation.nonShadowEndPoint = 'parent'; //shadow task in pred project deleted
                  }
                  else {
                      data.notificationFilter = 'task=' + relation.child; //actual task in succ project deleted
                      relation.nonShadowEndPoint = 'child';
                  }
              }
              result = data.tasks.filter(function(task) { return task.sys_id == relation.parent; });
              PPMDebug.log("InterProjectTaskDeletionHandler._getPayload result - parent -> " + (new JSON()).encode(result));
              if ( result.length > 0 ) {
                  if ( result[0].shadow == true ) {
                      data.notificationFilter = 'task=' + relation.child; //shadow task in succ project deleted
                      relation.nonShadowEndPoint = 'child';
                  }
                  else {
                      data.notificationFilter = 'source=' + relation.parent; // actual task in pred project deleted
                      relation.nonShadowEndPoint = 'parent';                  
                  }
              }
          }
      });
      PPMDebug.log("Return InterProjectTaskDeletionHandler._getPayload -> " + (new JSON()).encode(data));
      return data;
  },

  process: function(deletedTasksAndRelations) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler.process -> " + deletedTasksAndRelations);
      var data = this._getPayload(deletedTasksAndRelations);
      var relationsToDelete = [];
      var tasksToDelete = [];
      var projectsToRecalculate = [];
      var self = this;
      
      data.relations.forEach(function(relation) {
          if ( relation.shadow === true ) {
              relationsToDelete.push(relation.orig_sys_id);
              var relations = ShadowTaskQueryHelper.findShadowRelations(relation.orig_sys_id);
              while ( relations.next() )
                  relationsToDelete.push(relations.getValue('sys_id'));
              
              PPMDebug.log("InterProjectTaskDeletionHandler.process relation -> " + (new JSON()).encode(relation));
              var gr = new GlideRecord('planned_task');
              var taskId;
              if ( relation.nonShadowEndPoint == 'child' )
                  taskId = relation.child;
              else
                  taskId = relation.parent;
              if ( gr.get('orig_sys_id', taskId) ) {
                  PPMDebug.log("InterProjectTaskDeletionHandler.process - delete shadow -> " + gr.getValue("number") + 
                      " - " + gr.getValue("short_description") + " - " + gr.top_task.short_description);
                  // check if the task has other relations on the task
                  var relationService = new PlannedTaskRelationDBService();
                  allRelations = relationService.allRelations(gr.getValue("sys_id"), [relation.id || relation.sys_id]);
                  if(JSUtil.nil(allRelations) || allRelations.getRowCount() == 0) {
                      tasksToDelete.push(gr.getValue('sys_id'));
                      projectsToRecalculate.push(gr.getValue('top_task'));
                  }
              }
              var result = data.tasks.filter(function(task) { return task.sys_id == relation.child; });   
              if ( result.length > 0 )
                  taskId = relation.parent;
              else
                  taskId = relation.child;
              if ( self._taskShouldBeDeleted(taskId) )
                  tasksToDelete.push(taskId);
          }
      });

      //check if any task is not deleted yet due to cascade delete
      var projectsToBeRecalculated = [];
      data.tasks.forEach(function(task) {
          if ( task.shadow !== true ) {
             var gr = new GlideRecord('planned_task');
             gr.addQuery('orig_sys_id', task.sys_id);
             gr.query();
             while(gr.next()){  // check if originated sys_id
               tasksToDelete.push(gr.getValue("sys_id"));
               var subTreeRoot = gr.getValue("sub_tree_root");
               if(projectsToBeRecalculated.indexOf(subTreeRoot) == -1){
                  projectsToBeRecalculated.push(subTreeRoot);
               }
             }
          }
      });

      projectsToBeRecalculated.forEach(function(projectId){
          InterProjectEventManager.raiseFullRecalculateEvent(projectId);
      });


      this.deleteTasks(tasksToDelete);
      this.deleteRelations(relationsToDelete);
      this.recalculateProjects(projectsToRecalculate);
      this.deleteNotifications(data.notificationFilter);
  },
  
  _taskShouldBeDeleted: function(taskId) {
      var gr = new GlideRecord('planned_task');
      if ( gr.get(taskId) ) {
          if ( JSUtil.notNil(gr.getValue('orig_sys_id')) ) {
              var rel = new GlideRecord('planned_task_rel_planned_task');
              var qc = rel.addQuery('parent', taskId);
              qc.addOrCondition('child', taskId);
              rel.query();
              return (rel.getRowCount() == 0);
          }
      }
      return false;
  },
  
  deleteTasks: function(tasksToDelete) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler.deleteTasks -> " + tasksToDelete.join(","));
      var uniqueTopTasks = [], arrayUtil = new ArrayUtil();
      tasksToDelete.forEach(function(task) {          
          var gr = new GlideRecord('planned_task');
          if ( gr.get(task) ) {
              gr = new GlideRecord(gr.getValue('sys_class_name')); //set right class name, else workflow would fire on delete
              gr.get(task);
              if(JSUtil.notNil(gr.getValue("top_task"))) {
                  if(!arrayUtil.contains(uniqueTopTasks, gr.getValue("top_task")))
                      uniqueTopTasks.push(gr.getValue("top_task"));
              }
              gr.setWorkflow(false);
              gr.deleteRecord();              
          }
      });
      PPMDebug.log("Into InterProjectTaskDeletionHandler.uniqueTopTasks -> " + uniqueTopTasks.join(","));
      if(uniqueTopTasks.length > 0) {
          uniqueTopTasks.forEach(function(topTaskId) {
              this.api.validateWbs(topTaskId);
          });
      }
  },
  
  deleteRelations: function(relationsToDelete) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler.deleteRelations -> " + relationsToDelete.join(","));
      relationsToDelete.forEach(function(relation) {
          var gr = new GlideRecord('planned_task_rel_planned_task');
          if(gr.get(relation)) {
              // gr.setWorkflow(false); // if relation exists delete the relation
              gr.deleteRecord();
          }
      });
  },
  
  deleteNotifications: function(filter) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler.deleteNotifications -> " + filter);
      if ( JSUtil.notNil(filter) ) {
          var gr = new GlideRecord('planned_task_notification');
          gr.addEncodedQuery(filter);
          gr.setWorkflow(false);
          gr.deleteMultiple();
      }
  },
  
  recalculateProjects :function(projectsToRecalculate) {
      PPMDebug.log("Into InterProjectTaskDeletionHandler.recalculateProjects -> " + projectsToRecalculate.join(","));
      var uniqueProjects = projectsToRecalculate.filter(function(item, pos) {
          return projectsToRecalculate.indexOf(item) == pos;
      });
      uniqueProjects.forEach(function(projectId) {
          this.api.validateWbs(projectId); // re-vaidate on the safer side
          InterProjectEventManager.raiseFullRecalculateEvent(projectId);
      });     
  },
  
  type: 'InterProjectTaskDeletionHandler'
};

Sys ID

48adad319fd22200598a5bb0657fcf38

Offical Documentation

Official Docs: