Name
global.ChangeRequestSNC
Description
Base client API extended by ChangeRequest This API supports Model and Legacy new/old type based Change Requests.
Script
var ChangeRequestSNC = Class.create();
// Only for legacy types. Not for models as enforcement is done in the model
ChangeRequestSNC.ENFORCE_DATA_REQ_PROP = "com.snc.change_management.enforce_data_requirements";
ChangeRequestSNC.TYPE_COMPATIBILITY = "com.snc.change_management.change_model.type_compatibility";
ChangeRequestSNC.MANAGE_WORKFLOW = "com.snc.change_management.change_model.manage_workflow";
ChangeRequestSNC.CHANGE_REQUEST_FROM_NEW = "CHANGE_REQUEST_FROM_NEW";
// These constants are used for support of classic 'Mode 1' change types
ChangeRequestSNC.NORMAL = (function(pm) {
return pm.isActive("com.snc.change_management") ? "normal" : "Comprehensive";
})(pm);
ChangeRequestSNC.STANDARD = (function(pm) {
return pm.isActive("com.snc.change_management") ? "standard" : "Routine";
})(pm);
ChangeRequestSNC.EMERGENCY = (function(pm) {
return pm.isActive("com.snc.change_management") ? "emergency" : "Emergency";
})(pm);
// These states are only used to provide the set*, is*, to*, changesTo/From* legacy methods
ChangeRequestSNC.LEGACY_STATE = (function(pm) {
var stateModelActive = pm.isActive("com.snc.change_management.state_model");
var foundationActive = pm.isActive("com.snc.change_management.foundation");
// If state model or foundation is installed
if (stateModelActive || foundationActive)
return {
"NEW": "-5",
"ASSESS": "-4",
"AUTHORIZE": "-3",
"SCHEDULED": "-2",
"IMPLEMENT": "-1",
"REVIEW": "0",
"CLOSED": "3",
"CANCELED": "4"
};
//if the state model or foundation are not installed use old states
return {
"NEW": ["-5","1"], //Pending || Open
"ASSESS": null,
"AUTHORIZE": null,
"SCHEDULED": null,
"IMPLEMENT": "2", // Work in Progress
"REVIEW": "0",
"CLOSED": ["3","4"], //Closed successful,unsuccessful
"CANCELED": "7"
};
})(pm);
ChangeRequestSNC.prototype = {
APPROVAL: {
REQUESTED: "requested",
APPROVED: "approved",
REJECTED: "rejected",
NOT_REQUESTED: "not requested"
},
STATE: "state",
SUCCESSFUL: "successful",
UNSUCCESSFUL: "unsuccessful",
SUCCESSFUL_ISSUES: "successful_issues",
REQUESTED: "requested",
APPROVED: "approved",
REJECTED: "rejected",
NOT_REQUESTED: "not requested",
EMERGENCY_WORKFLOW: "Change Request - Emergency",
STANDARD_WORKFLOW: "Change Request - Standard",
NORMAL_WORKFLOW: "Change Request - Normal",
initialize: function(changeGr) {
this._log = new GSLog(ChangeCommon.LOG_PROPERTY, this.type);
this._gr = changeGr;
this._typeCompatibility = gs.getProperty(ChangeRequestSNC.TYPE_COMPATIBILITY, "false") === "true";
this.plugin = {
"change_management": pm.isActive("com.snc.change_management"),
"foundation": pm.isActive("com.snc.change_management.foundation"),
"state_model": pm.isActive("com.snc.change_management.state_model"),
"change_model": pm.isActive("com.snc.change_management.change_model"),
"best_practice": {
"jakarta": pm.isActive("com.snc.best_practice.change.jakarta"),
"kingston": pm.isActive("com.snc.best_practice.change.kingston")
}
};
this._api = null; // The API in use
// Used to checks if the gr has been navigated without instanciating a new object
this._idChk = null;
},
// Returns the appropriate API to use for the given change request
_getAPI: function() {
if (this._api !== null && this._idChk === this._gr.getUniqueValue())
return this._api;
this._idChk = this._gr.getUniqueValue();
if (this.plugin.change_model && this._gr.isValidField("chg_model") && !this._gr.chg_model.nil()) {
this._api = new ChangeModelChgReqAPI(this._gr);
return this._api;
}
if (this.plugin.state_model) {
this._api = new ChangeTypeChgReqAPI(this._gr);
return this._api;
}
this._api = new ChangeRequestChgReqAPI(this._gr);
return this._api;
},
// Returns the value of field configured to hold state for this type/model of CHange Request
getState: function() {
return this._gr.getValue(this.getStateFieldName());
},
// New Model Methods
//Returns the name of the field configured to hold state for the type/model of this Change Request
getStateFieldName: function() {
var api = this._getAPI();
if (!api.getStateFieldName)
return this.STATE;
return api.getStateFieldName();
},
// Returns the initial state value for the type/model of this Change Request
getInitialState: function() {
var api = this._getAPI();
if (!api.getInitialState) {
var defaultValue = sys_meta.change_request.state.default_value;
if (defaultValue === '' || defaultValue.startsWith('javascript:'))
return "-5"; //New in both state models
else
return defaultValue;
}
return api.getInitialState();
},
// Returns true if this Change Request is in the initial state for this type/model
isInitialState: function() {
return this._getAPI().isInitialState();
},
//Returns true if the Change Request changes to the initial state
changesToInitialState: function() {
var api = this._getAPI();
if (api.changesToInitialState)
return api.changesToInitialState();
return api.changesToNew();
},
//Returns true if the Change Request changes from the initial state
changesFromInitialState: function() {
var api = this._getAPI();
if (api.changesFromInitialState)
return api.changesFromInitialState();
return api.changesFromNew();
},
// Reverts the Change Request to the initial state defined for this type/model
revertToInitialState: function() {
return this._getAPI().revertToInitialState();
},
// Returns true if this Change Request is in a Terminal State. A Terminal State is defined as
// a state without any transitions.
isTerminalState: function() {
return this._getAPI().isTerminalState();
},
// Returns true if the Change Request state is equivalent to the provided state
isState: function(stateValue) {
return this._getAPI().isState(stateValue);
},
// Returns true if the provided state is valid as a transition for the current Change Request
isNextState: function(stateValue) {
return this._getAPI().isNextState(stateValue);
},
// Returns true if the provided state is valid as a non-automated transition for the current Change Request
// Defaults to isNextState
isNextManualState: function(stateValue) {
var api = this._getAPI();
if (api.isNextManualState)
return api.isNextManualState(stateValue);
return this.isNextState(stateValue);
},
// Returns a list of all transition states available from the Change Request's current state
getNextStates: function() {
return this._getAPI().getNextStates();
},
// Returns a list of manual transition states available for the Change Request's current state
// Defaults to getNextStates
getNextManualStates: function() {
var api = this._getAPI();
if (api.getNextManualStates)
return api.getNextManualStates();
return this.getNextStates();
},
// Sets the state field configured for this Change Request to the provided value
// if the Change Request can move to that value
moveTo: function(stateValue) {
return this._getAPI().moveTo(stateValue);
},
//Returns true if the Change Request can move from it's current state to the provided state
canMoveTo: function(stateValue) {
return this._getAPI().canMoveTo(stateValue);
},
/* Evaluates a move to the provided state from the Change Request's current state
* This method returns the evaluation information for the state move. As a minimum
* it will return the following structure:
* {
* from_state: "current state value",
* to_state: "transition state value",
* transiton_available: true/false
* }
*
* If Change Models are being used aditional information is returned:
* {
* sys_id: "sys_id of the sttrm_state_transition evaluated",
* display_value: "Display Value of the sttrm_state_transition",
* from_state: "current state value",
* to_state: "transition state value",
* transition_available: true/false,
* conditions: [ // An array of conditions evaluated for the transition
* {
* "passed": true/false,
* "condition": {
* "name": "Name given to the condition",
* "description": "Description of the condition",
* "sys_id": "sys_id of the condition"
* }
* }
* ...
* ]
* }
*/
evaluateMoveTo: function(stateValue, returnAll) {
return this._getAPI().evaluateMoveTo(stateValue, returnAll);
},
// Returns true if the Change Request is in the defined 'implementation' state
canImplement: function() {
var api = this._getAPI();
if (api.canImplement)
return api.canImplement();
return api.isImplement();
},
// Legacy state specific methods. In all cases use the new state agnostic methods (above) instead.
isNew: function() {
return this._getAPI().isNew();
},
changesToNew: function() {
return this._getAPI().changesToNew();
},
changesFromNew: function() {
return this._getAPI().changesFromNew();
},
setNew: function() {
return this._getAPI().setNew();
},
toNew: function() {
return this._getAPI().toNew();
},
// Legacy method from type change requests. Use revertToInitialState with an update instead.
revertToNew: function() {
var api = this._getAPI();
if (!api.revertToNew) {
if (api.revertToInitialState())
return !!this._gr.update();
return false;
}
return api.revertToNew();
},
/**
* Assess -- used internally by the change request workflows.
*/
isAssess: function() {
return this._getAPI().isAssess();
},
changesToAssess: function() {
return this._getAPI().changesToAssess();
},
setAssess: function() {
return this._getAPI().setAssess();
},
assess: function() {
return this._getAPI().assess();
},
isAuthorize: function() {
return this._getAPI().isAuthorize();
},
changesToAuthorize: function() {
return this._getAPI().changesToAuthorize();
},
setAuthorize: function() {
return this._getAPI().setAuthorize();
},
authorize: function() {
return this._getAPI().authorize();
},
isScheduled: function() {
return this._getAPI().isScheduled();
},
changesToScheduled: function() {
return this._getAPI().changesToScheduled();
},
setScheduled: function() {
return this._getAPI().setScheduled();
},
scheduled: function() {
return this._getAPI().scheduled();
},
isImplement: function() {
return this._getAPI().isImplement();
},
changesToImplement: function() {
return this._getAPI().changesToImplement();
},
setImplement: function() {
return this._getAPI().setImplement();
},
implement: function() {
return this._getAPI().implement();
},
isReview: function() {
return this._getAPI().isReview();
},
changesToReview: function() {
return this._getAPI().changesToReview();
},
setReview: function() {
return this._getAPI().setReview();
},
review: function() {
return this._getAPI().review();
},
/**
* Close
*/
isClosed: function() {
return this._getAPI().isClosed();
},
changesToClosed: function() {
return this._getAPI().changesToClosed();
},
isClosedSuccessful: function() {
return this._getAPI().isClosedSuccessful();
},
isClosedSuccessfulWithIssues: function() {
return this._getAPI().isClosedSuccessfulWithIssues();
},
isClosedUnsuccessful: function() {
return this._getAPI().isClosedUnsuccessful();
},
setClose: function(closeCode, closeNotes) {
return this._getAPI().setClose(closeCode, closeNotes);
},
close: function(closeCode, closeNotes) {
return this._getAPI().close(closeCode, closeNotes);
},
closeSuccessful: function(closeNotes) {
return this._getAPI().closeSuccessful(closeNotes);
},
closeSuccessfulWithIssues: function(closeNotes) {
return this._getAPI().closeSuccessfulWithIssues(closeNotes);
},
closeUnsuccessful: function(closeNotes) {
return this._getAPI().closeUnsuccessful(closeNotes);
},
/**
* Cancel
*/
isCanceled: function() {
return this._getAPI().isCanceled();
},
changesToCanceled: function() {
return this._getAPI().changesToCanceled();
},
setCancel: function() {
return this._getAPI().setCancel();
},
cancel: function() {
return this._getAPI().cancel();
},
/**
* Approvals
*/
isApprovalRequested: function() {
var api = this._getAPI();
if (api.isApprovalRequested)
return api.isApprovalRequested();
return this._gr.getValue("approval") === this.APPROVAL.REQUESTED;
},
isApproved: function() {
var api = this._getAPI();
if (api.isApproved)
return api.isApproved();
return this._gr.getValue("approval") === this.APPROVAL.APPROVED;
},
isRejected: function() {
var api = this._getAPI();
if (api.isRejected)
return api.isRejected();
return this._gr.getValue("approval") === this.APPROVAL.REJECTED;
},
// Legacy transition method. The transtition to an approval state may not exist in a Change model
// Use moveTo(state) as an alternative
setRequestApproval: function() {
var api = this._getAPI();
if (api.setRequestApproval)
return api.setRequestApproval();
this._gr.setValue("approval", this.APPROVAL.REQUESTED);
return true;
},
// Legacy method. The transtition to an approval state may not exist in a Change model
// Use moveTo(state) and update the record as an alternative
requestApproval: function() {
var api = this._getAPI();
if (api.requestApproval)
return api.requestApproval();
if (this.setRequestApproval())
return !!this._gr.update();
return false;
},
isOnHold: function() {
if (this.plugin.state_model || this.plugin.foundation)
return this._gr.getValue("on_hold") === "1";
return false;
},
onHoldChanges: function() {
if (this.plugin.state_model || this.plugin.foundation)
return this._gr.on_hold.changes();
return false;
},
onHoldReasonChanges: function() {
if (this.plugin.state_model || this.plugin.foundation)
return this._gr.on_hold_reason.changes();
return false;
},
syncOnHoldTasks: function() {
if (!this.plugin.best_practice.jakarta && !this.plugin.best_practice.kingston)
return;
var updatedTasks = [];
if (!this._gr.on_hold_task.nil())
updatedTasks = this._gr.getValue('on_hold_task').split(',');
var cTaskGR = new GlideRecord('change_task');
cTaskGR.addQuery('change_request', this._gr.getUniqueValue());
cTaskGR.addActiveQuery();
cTaskGR.query();
while (cTaskGR.next()) {
if (this._gr.on_hold) {
if (cTaskGR.on_hold_reason.nil()) {
new ChangeTask(cTaskGR).onHold(this._gr.on_hold, this._gr.getValue('on_hold_reason'));
updatedTasks.push(cTaskGR.getUniqueValue());
}
}
else {
if (updatedTasks.indexOf(cTaskGR.getUniqueValue()) > -1)
new ChangeTask(cTaskGR).onHold(this._gr.on_hold, '');
}
}
if (this._gr.on_hold)
this._gr.setValue('on_hold_task', updatedTasks.join());
else
this._gr.setValue('on_hold_task','');
this._gr.update();
},
updateOnHoldReason: function() {
if (!this.plugin.best_practice.jakarta && !this.plugin.best_practice.kingston)
return;
if (this._gr.on_hold_task.nil())
return;
var cTaskGR = new GlideRecord('change_task');
cTaskGR.addQuery('sys_id', this._gr.on_hold_task.getGlideList().getValues());
cTaskGR.query();
while (cTaskGR.next())
new ChangeTask(cTaskGR).onHoldReason(this._gr.getValue('on_hold_reason'));
},
addToOnHoldTaskList: function(taskID) {
if (!this.plugin.best_practice.jakarta && !this.plugin.best_practice.kingston)
return;
var updatedTasks = [];
if (!this._gr.on_hold_task.nil())
updatedTasks = this._gr.getValue('on_hold_task').split(',');
if (updatedTasks.indexOf(taskID) == -1)
updatedTasks.push(taskID);
this._gr.setValue('on_hold_task', updatedTasks.join());
this._gr.update();
},
cancelAssociatedTasks: function() {
if (!this.plugin.best_practice.jakarta)
return;
var cTaskGR = new GlideRecord('change_task');
cTaskGR.addQuery('change_request', this._gr.getUniqueValue());
cTaskGR.addActiveQuery();
cTaskGR.query();
while (cTaskGR.next())
new ChangeTask(cTaskGR).cancel(gs.getMessage('Change task cancelled due to Change request being cancelled'));
},
hasOpenTasks: function() {
var cTaskAgg = new GlideAggregate('change_task');
cTaskAgg.addQuery('change_request', this._gr.getUniqueValue());
cTaskAgg.addActiveQuery();
cTaskAgg.addAggregate("COUNT");
cTaskAgg.query();
if (cTaskAgg.next())
return (cTaskAgg.getAggregate("COUNT") > 0);
return false;
},
// Legacy method to check if a change can modify it's type. Do not use.
modifyType: function(previousType) {
var api = this._getAPI();
if (api.modifyType)
api.modifyType(previousType);
},
// Legacy method for managing workflows
deleteDefaultWorkflowContext: function() {
var api = this._getAPI();
if (api.deleteDefaultWorkflowContext)
api.deleteDefaultWorkflowContext();
},
// Legacy choice checking method
hasValidChoice: function(field, value) {
var choiceUtils = new TableChoiceUtils('change_request');
var choices = choiceUtils.getChoicesForField(field);
return choices.hasOwnProperty(value);
},
setValue: function(name, value) {
this._gr.setValue(name, value);
},
getValue: function(name) {
return this._gr.getValue(name);
},
setDisplayValue: function(name, value) {
this._gr.setDisplayValue(name, value);
},
getDisplayValue: function(name) {
return this._gr.getDisplayValue(name);
},
insert: function() {
return this._gr.insert();
},
update: function() {
return this._gr.update();
},
refreshGlideRecord: function() {
var gr = new GlideRecord(ChangeRequest.CHANGE_REQUEST);
if (!gr.get(this._gr.getUniqueValue()))
return;
this.initialize(gr);
},
isChangeRequest: function() {
if (!this._gr)
return false;
return this._gr.sys_class_name == ChangeRequest.CHANGE_REQUEST;
},
isEnforceData: function() {
return gs.getProperty(ChangeRequestSNC.ENFORCE_DATA_REQ_PROP) === "true";
},
setGlobalFromNew: function(value) {
GlideController.putGlobal(ChangeRequestSNC.CHANGE_REQUEST_FROM_NEW, /* boolean */ value);
},
isGlobalFromNew: function() {
return GlideController.getGlobal(ChangeRequestSNC.CHANGE_REQUEST_FROM_NEW) + "" === "true";
},
toString: function() {
return JSON.stringify(this.toJS());
},
toJS: function() {
return ChangeCommon.toJS(this._gr);
},
deleteRecord: ChangeCommon.methods.deleteRecord,
getGlideRecord: ChangeCommon.methods.getGlideRecord,
setValues: ChangeCommon.methods.setValues,
canWriteTo: ChangeCommon.methods.canWriteTo,
type: 'ChangeRequestSNC'
};
ChangeRequestSNC.getAPIClass = function() {
// Only use the new Model based classes if it's installed and model compatibility is turned off.
if (pm.isActive("com.snc.change_management.change_model") && gs.getProperty(ChangeRequestSNC.TYPE_COMPATIBILITY, "false") !== "true")
return ChangeModelChgReqAPI;
if (pm.isActive("com.snc.change_management.state_model"))
return ChangeTypeChgReqAPI;
return ChangeRequestChgReqAPI;
};
ChangeRequestSNC.newNormal = function() {
return ChangeRequestSNC.getAPIClass().newNormal();
};
ChangeRequestSNC.newStandard = function() {
return ChangeRequestSNC.getAPIClass().newStandard();
};
ChangeRequestSNC.newEmergency = function() {
return ChangeRequestSNC.getAPIClass().newEmergency();
};
ChangeRequestSNC.newChange = function(modelSysIdOrType) {
return ChangeRequestSNC.getAPIClass().newChange(modelSysIdOrType);
};
Sys ID
c4d9924deb1102002a7a666cd206fedf