Name
sn_chg_score.ChangeSuccessScoreUtilsSNC
Description
Provides utility functions for the Change success score feature. To modify behavior, use the provided ChangeSuccessScoreUtils extension to override functions defined within this script include.
Script
var ChangeSuccessScoreUtilsSNC = Class.create();
ChangeSuccessScoreUtilsSNC.prototype = {
// Ids of key records - Team Success Score
PA_CHANGE_SUCCESS_SCORE_ADJUSTMENT_INDICATOR_ID: "ae4a10a573330010491d235f04f6a71c",
PA_CHANGE_SUCCESS_SCORE_INDICATOR_ID: "0ff316e173081010491d235f04f6a758",
PA_SUCCESSFUL_CHANGES_INDICATOR_ID: "205f4fd173330010491d235f04f6a750",
PA_CHANGE_SCORE_INDICATOR_GROUP_ID: "497e43d173330010491d235f04f6a7f7",
PA_CHANGE_SCORE_GROUP_BREAKDOWN_ID: "d21e0f9173330010491d235f04f6a74d",
PA_CHANGE_SUCCESS_SCORE_DASHBOARD_ID: "8a681506f04c1010f877a579f6e43397",
PA_CHANGE_SUCCESS_SCORE_BREAKDOWN_SOURCE_ID: "92cd0b9173330010491d235f04f6a782",
PA_CHANGE_SUCCESS_SCORE_METRICS_JOB_ID: "14b8113573fb0010491d235f04f6a702",
PA_CHANGE_SUCCESS_SCORE_METRICS_HISTORICAL_JOB_ID: "6f7d879173330010491d235f04f6a743",
PA_CHANGE_SUCCESS_SCORES_JOB_ID: "6adc7c2773001010491d235f04f6a7ee",
PA_CHANGE_SUCCESS_SCORES_HISTORICAL_JOB_ID: "be2c342773001010491d235f04f6a762",
METRIC_DEFINITION_ID: "c8b3e4c173c01010491d235f04f6a726",
// Ids of key records - Model Success Score
PA_MODEL_SUCCESS_BREAKDOWN_ID: "c8541519c3ce011005aea539e540ddc2",
PA_MODEL_SUCCESS_FORMULA_INDICATOR: "604f98dfc302011005aea539e540dd75",
PA_MODEL_SUCCESS_AUTOMATED_INDICATOR_GROUP: "45b8a561c312011005aea539e540ddc3",
PA_TYPE_SUCCESS_BREAKDOWN_ID: "ae1b0255c382411005aea539e540dd87",
PA_TYPE_SUCCESS_FORMULA_INDICATOR: "f9d25995c3ce011005aea539e540ddee",
PA_TYPE_SUCCESS_AUTOMATED_INDICATOR_GROUP: "c3f861a1c312011005aea539e540ddce",
// Table names
CHG_SUCCESS_SCORE_RATING: "chg_success_score_rating",
PA_JOB_LOGS_TABLE: "pa_job_logs",
SYSAUTO_PA: "sysauto_pa",
PA_JOB_INDICATORS: "pa_job_indicators",
PA_JOB_DOMAIN_CONFIGURATIONS: "pa_job_domain_configurations",
// Properties
CHG_SUCCESS_LOG_PROP: "com.snc.change_management.success_score.log",
CHG_SUCCESS_SCORE_ENTRY_LEVEL_PROP: "com.snc.change_management.success_score.entry_level_score",
CHG_SUCCESS_SCORE_MINIMUM_PROP: "com.snc.change_management.success_score.minimum_score",
CHG_SUCCESS_SCORE_MAXIMUM_PROP: "com.snc.change_management.success_score.maximum_score",
CHG_SUCCESS_PREVIOUS_SCORE_HISTORY_LIMIT_PROP: "com.snc.change_management.success_score.previous_score_history_limit",
initialize: function() {
this.changeSuccessScoreGlobalUtils = new global.ChangeSuccessScoreGlobalUtils();
},
getMinAllowedScore: function() {
return this._getScoreFromProperty(this.CHG_SUCCESS_SCORE_MINIMUM_PROP, 0);
},
getMaxAllowedScore: function() {
return this._getScoreFromProperty(this.CHG_SUCCESS_SCORE_MAXIMUM_PROP, 850);
},
getEntryLevelScore: function() {
return this._getScoreFromProperty(this.CHG_SUCCESS_SCORE_ENTRY_LEVEL_PROP, 500);
},
getPreviousScoreHistoryLimit: function() {
return this._getScoreFromProperty(this.CHG_SUCCESS_PREVIOUS_SCORE_HISTORY_LIMIT_PROP, 6);
},
getDashboardURL: function(groupId) {
var url = "$pa_dashboard.do?dashboard=" + this.PA_CHANGE_SUCCESS_SCORE_DASHBOARD_ID + "&sysparm_breakdown_source=" + this.PA_CHANGE_SUCCESS_SCORE_BREAKDOWN_SOURCE_ID;
if (groupId)
url += "&sysparm_element=" + groupId;
return url;
},
/* Based on the PA Job log record passed in and the associated PA Job, determine if latest daily scores or
historical scores need to be generated and ensure to generate the scores in the same timezone as the
PA Job. This is important to ensure we fetch the correct records using the PA API and use the
correct date/time on the "metric_instance" records */
generateScoresByPAJobLog: function(paLogsGr) {
var isDailyMetricsLog = this.isPALogForDailyMetrics(paLogsGr);
var isHistoricalMetricsLog = this.isPALogForHistoricalMetrics(paLogsGr);
/* if the log is not for either the daily or historical Change success score metrics jobs
then there's nothing to do */
if (!isDailyMetricsLog && !isHistoricalMetricsLog)
return;
// get the timezone that the associated PA job ran in
var paJobTimeZone = this.getPAJobTimezone(paLogsGr.job.getRefRecord());
// call the appropriate function to generate either latest or historical scores
if (isDailyMetricsLog)
this.generateLatestScoresByTimezone(paJobTimeZone);
else if (isHistoricalMetricsLog)
this.generateScoresForHistoricalMetrics(paJobTimeZone);
},
// For the supplied PA Job ("sysauto_pa") record derive the timezone it runs in
getPAJobTimezone: function(paJobGr) {
// if we haven't been passed a PA Job just return system timezone
if (!this._isPAJob(paJobGr))
return gs.getSysTimeZone();
// if "Run as tz" is set in the record this takes precedence
if (!paJobGr.run_as_tz.nil())
return paJobGr.getValue("run_as_tz");
/* otherwise get timezone fron the "Run as" user
- if "Run as" is empty or the user has no timezone we'll return system timezone */
return this.changeSuccessScoreGlobalUtils.getUsersTimezone(paJobGr.getValue("run_as"));
},
isPALogForDailyMetrics: function(paLogsGr) {
if (!this._isPALog(paLogsGr))
return false;
return paLogsGr.getValue("job") === this.PA_CHANGE_SUCCESS_SCORE_METRICS_JOB_ID;
},
isPALogForHistoricalMetrics: function(paLogsGr) {
if (!this._isPALog(paLogsGr))
return false;
return paLogsGr.getValue("job") === this.PA_CHANGE_SUCCESS_SCORE_METRICS_HISTORICAL_JOB_ID;
},
getPAChangeSuccessScoresJobs: function() {
var sysAutoGr = new GlideRecord(this.SYSAUTO_PA);
sysAutoGr.addQuery("sys_id", this.getJobsLinkedToIndicator(this.PA_CHANGE_SUCCESS_SCORE_INDICATOR_ID));
sysAutoGr.addQuery("score_relative_start", 0);
sysAutoGr.addQuery("score_relative_start_interval", "days");
sysAutoGr.addQuery("score_relative_end", "0");
sysAutoGr.addQuery("score_relative_end_interval", "days");
sysAutoGr.query();
return sysAutoGr;
},
getPAChangeSuccessScoresHistoricalJobs: function() {
var sysAutoGr = new GlideRecord(this.SYSAUTO_PA);
sysAutoGr.addQuery("sys_id", this.getJobsLinkedToIndicator(this.PA_CHANGE_SUCCESS_SCORE_INDICATOR_ID));
sysAutoGr.addQuery("score_relative_start", "!=", 0).addOrCondition("score_relative_end", "!=", 0);
sysAutoGr.query();
return sysAutoGr;
},
getJobsLinkedToIndicator: function(indicatorId) {
var jobIds = [];
if (!indicatorId)
return jobIds;
var paJobIndicatorsGr = new GlideRecord(this.PA_JOB_INDICATORS);
paJobIndicatorsGr.addQuery("indicator", indicatorId);
paJobIndicatorsGr.addQuery("job.active", true);
paJobIndicatorsGr.query();
while (paJobIndicatorsGr.next())
jobIds.push(paJobIndicatorsGr.getValue("job"));
return jobIds;
},
/* Call the method to generate the latest Change Success scores in the Metrics ("metric_instanc") table
but in a specific timezone - this will query the PA API based on this timezone along with
finding and creating/updating appropriate "metric_instance" records */
generateLatestScoresByTimezone: function(timezone) {
new sn_chg_score.ChangeSuccessScoreGenerator().setTimeZone(timezone).generateLatest();
},
generateScoresForHistoricalMetrics: function(timezone) {
var paJobGr = new GlideRecord(this.SYSAUTO_PA);
if (!paJobGr.get(this.PA_CHANGE_SUCCESS_SCORE_METRICS_HISTORICAL_JOB_ID))
return;
var relativeStart = -parseInt(paJobGr.getValue("score_relative_start"));
var relativeStartInterval = paJobGr.getValue("score_relative_start_interval");
var relativeEnd = -parseInt(paJobGr.getValue("score_relative_end"));
var relativeEndInterval = paJobGr.getValue("score_relative_end_interval");
if (isNaN(relativeStart) || isNaN(relativeEnd)) {
gs.warn('Change Success Score: Cannot generate scores because data collection job '+ paJobGr.name + ' does not have relative start and end date');
return;
}
var startDate = new GlideDateTime();
switch (relativeStartInterval) {
case "days":
startDate.addDaysUTC(relativeStart);
break;
case "weeks":
startDate.addWeeksUTC(relativeStart);
break;
case "months":
startDate.addMonthsUTC(relativeStart);
break;
}
//To sync sore with Change Success Score metrics
startDate.addDaysUTC(1);
var endDate = new GlideDateTime();
switch (relativeEndInterval) {
case "days":
endDate.addDaysUTC(relativeEnd);
break;
case "weeks":
endDate.addWeeksUTC(relativeEnd);
break;
case "months":
endDate.addMonthsUTC(relativeEnd);
break;
}
var changeSuccessScoreGenerator = new ChangeSuccessScoreGenerator().setTimeZone(timezone);
do {
changeSuccessScoreGenerator.generateForDate(startDate);
startDate.addDaysUTC(1);
} while (startDate.getValue() <= endDate.getValue());
},
getAggregateDomain: function() {
var jobsGr = new GlideRecord(this.SYSAUTO_PA);
var domainConfigJoin = jobsGr.addJoinQuery(this.PA_JOB_DOMAIN_CONFIGURATIONS, "sys_id", "job");
domainConfigJoin.addCondition("domain_configuration.collect_aggregate", true);
var indicatorGr = jobsGr.addJoinQuery(this.PA_JOB_INDICATORS, "sys_id", "job");
indicatorGr.addCondition("indicator", this.PA_SUCCESSFUL_CHANGES_INDICATOR_ID);
jobsGr.query();
if (!jobsGr.next())
return "";
var domainConfigurationGr = new GlideRecord(this.PA_JOB_DOMAIN_CONFIGURATIONS);
domainConfigurationGr.addQuery("job", jobsGr.getUniqueValue());
domainConfigurationGr.addQuery("domain_configuration.collect_aggregate", true);
domainConfigurationGr.query();
if (!domainConfigurationGr.next())
return "";
return "" + domainConfigurationGr.domain_configuration.aggregate_domain;
},
isTrue: function(trueOrFalse) {
return "" + trueOrFalse === "true";
},
_isPALog: function(paLogsGr) {
if (!paLogsGr)
return false;
return paLogsGr.getRecordClassName() === this.PA_JOB_LOGS_TABLE;
},
_isPAJob: function(paJobGr) {
return paJobGr && (paJobGr.getRecordClassName() === this.SYSAUTO_PA);
},
_getScoreFromProperty: function(propertyName, defaultValue) {
var score = 0;
if (!defaultValue || isNaN(defaultValue))
defaultValue = 0;
if (!propertyName)
return score;
score = parseInt(gs.getProperty(propertyName, defaultValue), 10);
if (isNaN(score))
return defaultValue;
return score;
},
type: 'ChangeSuccessScoreUtilsSNC'
};
Sys ID
52a3737573805010491d235f04f6a71e