Name
sn_sow_chg.SOWChangeUtilsSNC
Description
No description available
Script
var SOWChangeUtilsSNC = Class.create();
SOWChangeUtilsSNC.prototype = {
LOG_PROPERTY: 'com.snc.change_management.sow_chg_utils.log.level',
CHG_OVERVIEW_CFG_CACHE: 'change_overview_config',
PLUGIN_RISK: 'com.snc.bestpractice.change_risk',
PLUGIN_RISK_ASSESSMENT: 'com.snc.change_management.risk_assessment',
initialize: function() {
this._log = new global.GSLog(this.LOG_PROPERTY, this.type);
this._log.includeTimestamp();
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[initialize] type: ' + this.type);
},
deleteChangeRiskAsmts: function(changeSysId) {
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[deleteIncompleteRiskAssessments] changeSysId: ' + changeSysId);
if (!changeSysId)
return;
var changeGr = new GlideRecord('change_request');
if (!changeGr.get(changeSysId))
return;
var changeRiskAsmt = new global.ChangeRiskAsmt();
var asmtInstanceGr = new GlideRecord('asmt_assessment_instance');
asmtInstanceGr.addQuery('task_id', changeGr.getUniqueValue());
asmtInstanceGr.addQuery('metric_type.sys_class_name', 'change_risk_asmt');
asmtInstanceGr.addQuery('state', '!=', 'complete');
asmtInstanceGr.query();
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[deleteIncompleteRiskAssessments] asmt_assessment_instance encodedQuery: ' + asmtInstanceGr.getEncodedQuery());
// This is a cleanup operation which does not delete any records that customer would not wish deleted
while (asmtInstanceGr.next())
changeRiskAsmt.deleteAsmtInstance(asmtInstanceGr.getUniqueValue());
},
_getGr: function(sysId, table) {
if (!sysId)
return { errorMessage: gs.getMessage('Record sys_id not provided') };
table = table || 'change_request';
var gr = null;
if (sysId instanceof GlideRecord)
gr = sysId;
else {
gr = new GlideRecord(table);
if (!gr.get(sysId))
return { errorMessage: gs.getMessage('Record not found') };
}
if (!gr.canRead())
return { errorMessage: gs.getMessage('Not authorized') };
return gr;
},
getRiskActions: function(sysIdOrGr) {
var gr = this._getGr(sysIdOrGr);
if (!gr)
return { errorMessage: gs.getMessage('No record found') };
if (!GlidePluginManager.isActive(this.PLUGIN_RISK))
return { errorMessage: gs.getMessage('Risk plugin is not installed') };
if (gr && gr.errorMessage)
return gr;
var result = {};
var riskCalculator = new global.RiskCalculator(gr);
var showChangeRiskDetails = false;
var changeRiskDetails = {};
var validChgSysId = gr.getUniqueValue();
if (validChgSysId) {
var chgRiskDetailsGr = new GlideRecord('change_risk_details');
chgRiskDetailsGr.addQuery('change_request', validChgSysId);
chgRiskDetailsGr.query();
if (chgRiskDetailsGr.next()) {
changeRiskDetails.sysId = chgRiskDetailsGr.getUniqueValue();
showChangeRiskDetails = !!changeRiskDetails.sysId;
changeRiskDetails.sys_updated_on = {
display_value: chgRiskDetailsGr.sys_updated_on.getDisplayValue(),
value: chgRiskDetailsGr.getValue('sys_updated_on')
};
changeRiskDetails.description = gs.getMessage('We calculate the risk score as a balance of factors such as scope, impact, and scheduling');
}
}
var showLegacyRiskAssessment = !!(typeof global.RiskAssessmentCalculator !== 'undefined' && new global.RiskAssessmentCalculator(gr).checkForMatchingAssessment(gr.sys_class_name, gr) && (GlidePluginManager.isActive(this.PLUGIN_RISK_ASSESSMENT) + '').toLowerCase() !== 'true');
var showCalculateRisk = !showLegacyRiskAssessment && riskCalculator.showCalculateRisk();
var showRiskAssessment = riskCalculator.showRiskAssessment();
var showCompletedRiskAssessment = showRiskAssessment ? new global.ChangeRiskAsmt().hasCompletedAssessment(gr) : false;
return {
showLegacyRiskAssessment: { hide: !showLegacyRiskAssessment, label: gs.getMessage('Legacy Risk Assessment is not supported by SOW. Please evaluate risk using classic form.') },
showCalculateRisk: { hide: !showCalculateRisk, label: gs.getMessage('Recalculate risk') },
showRiskAssessment: { hide: !showRiskAssessment, label: gs.getMessage('Assess risk') },
showCompletedRiskAssessment: { hide: !showCompletedRiskAssessment, label: gs.getMessage('View risk assessment') },
showChangeRiskDetails: { hide: !showChangeRiskDetails, label: gs.getMessage('View risk details') },
changeRiskDetails: changeRiskDetails
};
},
calculateRisk: function(sysId, dryRun) {
if (!gs.hasRole('itil,sn_change_write'))
return { errorMessage: gs.getMessage('Not Authorized') };
var gr = this._getGr(sysId, 'change_request');
if (!gr)
return { errorMessage: gs.getMessage('No record found') };
if (gr && gr.errorMessage)
return gr;
if (!GlidePluginManager.isActive(this.PLUGIN_RISK))
return { errorMessage: gs.getMessage('Risk plugin is not installed') };
// Explicit false must be passed to dryRun and must be a boolean
if (typeof dryRun === 'undefined')
dryRun = true;
else if (typeof dryRun === 'string')
dryRun = dryRun.toLowerCase() === 'true';
if (!dryRun) {
var riskCalculator = new global.RiskCalculator(gr);
if (riskCalculator.setHideNotification)
riskCalculator.setHideNotification(true);
var evaluatedRiskImpact = riskCalculator.evaluateRiskImpact();
if (!evaluatedRiskImpact)
return { errorMessage: gs.getMessage('Failed to evaluate Risk') };
}
var result = this.getRiskActions(gr);
if (evaluatedRiskImpact)
result = global.ChangeCommon.assign(result, evaluatedRiskImpact);
return result;
},
getCompletedChangeRiskAsmts: function(table, sysId) {
var gr = this._getGr(sysId);
if (!gr)
return { errorMessage: gs.getMessage('No record found') };
if (gr && gr.errorMessage)
return gr;
if (!GlidePluginManager.isActive(this.PLUGIN_RISK))
return { errorMessage: gs.getMessage('Risk plugin is not installed') };
var riskCalculator = new global.RiskCalculator(gr);
if (riskCalculator.showRiskAssessment()) {
var changeRiskAsmt = new global.ChangeRiskAsmt();
if (changeRiskAsmt.hasCompletedAssessment(gr))
return changeRiskAsmt.viewAssessment({
'tableName': gr.getValue('sys_class_name'),
'sysId': gr.getUniqueValue(),
'userId': gs.getUserID()
});
}
return {
errorMessage: gs.getMessage('No completed Change Risk Assessment found')
};
},
getFormSectionsForLayout: function(table, sysId, view) {
if (!table || !sysId || !view)
return {};
var result = {
formLayout: {
isValidRecord: true,
table: table,
sysId: sysId,
sectionLayout: []
}
};
var sectionGr = new GlideRecord('sys_ui_section');
sectionGr.addQuery('name', table);
sectionGr.addQuery('view.name', view);
sectionGr.orderBy('sys_created_on');
sectionGr.query();
while (sectionGr.next()) {
var sectionSysId = sectionGr.getUniqueValue();
var section = {
sysId: sectionSysId,
caption: (sectionGr.getValue('caption') || '').toLowerCase(),
captionDisplay: sectionGr.caption.getDisplayValue() || sectionGr.name.getDisplayValue(),
rows: this._getSectionRows(sectionSysId)
};
result.formLayout.sectionLayout.push(section);
}
return result;
},
_getSectionRows: function (sectionSysId) {
var rows = [];
if (!sectionSysId)
return rows;
var blocks = [];
var fields = [];
var elementGr = new GlideRecord('sys_ui_element');
elementGr.addQuery('sys_ui_section', sectionSysId);
elementGr.orderBy('position');
elementGr.query();
while (elementGr.next()) {
var field = elementGr.element + '';
var elementType = elementGr.type + '';
switch (elementType) {
case '.begin_split':
if (fields.length > 0) {
blocks.push({ fields: fields });
rows.push(blocks);
}
fields = [];
blocks = [];
break;
case '.split':
if (fields.length > 0)
blocks.push({ fields: fields });
fields = [];
break;
case '.end_split':
if (fields.length > 0)
blocks.push({ fields: fields });
fields = [];
rows.push(blocks);
blocks = [];
break;
default:
fields.push(field);
}
}
// No Splits
if (fields.length > 0) {
blocks.push({ fields: fields });
rows.push(blocks);
}
return rows;
},
getSectionsForState: function(table, sysId, state) {
var sectionsForState = {};
if (!table || !sysId || !state)
return sectionsForState;
var changeRequestGr = new GlideRecord(table);
if (sysId === '-1')
changeRequestGr.setValue('state', state);
else if (!changeRequestGr.get(sysId) || !changeRequestGr.canRead())
return sectionsForState;
var matched = false;
var orderMatched = '';
var chgOverviewContainers = this._getChgOverviewContainers(table);
for (var i = 0; i < chgOverviewContainers.length && !matched; i++) {
var chgOverviewContainer = chgOverviewContainers[i];
if (GlideFilter.checkRecord(changeRequestGr, chgOverviewContainer.condition)) {
matched = true;
orderMatched = chgOverviewContainer.order;
sectionsForState = chgOverviewContainer;
}
}
var scriptedSectionsForState = this._getScriptedChgOverviewContainers(orderMatched, table, changeRequestGr);
sectionsForState = scriptedSectionsForState ? scriptedSectionsForState : sectionsForState;
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[getSectionsForState] cards: ' + JSON.stringify(sectionsForState));
return sectionsForState;
},
getCacheKey: function(table, hasTranslatedContent) {
var key = table || '';
var domain = gs.getSession().getCurrentDomainID();
if (global.JSUtil.nil(domain))
domain = 'global';
key += '^' + domain;
if (hasTranslatedContent)
key += '^' + gs.getSession().getLanguage() || gs.getProperty('glide.sys.language', 'en');
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[getCacheKey] key: ' + key);
return key;
},
_getChgOverviewContainers: function(table) {
table = table || '';
var key = this.getCacheKey(table, true);
var chgOverviewContainersStr = sn_scoped_cache.ScopedCacheManager.get(this.CHG_OVERVIEW_CFG_CACHE, key);
if (chgOverviewContainersStr)
return JSON.parse(chgOverviewContainersStr);
chgOverviewContainers = [];
var chgOverviewCntGr = new GlideRecord('chg_overview_container');
chgOverviewCntGr.addActiveQuery();
chgOverviewCntGr.addQuery('table', table);
chgOverviewCntGr.addQuery('use_advanced_condition', false);
chgOverviewCntGr.orderBy('order');
chgOverviewCntGr.orderBy('sys_id');
chgOverviewCntGr.query();
while (chgOverviewCntGr.next()) {
var chgOverviewContainer = {};
chgOverviewContainer.name = chgOverviewCntGr.getDisplayValue();
chgOverviewContainer.order = chgOverviewCntGr.order + '';
chgOverviewContainer.condition = chgOverviewCntGr.condition + '';
chgOverviewContainer.displayActionBar = chgOverviewCntGr.getValue('display_action_bar') + '' === '1';
chgOverviewContainer.items = this._getChgOverviewCards(chgOverviewCntGr.getUniqueValue());
chgOverviewContainers.push(chgOverviewContainer);
}
chgOverviewContainersStr = JSON.stringify(chgOverviewContainers);
sn_scoped_cache.ScopedCacheManager.put(this.CHG_OVERVIEW_CFG_CACHE, key, chgOverviewContainersStr);
return JSON.parse(chgOverviewContainersStr);
},
_getScriptedChgOverviewContainers: function(order, table, changeRequestGr) {
var sectionsForState = null;
if (!changeRequestGr || !table)
return sectionsForState;
var evaluator;
var matched = false;
var chgOverviewCntGr = new GlideRecord('chg_overview_container');
chgOverviewCntGr.addActiveQuery();
chgOverviewCntGr.addQuery('table', table);
chgOverviewCntGr.addQuery('use_advanced_condition', true);
if (!global.JSUtil.nil(order))
chgOverviewCntGr.addQuery('order', '<', order);
chgOverviewCntGr.orderBy('order');
chgOverviewCntGr.orderBy('sys_id');
chgOverviewCntGr.query();
while (chgOverviewCntGr.next() && !matched) {
if (!evaluator) {
evaluator = new GlideScopedEvaluator();
evaluator.putVariable('current', changeRequestGr);
evaluator.putVariable('answer', false);
}
evaluator.evaluateScript(chgOverviewCntGr, 'advanced_condition');
matched = evaluator.getVariable('answer');
if (matched) {
sectionsForState = {};
sectionsForState.id = changeRequestGr.getValue('state');
sectionsForState.state = changeRequestGr.state.getDisplayValue();
sectionsForState.name = chgOverviewCntGr.getDisplayValue();
sectionsForState.displayActionBar = chgOverviewCntGr.getValue('display_action_bar') + '' === '1';
sectionsForState.items = this._getChgOverviewCards(chgOverviewCntGr.getUniqueValue());
}
}
return sectionsForState;
},
_getChgOverviewCards: function(chgOverviewContainerSysId) {
var cards = [];
if (!chgOverviewContainerSysId)
return cards;
var chgOverviewCardGr = new GlideRecord('chg_overview_card');
chgOverviewCardGr.addActiveQuery();
chgOverviewCardGr.addQuery('chg_overview_container', chgOverviewContainerSysId);
chgOverviewCardGr.orderBy('order');
chgOverviewCardGr.orderBy('sys_id');
chgOverviewCardGr.query();
while (chgOverviewCardGr.next()) {
var card = {};
card.name = chgOverviewCardGr.getValue('name');
card.expanded = chgOverviewCardGr.getValue('expanded') + '' === '1';
card.showNewRecord = chgOverviewCardGr.getValue('show_new_record') + '' === '1';
card.heading = chgOverviewCardGr.heading.getDisplayValue();
var fields = this._getChgOverviewFields(chgOverviewCardGr.getUniqueValue());
if (fields && fields.length > 0)
card.fields = fields;
cards.push(card);
}
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[_getChgOverviewCards] cards: ' + JSON.stringify(cards));
return cards;
},
_getChgOverviewFields: function(chgOverviewCardSysId) {
var fields = [];
if (!chgOverviewCardSysId)
return fields;
var chgOverviewCardGr = new GlideRecord('chg_overview_field');
chgOverviewCardGr.addActiveQuery();
chgOverviewCardGr.addQuery('chg_overview_card', chgOverviewCardSysId);
chgOverviewCardGr.query();
while (chgOverviewCardGr.next())
fields.push(chgOverviewCardGr.getValue('name'));
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[_getChgOverviewFields] fields: ' + JSON.stringify(fields));
return fields;
},
_getChangeQueryParams: function(srcSysId) {
var changeUtils = new global.ChangeUtils();
var attributesList = changeUtils._getCsvPropertyValue(changeUtils.PROP_CHANGE_ATTRS, changeUtils.CHANGE_REQUEST_DEFAULT_ATTR_VALUE);
var gr = new GlideRecord(changeUtils.CHANGE_REQUEST);
if (gr.get(srcSysId))
return changeUtils._getRecordValuesAsEncodedQuery(gr, attributesList);
else
this._log.logErr('Invalid src change_request sysid provided = ' + srcSysId);
return '';
},
copyChangeURL: function(srcSysId) {
var changeUtils = new global.ChangeUtils();
var queryParams = this._getChangeQueryParams(srcSysId);
if (changeUtils.hasReadWriteAccess()) {
var newSysID = '-1';
// Copy Change attachments if enabled
changeUtils.copyChangeAttachments(srcSysId, newSysID);
// If API status is true all was ok. If no, still redirect to the URL on stack. All warning messages will be put in the util.
if (!changeUtils.copyChangeRelatedLists(srcSysId, newSysID))
gs.log('sn_sow_chg.SOWChangeUtilsSNC - copyChangeURL - Warnings present in ChangeUtils.copyChangeRelatedLists');
return queryParams;
}
},
getApprovals: function(taskId) {
var cabApproval = new sn_change_cab.CABApproval(taskId);
var delegators = cabApproval._getDelegators();
var approvals = cabApproval.toJS();
var groupsArray = approvals.groups;
var groupsObject = {};
groupsArray.forEach(function(group) {
groupsObject[group.sys_id] = group.delegated;
});
approvals.groups = groupsObject;
approvals.allowedApprovers = delegators;
approvals.allowedApprovers.push(gs.getUserID());
var result = {
'taskId': taskId,
'approvals': {}
};
var approvalsGr = new GlideRecord('sysapproval_approver');
approvalsGr.addQuery('sysapproval', taskId);
approvalsGr.addQuery('approver', 'IN', approvals.allowedApprovers);
approvalsGr.query();
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[getApprovals] sysapproval_approver.encodedQuery: ' + approvalsGr.getEncodedQuery());
while (approvalsGr.next()) {
var groupED = approvalsGr.group.assignment_group.getRefRecord();
var group = {
'value': groupED.getUniqueValue() + '',
'displayValue': groupED.getDisplayValue()
};
var isDelegated = false;
if ((approvals.groups && approvals.groups[approvalsGr.group]) || (approvalsGr.getValue('approver') !== gs.getUserID()))
isDelegated = true;
var approvalSysId = approvalsGr.getUniqueValue();
var groupDisplayValue = isDelegated ? gs.getMessage('{0} (delegated)', group.displayValue) : group.displayValue;
var approverDisplayValue = isDelegated ? gs.getMessage('{0} (delegated)', approvalsGr.getDisplayValue('approver')) : approvalsGr.getDisplayValue('approver');
result.approvals[approvalSysId] = {
'sys_id': approvalSysId,
'group': approvalsGr.getValue('group'),
'assignment_group': {
'value': group.value,
'displayValue': groupDisplayValue
},
'approver': {
'value': approvalsGr.getValue('approver'),
'displayValue': approverDisplayValue
},
'delegated': isDelegated,
'state': {
'value': approvalsGr.getValue('state'),
'displayValue': approvalsGr.getDisplayValue('state')
},
'last_updated': {
'value': approvalsGr.getValue('sys_updated_on'),
'displayValue': approvalsGr.getDisplayValue('sys_updated_on')
}
};
}
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[getApprovals] result: ' + JSON.stringify(result));
return result;
},
updateApproval: function(taskSysId, state, comments) {
var approvalUser = this._processApproval(taskSysId, state, comments);
var result = this.getApprovals(taskSysId);
result.approvalUser = approvalUser;
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[updateApproval] result: ' + JSON.stringify(result));
return result;
},
_processApproval: function(taskSysId, state, comments) {
var approvalUser = {};
state = (state + '').toLowerCase();
if (state !== 'approved' && state !== 'rejected')
return approvalUser;
// comments are mandatory on rejection
if (state === 'rejected' && !comments)
return approvalUser;
// only process my approvals
var userSysIds = this._getMyApprovals();
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug('[_processApproval] userSysIds: ' + userSysIds);
var gr = new GlideRecord('sysapproval_approver');
gr.addQuery('approver', 'IN', userSysIds);
gr.addQuery('document_id', taskSysId);
gr.addQuery('state', 'requested');
gr.query();
while (gr.next()) {
gr.state = state;
if (comments)
gr.comments = comments;
if (gr.canWrite()) {
var approvalSysId = gr.update();
if (approvalSysId)
approvalUser[approvalSysId] = {
userSysId: gr.getValue('approver'),
state: gr.getValue('state')
};
}
}
return approvalUser;
},
_getMyApprovals: function() {
var u = gs.getUserID();
var answer = new Array();
var i = 0;
answer[i++] = new String(u);
var g = new GlideRecord('sys_user_delegate');
g.addQuery('delegate', u);
g.addQuery('approvals', 'true');
g.addQuery('starts', '<=', gs.daysAgo(0));
g.addQuery('ends', '>=', gs.daysAgo(0));
g.query();
while (g.next()) {
answer[i++] = new String(g.user);
}
return answer;
},
type: 'SOWChangeUtilsSNC'
};
Sys ID
02e123a553615110532cddeeff7b129e