Skip to content

Instantly share code, notes, and snippets.

@jmbauguess
Created December 4, 2015 16:46
Show Gist options
  • Save jmbauguess/910ae551f58664ce5c4c to your computer and use it in GitHub Desktop.
Save jmbauguess/910ae551f58664ce5c4c to your computer and use it in GitHub Desktop.
An updated version of ChangeTasker, which handles dates and times
var ct = new ChangeTasker(current),
cm = new ChangeManagementUtil();
if (current.isNewRecord()) {
ct.run();
}
if (ct.dateFieldChanges(current)) {
ct.updateDueDatesOnTasks();
}
if (current.approval.changesTo("approved")) {
ct.runOnApproval();
}
if (current.cmdb_ci.changes() || current.u_sox_project_framework_.changes() ||
current.cmdb_ci.u_sox_governed_yn.changes()) {
ct.run();
}
if (current.type.changes() && !current.isNewRecord()) {
ct.runOnTypeChange();
}
if (ct.isEmergencyGoingBack(current.type, previous.u_life_cycle_status, current.u_life_cycle_status)) {
ct.resetEmergencyApprovalTask();
}
if (ct.isInfrastructureGoingBack(previous.u_life_cycle_status, current.u_life_cycle_status) && cm.isInfrastructure(current.type)) {
ct.infrastructureGoBack();
}
/**
* @description A class for handling creation, updating, and deleting of change tasks
* @namespace ChangeTasker
* @type {Class}
*/
var ChangeTasker = Class.create();
ChangeTasker.prototype = {
/**
* @description A list of date fields we care about on change requests/change tasks
* @type {Object}
*/
CHANGE_DATE_FIELDS: ['due_date', 'start_date', 'work_start', 'u_release_due_date', 'work_end', 'end_date', 'opened_at'],
/**
* @description A list of date fields that actually appear on the change form
* @type {Object}
*/
CHANGE_FORM_FIELDS: ['start_date', 'end_date', 'requested_by_date', 'u_release_due_date', 'work_start', 'work_end'],
/**
* @description A list of date fields that are for a change task
* @type {Object}
*/
CHANGE_TASK_FIELDS: ['due_date', 'opened_at', 'closed_at'],
/**
* @description initializes values for the class
* @param {GlideRecord} change Change Request
*/
initialize: function(change) {
this.change = change;
this.changeType = change.type;
this.ci = change.cmdb_ci;
},
/**
* @description Sets the change request for the object
* @param {GlideRecord} change The Change Request
*/
setChange: function(change) {
this.change = change;
this.changeType = change.type;
this.ci = change.cmdb_ci;
},
/**
* @description Main Method
*/
run: function() {
this.createTasksByType('create');
this.runSOXTasks();
this.runSOXFrameworkTasks();
this.createTasksByType('dependent');
},
/**
* @description Main Method for when a change request becomes approved
*/
runOnApproval: function() {
this.createTasksByType('approval');
this.createTasksByType('dependent');
},
/**
* @description Runs if the type of a change request is changed
*/
runOnTypeChange: function() {
this._deleteOldTasks();
this.createTasksByType('create');
},
/**
* @description Marks task template objects as created if the change task related to it already exists for a change
* @param {GlideRecord} tasks A change task
* @param {Object} templates A list of task templates
*/
markTemplateTasksCreated: function(tasks, templates) {
for (var task in templates) {
if (templates.hasOwnProperty(task)) {
if (tasks.u_task_template == templates[task].u_task_template ||
tasks.short_description == templates[task].short_description) {
templates[task].created = true;
}
}
}
},
/**
* @description Compares current change tasks with a list of sox change tasks to see if any need to be generated
*/
runSOXTasks: function() {
var soxTasks = this._getSoxTasks(),
tasks = this.getCurrentTasks(this.change);
while (tasks.next()) {
this.markTemplateTasksCreated(tasks, soxTasks);
}
for (var task in soxTasks) {
//If the task is not created and we're still sox governed
//If the task is created and we're not sox anymore, delete the tasks
if (soxTasks[task].created != true && this._shouldSOXTasksBeMade() &&
this.isDependencyFulfilled(soxTasks[task])) {
this.createAChangeTask(soxTasks[task]);
} else if (!this._shouldSOXTasksBeMade()) {
var changeTasks = new GlideRecord('change_task');
changeTasks.addQuery('change_request', this.change.sys_id);
changeTasks.addQuery('u_task_template', soxTasks[task].u_task_template.toString());
changeTasks.query();
if (changeTasks.next()) {
changeTasks.deleteRecord();
}
}
}
},
runSOXFrameworkTasks: function() {
var soxTasks = this._getSoxFrameworkTasks(),
tasks = this.getCurrentTasks(this.change);
while (tasks.next()) {
this.markTemplateTasksCreated(tasks, soxTasks);
}
for (var task in soxTasks) {
//If the task is not created and we're still sox governed
//If the task is created and we're not sox anymore, delete the tasks
if (soxTasks[task].created != true && this._shouldSOXFrameworkTasksBeMade() &&
this.isDependencyFulfilled(soxTasks[task])) {
this.createAChangeTask(soxTasks[task]);
} else if (!this._shouldSOXFrameworkTasksBeMade()) {
var changeTasks = new GlideRecord('change_task');
changeTasks.addQuery('change_request', this.change.sys_id);
changeTasks.addQuery('u_task_template', soxTasks[task].u_task_template.toString());
changeTasks.query();
if (changeTasks.next()) {
changeTasks.deleteRecord();
}
}
}
},
/**
* @description Creates a change task record
* @param {Object} task A task template
* @return {String} The sys_id of the created task
*/
createAChangeTask: function(task) {
var changeTask = new GlideRecord('change_task');
changeTask.initialize();
changeTask.short_description = String(task.short_description);
changeTask.description = String(task.description);
changeTask.assignment_group = String(task.assignment_group);
changeTask.assigned_to = String(task.assigned_to);
changeTask.change_request = String(this.change.sys_id);
changeTask.u_task_template = String(task.u_task_template);
changeTask.due_date = task.due_date;
return changeTask.insert();
},
/**
* @description Determines if the dependent task is completed (or exists)
* @param {Object} taskObject An object representing a task template to examine
* @return {Boolean} True if the dependencies are fulfilled
*/
isDependencyFulfilled: function(object) {
if (object.dependent == '') {
return true;
}
var changeTasks = new GlideRecord('change_task'),
dependents = object.dependent;
changeTasks.addQuery('parent', this.change.sys_id);
changeTasks.addQuery('u_task_template', 'IN', object.dependent);
changeTasks.addEncodedQuery('stateIN3,4,7');
changeTasks.query();
if (changeTasks.next()) {
if (dependents.split(',').length == changeTasks.getRowCount()) {
return true;
}
}
return false;
},
/**
* @description Gets non-SOX task templates by creation type
* @param {String} type The creation type
* @return {Object} An array of tasks data
*/
getTaskTemplatesByCreationType: function(type) {
var taskArray = [],
tasks = new GlideRecord('u_change_tasks');
tasks.addQuery('u_sox', false);
tasks.addQuery('u_framework', false);
tasks.addQuery('u_type', this.changeType);
tasks.addQuery('u_creation_method', type);
if (this.ci != '') {
tasks.addQuery('u_ci', this.ci);
}
tasks.query();
while (tasks.next()) {
taskArray.push(this.makeTaskObject(tasks));
}
return taskArray;
},
/**
* @description runs to deal with SOX related change requests
* @return {Array} an array of tasks data
*/
_getSoxTasks: function() {
var taskArray = [];
var tasks = new GlideRecord('u_change_tasks');
tasks.addQuery('u_sox', true);
tasks.addQuery('u_type', this.change.type);
tasks.query();
while (tasks.next()) {
taskArray.push(this.makeTaskObject(tasks));
}
return taskArray;
},
/**
* @description runs to deal with SOX Framework related change requests
* @return {Array} an array of tasks data
*/
_getSoxFrameworkTasks: function() {
var taskArray = [];
var tasks = new GlideRecord('u_change_tasks');
tasks.addQuery('u_framework', true);
tasks.addQuery('u_type', this.change.type);
tasks.query();
while (tasks.next()) {
taskArray.push(this.makeTaskObject(tasks));
}
return taskArray;
},
/**
* @description Creates timed change tasks for a given change request
* @param {GlideRecord} changeRequest A change request
*/
createTimedTasks: function(changeRequest) {
var timedTasks = this.getTaskTemplatesByCreationType('timed'),
changeTasks = new GlideRecord('change_task');
changeTasks.addQuery('parent', changeRequest.sys_id);
changeTasks.query();
while (changeTasks.next()) {
this.markTemplateTasksCreated(changeTasks, timedTasks);
}
for (var task in timedTasks) {
if (timedTasks.hasOwnProperty(task)) {
if (timedTasks[task].u_table_type == 'change_request') {
if (!timedTasks[task].created && this.isTimeToMake(timedTasks[task], changeRequest)) {
this.createAChangeTask(timedTasks[task]);
}
} else if (timedTasks[task].u_table_type == 'change_task') {
var changeTask = this.getRelatedChangeTask(timedTasks[task].u_change_task, changeRequest);
while (changeTask.next()) {
if (!timedTasks[task].created && this.isTimeToMake(timedTasks[task], changeTask)) {
this.createAChangeTask(timedTasks[task]);
}
}
}
}
}
},
/**
* @description Determines if it is appropriate to generate a timed change task
* @param {Object} taskTemplate A change task template
* @param {GlideRecord} changeRequest A change request or task record
* @return {Boolean} True if the task should be generated
*/
isTimeToMake: function(taskTemplate, changeRequest) {
var date = new GlideDateTime(),
changeDate = new GlideDateTime(changeRequest[taskTemplate.u_change_date_field]);
changeDate.addDays(taskTemplate.u_change_days);
if (changeRequest.getValue(taskTemplate.u_change_date_field) == '') {
return false;
}
if (changeDate.compareTo(date) == -1) {
return true;
}
return false;
},
/**
* @description Gets a change task record related to a template and change request
* @param {String} template The sys_id of a task template
* @param {GlideRecord} changeRequest A change request
* @return {GlideRecord} A change task
*/
getRelatedChangeTask: function(template, changeRequest) {
var changeTask = new GlideRecord('change_task');
changeTask.addQuery('parent', changeRequest.sys_id);
changeTask.addQuery('u_task_template', template);
changeTask.query();
return changeTask;
},
/**
* @description Makes an object of task template data given a task template record
* @param {GlideRecord} taskTemplateRecord A task template record
* @return {Object} an object containing task template data
*/
makeTaskObject: function(taskTemplateRecord) {
var dueDate = '';
if (taskTemplateRecord.u_base_due_date_on != 'nothing') {
dueDate = this.generateDueDate(taskTemplateRecord);
}
return {
'short_description': taskTemplateRecord.u_short_description + '',
'assignment_group': taskTemplateRecord.u_assignment_group + '',
'description': taskTemplateRecord.u_description + '',
'assigned_to': taskTemplateRecord.u_assigned_to + '',
'u_task_template' : taskTemplateRecord.sys_id + '',
'dependent' : taskTemplateRecord.u_dependent_on + '',
'u_table_type' : taskTemplateRecord.u_table_type + '',
'u_change_task' : taskTemplateRecord.u_change_task + '',
'u_change_date_field' : taskTemplateRecord.u_change_date_field.element + '',
'u_change_days' : taskTemplateRecord.u_change_days + '',
'due_date' : dueDate,
'created' : false
};
},
/**
* @description generates a due date for the change task to create, based on information in the template
* @param {GlideRecord} taskTemplate The task template record
* @return {GlideDateTime} A due date for the task to be created
*/
generateDueDate: function(taskTemplate) {
var date;
if (taskTemplate.u_base_due_date_on == 'change_request') {
date = new GlideDateTime(this.change.getValue(taskTemplate.u_due_date_field.element));
date.addDays(taskTemplate.u_due_date_days);
} else if (taskTemplate.u_base_due_date_on == 'change_task') {
var changeTask = this.getRelatedChangeTask(taskTemplate, this.change);
if (changeTask.next()) {
if (changeTask[taskTemplate.u_due_date_field]) {
date = new GlideDateTime(changeTask.getValue(taskTemplate.u_due_date_field.element));
date.addDays(taskTemplate.u_due_date_days);
}
}
} else if (taskTemplate.u_base_due_date_on == "static") {
date = new GlideDateTime();
date.addDays(taskTemplate.u_due_date_days);
}
return date;
},
/**
* @description Updates the due dates for all tasks related to a change request
*/
updateDueDatesOnTasks: function() {
var tasks = this.getCurrentTasks();
while (tasks.next()) {
this.updateDueDateOnTask(tasks);
}
},
/**
* @description Updates the due date for a single change task
* @param {GlideRecord} task A change task
* @return {String} The sys_id of the updated change task
*/
updateDueDateOnTask: function(task) {
var template = new GlideRecord('u_change_tasks');
if (template.get(task.u_task_template)) {
task.due_date = this.generateDueDate(template);
return task.update();
}
},
/**
* @description Determines if a date field changes
* @param {GlideRecord} change A change task or change request
* @return {Boolean} True if one of the date fields changed
*/
dateFieldChanges: function(change) {
for (var date in this.CHANGE_DATE_FIELDS) {
if (this.CHANGE_DATE_FIELDS.hasOwnProperty(date)) {
if (change[this.CHANGE_DATE_FIELDS[date]].changes()) {
return true;
}
}
}
return false;
},
/**
* @description Gets a list of change tasks given a change request
* @return {GlideRecord} the change tasks related to a change
*/
getCurrentTasks: function() {
var tasks = new GlideRecord('change_task');
tasks.addQuery('change_request', this.change.sys_id);
tasks.query();
return tasks;
},
/**
* @description Deletes all change tasks related to the current change request, but only if they are inactive
*/
_deleteOldTasks: function() {
var changeTasks = new GlideRecord('change_task');
changeTasks.addQuery('change_request', this.change.sys_id);
changeTasks.addActiveQuery();
changeTasks.query();
while (changeTasks.next()){
changeTasks.deleteRecord();
}
},
/**
* @description Creates change tasks by a creation type
* @param {String} type The creation type
*/
createTasksByType: function(type) {
var tasks = this.getCurrentTasks(this.change),
templates = this.getTaskTemplatesByCreationType(type);
if (tasks.getRowCount() != 0) {
while (tasks.next()) {
this.markTemplateTasksCreated(tasks, templates);
}
}
for (var task in templates) {
if (templates.hasOwnProperty(task)) {
if (!templates[task].created &&
this.isDependencyFulfilled(templates[task])) {
this.createAChangeTask(templates[task]);
}
}
}
},
/**
* @description Conditional for when SOX change tasks should be created
* @return {Boolean} true if the CI is SOX governed and the change request uses SOX project framework
*/
_shouldSOXTasksBeMade: function() {
return this.change.cmdb_ci.u_sox_governed_yn == "Yes" ? true : false;
},
/**
* @description Conditional for when SOX Framework change tasks should be created
* @return {Boolean} true if the CI is SOX governed and the change request uses SOX project framework
*/
_shouldSOXFrameworkTasksBeMade: function() {
return this.change.cmdb_ci.u_sox_governed_yn == "Yes" && this.change.u_sox_project_framework_ == "Yes" ? true : false;
},
/**
* @description Resets the emergency approval task to open
*/
resetEmergencyApprovalTask: function() {
var changeTask = new GlideRecord('change_task');
changeTask.addQuery('change_request', this.change.sys_id);
changeTask.addQuery('short_description', 'Get Verbal Approval from Change Management');
changeTask.query();
if (changeTask.next()){
changeTask.state = 1;
changeTask.update();
}
},
/**
* @description Conditional for a Business Rule: true if the emergency change request moves from Scheduled to Draft
* @param {String} type The type of change request
* @param {String} oldLCS The old life cycle status
* @param {String} newLCS the new life cycle status
* @return {Boolean} true if the change request is emergency and moves back to Draft from Scheduled
*/
isEmergencyGoingBack: function(type, oldLCS, newLCS) {
return type == "Emergency" && newLCS == "Draft" && oldLCS == "Scheduled" ? true : false;
},
/**
* @description Determines if the change is an infrastructure type
* @param {String} type A change type
* @return {Boolean} True if it's infrastructure
*/
isInfrastructure: function(type) {
return type != "Std-Application" && type != "Emergency";
},
/**
* @description Determines if the change is not an infrastructure type
* @param {String} type A change type
* @return {Boolean} True if it's not infrastructure
*/
isNonInfrastructure: function(type) {
return type == "Std-Application" || type == "Emergency";
},
/**
* isInfrastructureScheduled Conditional for a business rule: true if it's an infrastructure record moving to scheduled
* @param {String} type The type of change request
* @return {Boolean} true if the change request is infrastructure and scheduled
*/
isInfrastructureScheduled: function(type, isScheduled) {
return isScheduled && this.isInfrastructure(type) ? true : false;
},
/**
* @description Conditional for a business rule: true if it's a new non-infrastructure record
* @return {Boolean} true if it's a new record that's not an infrastructure type
*/
isNonInfrastructureCreated: function(type) {
return current.isNewRecord() && this.isNonInfrastructure(type) ? true : false;
},
/**
* @description Conditional for business rule: tests if a record is move back from scheduled
* @param {String} oldLCS The old life cycle status
* @param {String} newLCS the new life cycle status
* @return {Boolean} true if the record is going back
*/
isInfrastructureGoingBack: function(oldLCS, newLCS) {
return oldLCS == "Scheduled" &&
(newLCS == "Draft" || newLCS == "Planning in Progress") ? true : false;
},
/**
* @description What action to take if Infrastructure changes move back in LCS
*/
infrastructureGoBack: function() {
this._deleteOldTasks();
},
/**
* @description returns the reference qualifier for Change Task dependent on field
* @param {GlideRecord} The current record
* @return {String} The reference qualifier for the dependent on
*/
referenceQual: function(current) {
return 'u_type=' + current.u_type;
},
/**
* @description Returns the reference qualifier for the Change Date Field
* @param {GlideRecord} The current record
* @return {String} The reference qualifier for the change date field
*/
dateFieldReferenceQual: function(current) {
if (current.u_table_type == 'change_request') {
return 'name=task^ORname=' + current.u_table_type + '^internal_type=glide_date_time^elementIN' + this.CHANGE_FORM_FIELDS.toString();
} else {
return 'name=task^ORname=' + current.u_table_type + '^internal_type=glide_date_time^elementIN' + this.CHANGE_TASK_FIELDS.toString();
}
},
/**
* @description Returns the reference qualifier for the Change Date Field
* @param {GlideRecord} The current record
* @return {String} The reference qualifier for the change date field
*/
dueDateFieldReferenceQual: function(current) {
return 'name=task^ORname=' + current.u_base_due_date_on + '^internal_type=glide_date_time^EQ';
},
/**
* @description Determines if there are future tasks for a change request
* @return {Boolean} True if the future tasks are made; false if any have yet to be created
*/
areTheFutureTasksMade: function() {
var tasks = this._getTimedTasks(),
currentTasks = this.getCurrentTasks();
while(currentTasks.next()) {
this.markTemplateTasksCreated(currentTasks, tasks);
}
for (var task in tasks) {
if (tasks.hasOwnProperty(task)) {
if (tasks[task].created == false) {
return false;
}
}
}
return true;
},
type: 'ChangeTasker'
};
//change_task
function onAfter(current, previous) {
var change = getChange(current.parent),
tasker = new ChangeTasker(change);
tasker.run();
tasker.createTimedTasks(change);
if (tasker.dateFieldChanges(current)) {
tasker.updateDueDatesOnTasks();
}
function getChange(sysid) {
var change = new GlideRecord('change_request');
change.get(sysid);
return change;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment