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

Offical Documentation

Official Docs: