Name

sn_itom_licensing.ITOMLicensingAggregationHelperStore

Description

Helper for ITOM Licensing CI Counts Aggregation

Script

var ITOMLicensingAggregationHelperStore = Class.create();
ITOMLicensingAggregationHelperStore.prototype = {

  initialize: function() {
      this.jobStartTime = new GlideDateTime();
      this.CI_COUNTS_TABLE_NAME = 'itom_lu_ci_counts';
      this.utils = new ITOMLicensingUtilsStore();
      this.valueStreams = this.utils.getValueStreams();
      this.category2Ratio = this.utils.getCategory2Ratio();
      this.domains = this.utils.getDomains();
      this.metadataUtil = new ITOMLicensingMetaDataStore();
      this.instanceSkuList = JSON.parse(sn_lef.GlideEntitlement.getUnifiedItomLicenseInfo());
      this.arrayUtils = new global.ArrayUtil();
  },

  getAggregateMethod: function() {
  var gr = new GlideRecord('itom_lu_sku_type');
  gr.query();
  while (gr.next()) {
      var skuType = gr.getValue('sku');
      if ((skuType == "itom") || (skuType == "otm" && this.utils.isOTDependencyPresent())) {
          this.aggregateCiCounts(gr.getValue('sku'));
      }
  }
},
  aggregateCiCounts: function(skuType) {
  	var skuBasedLicenseInfoList = this._getSkuBasedLicenseInfoList(skuType);
      var aggregates = this._initAggregatesJson(skuBasedLicenseInfoList, skuType);
      var ga = new GlideAggregate(this.CI_COUNTS_TABLE_NAME);
      var isDomainSeparated = this._isDomainSeparated();
      var encodedQuery = 'sys_created_onONLast 90 days@javascript:gs.beginningOfLast90Days()@javascript:gs.endOfLast90Days()';
      if (isDomainSeparated) {
          ga.addAggregate('SUM', 'count');
          var domainSeparationEnabledOn = this._getDomainSeparationEnabledDate();
          if (domainSeparationEnabledOn && domainSeparationEnabledOn.length > 0) {
              var domainSeparationEnabledDate = new GlideDateTime();
              domainSeparationEnabledDate.setValue(domainSeparationEnabledOn);

              var currentDate = new GlideDateTime();
              var duration = GlideDateTime.subtract(domainSeparationEnabledDate, currentDate);
              var noOfDays = (duration.getDayPart() + 1);
              if (noOfDays < 90) {
                  //taking average from the days when domain separation is enabled
                  encodedQuery = "sys_created_on>=" + domainSeparationEnabledOn;
              }
          }
      } else {
          ga.addAggregate('AVG', 'count');
      }

      this.skuId = this.utils.skuSysId[skuType];
      ga.addAggregate('AVG', 'count');
      ga.addQuery('sku', this.skuId);
      ga.addQuery('is_aggregated', false);
      ga.addEncodedQuery(encodedQuery);
      ga.addQuery('value_stream', 'IN', this.valueStreams);
      ga.addQuery('category', 'IN', Object.keys(this.category2Ratio));
      ga.groupBy('value_stream');
      ga.groupBy('category');
      ga.groupBy('sys_domain');
      ga.query();
      while (ga.next()) {
          var valueStream = ga.getValue('value_stream');
          var category = ga.getValue('category');
          var domain = ga.getValue('sys_domain');
          if (aggregates[valueStream][domain].hasOwnProperty(category)) {
              var categoryJson = aggregates[valueStream][domain][category];
              if (isDomainSeparated) {
                  avg = noOfDays && noOfDays < 90 ? Math.floor(ga.getAggregate('SUM', 'count') / noOfDays) : Math.floor(ga.getAggregate('SUM', 'count') / 90);
              } else {
                  avg = Math.floor(ga.getAggregate('AVG', 'count'));
              }
              var suCount = this._calcSuCount(avg, categoryJson.su_ratio);
              categoryJson.count = avg;
              categoryJson.su_count = suCount;
          }
      }
      this._updateCiCountsTable(aggregates);
      if (!JSON.parse(sn_lef.GlideEntitlement.getUnifiedItomLicenseInfo()).length)
          return;
      var accountingHelper = new ITOMLicensingAccountingHelperStore();
      accountingHelper.accountUsage(isDomainSeparated, skuType, aggregates);

  },
  _getDomainSeparationEnabledDate: function() {
      var DSEnabledOn = gs.getProperty('sn_itom_license.domain_separation_enabled_date');
      if (DSEnabledOn)
          return DSEnabledOn;

      // Check for oldest non-aggregated record where domain is not global i.e. a new domain has arrived
      var gr = new GlideRecord(this.CI_COUNTS_TABLE_NAME);
      gr.addQuery('sys_domain', '!=', 'global');
      gr.addQuery('is_aggregated', false);
      gr.setLimit(1);
      gr.orderBy('sys_created_on');
      gr.query();
      if (gr.next()) {
          // Update System Property
          var systemPropertyGr = new GlideRecord('sys_properties');
          systemPropertyGr.get('name', 'sn_itom_license.domain_separation_enabled_date');
          systemPropertyGr.setValue('value', gr.getValue('sys_created_on'));
          systemPropertyGr.update();
          return gr.getValue('sys_created_on');
      }
  },

  _isDomainSeparated: function() {
      return (GlidePluginManager.isActive('com.glide.domain.msp_extensions.installer') && this.domains.length > 1);
  },

  _initAggregatesJson: function(skuBasedLicenseInfoList, skuType) {
      var aggregates = {};
      var timestamp = new GlideDateTime();
      for (var i = 0; i < this.valueStreams.length; i++) {
          var valueStreamJson = {};
          var isLicensableValueStream = this.arrayUtils.contains(this._getLicensableValueStreams(skuBasedLicenseInfoList, skuType), this.valueStreams[i]);
          for (var k = 0; k < this.domains.length; k++) {
              var domain = this.domains[k];
              var domainJson = {};
              var categories = {};
              if (isLicensableValueStream) {
                  categories = this._getCategoryNamesBasedonValueStream(this.valueStreams[i].toLowerCase(), skuType);
              } else {
                  categories = Object.keys(this.utils._getCategorySuRatiosFromProperty(skuType));
              }
              for (var j = 0; j < categories.length; j++) {
                  var category = categories[j];
                  var categoryJson = {};
                  categoryJson.count = 0;
                  categoryJson.su_ratio = this.category2Ratio[category];
                  categoryJson.su_count = 0;
                  categoryJson.last_aggregated = timestamp;
                  domainJson[category] = categoryJson;
              }

              valueStreamJson[domain] = domainJson;
          }

          var valueStream = this.valueStreams[i];
          aggregates[valueStream] = valueStreamJson;
      }

      return aggregates;
  },

  _updateCiCountsTable: function(aggregates) {
      if (!Object.keys(aggregates).length) {
          this._removeStaleRecords();
          return;
      }
      var valueStreams = Object.keys(aggregates);
      for (var i = 0; i < valueStreams.length; i++) {
          var valueStream = valueStreams[i];
          var valueStreamJson = aggregates[valueStream];
          for (var j = 0; j < this.domains.length; j++) {
              var domain = this.domains[j];
              var domainJson = valueStreamJson[domain];

              var categories = Object.keys(domainJson);
              for (var k = 0; k < categories.length; k++) {
                  var category = categories[k];
                  this._createOrUpdate(valueStream, category, domainJson[category], domain);
              }
          }
      }
      this._removeStaleRecords();
  },

  _createOrUpdate: function(valueStream, category, values, domain) {
      var gr = new GlideRecord(this.CI_COUNTS_TABLE_NAME);
      gr.addQuery('value_stream', valueStream);
      gr.addQuery('sku', this.skuId);
      gr.addQuery('category', category);
      gr.addQuery('is_aggregated', true);
      gr.addQuery('sys_domain', domain);
      gr.query();
      var hasNext = gr.next();
      this._setValues(gr, values);
      if (hasNext) {
          gr.update();
      } else {
          gr.setValue('value_stream', valueStream);
          gr.setValue('sku', this.skuId);
          gr.setValue('category', category);
          gr.setValue('is_aggregated', true);
          gr.setValue('sys_domain', domain);
          gr.insert();
      }
  },

  _setValues: function(gr, values) {
      for (var key in values) {
          var value = values[key];
          if (key == 'su_ratio') {
              // Formatting ratio, assuming "to one"
              value = value + ":1";
          }
          gr.setValue(key, value);
      }
  },

  _calcSuCount: function(count, devicesPerSu) {
      if (devicesPerSu == 0)
          return 0;

      return parseInt(Math.floor(count / devicesPerSu));
  },

  _getLicensableValueStreams: function(skuBasedLicenseInfoList) {
      var i;
      var valueStreams = [];
      for (i = 0; i < skuBasedLicenseInfoList.length; i++) {
          var gr = new GlideRecord('itom_lu_bundle_mappings');
          var bundleId = skuBasedLicenseInfoList[i].app_bundle;
          gr.addQuery('bundle_id', bundleId);
          gr.query();
          while (gr.next()) {
              var vs = gr.getDisplayValue('value_stream');
              vs = vs.split(",");
              vs.forEach(function(obj) {
                  obj = this.utils._localizationSupportForValueStreamName(obj);
                  if (valueStreams.indexOf(obj) == -1)
                      valueStreams.push(obj);
              }.bind(this));
          }
      }

      return valueStreams;
  },
  
  _getCategoryNamesBasedonValueStream: function(valueStream, skuType) {
      var licenseInfoList = this.utils._getItomLicenseInfo();

      if (!licenseInfoList.length) {
          gs.error('Could not retreive license information from GlideEntitlement API');
          return [];
      }

      var skuList = this.metadataUtil.bundleMapping[valueStream];
      var bundleListforSKU = this.metadataUtil.getBundleIdFromSkuType(skuType);

      if (!skuList) {
          gs.error('Could not retreive a list of Bundles for a given valuestream');
          return [];
      }

      var categories = [];
      for (var i = 0; i < licenseInfoList.length; i++) {
          var sku = licenseInfoList[i];
          var ratioInfo = sku.ciTypeToSURatioMap || sku.su_ratio;
          if (new global.ArrayUtil().contains(skuList, sku.app_bundle) && new global.ArrayUtil().contains(bundleListforSKU, sku.app_bundle) && ratioInfo) {
              if (sku.app_bundle.indexOf(skuType) != -1) {
                  categories = this.metadataUtil.getCategoriesOfSku(ratioInfo);
                  break;
              } else if (skuType == 'itom') {
                  categories = this.metadataUtil.getCategoriesOfSku(ratioInfo);
                  break;
              }
          }
      }
      if (new global.ArrayUtil().contains(categories, this.metadataUtil.getCategoryNameForUnknown()) && "health" != valueStream && "hla" != valueStream)
          categories = categories.filter(function(category) {
              return category != this.metadataUtil.getCategoryNameForUnknown();
          }, this);
      return categories;
  },

  _removeStaleRecords: function() {
      var tableGr = new GlideRecord('itom_lu_ci_counts');
      tableGr.addQuery('sys_updated_on', '<', this.jobStartTime);
      tableGr.addQuery('is_aggregated', true);
      tableGr.addQuery('sku', this.skuId);
      tableGr.query();
      tableGr.deleteMultiple();
  },
  
  _getSkuBasedLicenseInfoList: function(skuType) {
  	var skuBasedLicenseInfoList = [];
  	this.instanceSkuList.forEach(function(obj) {
  		if (skuType == 'otm' && obj.app_bundle.indexOf('otm') != -1) 
  			skuBasedLicenseInfoList.push(obj);
  		else if (skuType == 'itom' && obj.app_bundle.indexOf('otm') == -1) 
  			skuBasedLicenseInfoList.push(obj);
  	});
  	return skuBasedLicenseInfoList;
  },

  type: 'ITOMLicensingAggregationHelperStore'
};

Sys ID

4fd8ef1b5375301046dfddeeff7b121d

Offical Documentation

Official Docs: