Created
December 4, 2015 16:46
-
-
Save jmbauguess/910ae551f58664ce5c4c to your computer and use it in GitHub Desktop.
An updated version of ChangeTasker, which handles dates and times
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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' | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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