Name

sn_service_builder.ASBPublishService

Description

No description available

Script

var ASBPublishService = Class.create();
ASBPublishService.prototype = {
  initialize: function() {
      this.utils = new sn_service_builder.ASBUtils();
      this.CONSTANTS = new sn_service_builder.ASBConstants();
      this.DPM_ACTIVE = GlidePluginManager.isActive('com.snc.dpm');

      if (this.DPM_ACTIVE)
          this.DPM_SB_UTILS = new sn_service_builder.ASBUtilsDPM();
  },

  /**
   * publishService
   * copies the data of the draft service to the published service and 
   * deletes the draft records
   *
   * @param {string} serviceTable - the service table ie cmdb_ci_service_business
   * @param {sysId} serviceId - the service that will be published
   * @returns {boolean} true if succeeded, false otherwise
   */
  publishService: function (serviceTable, serviceId) {
      //Get the draft service
      var draftServiceGr = new GlideRecord(serviceTable);
      if (!draftServiceGr.get(serviceId))
          return false;

      //Check if the draft service is a new service
      if (draftServiceGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF) === null) {

          //Since it is new, there is no original to copy data to and no reference tables need updating
          try {
              this._publishNewService(draftServiceGr);
          } catch (err) {
              //Error while publishing rollback by setting service and offerings back to draft
              gs.error('[ASB] Could not publish service');
              return false;
          }
          return true;
      }

      try {
          this._publishExistingService(draftServiceGr);
      } catch (err) {
          //There was an error while publishing, so rollback
          gs.error('[ASB] Problem while publishing ' + draftServiceGr + ': ' + err);
          return false;
      }

      return true;
  },

  /**
   * _publishNewService
   * publishes the new service and its offerings
   *
   * @param {GlideRecord} serviceGr - the service that will be published
   */
  _publishNewService: function(serviceGr) {
      if (!serviceGr || !serviceGr.isValidRecord())
          throw "Error while updating Service: invalid service passed into method";

      // update offerings first
      var offeringGr = new GlideRecord(this.CONSTANTS.TABLE.SERVICE_OFFERING);
      offeringGr.addQuery(this.CONSTANTS.FIELD.PARENT, serviceGr.getUniqueValue());
      offeringGr.query();
      while (offeringGr.next()) {
          var offeringCheckoutResult = this.utils.setCheckoutState(offeringGr,
              this.CONSTANTS.FIELD_VALUE.FALSE,
              this.CONSTANTS.FIELD_VALUE.PUBLISHED);

          if (!offeringCheckoutResult)
              throw 'Error while updating Offering: ' + offeringGr.getValue(this.CONSTANTS.FIELD.NAME) + ': ' + offeringGr.getUniqueValue();
      }

      var result = this.utils.setCheckoutState(serviceGr,
          this.CONSTANTS.FIELD_VALUE.FALSE,
          this.CONSTANTS.FIELD_VALUE.PUBLISHED);

      if (!result)
          throw 'Error while updating Service: ' + serviceGr.getValue(this.CONSTANTS.FIELD.NAME) + ': ' + serviceGr.getUniqueValue();
  },

  /**
   * _publishExistingService
   * publishes the draft service and its offerings
   *
   * @param {GlideRecord} draftServiceGr - the service that will be published
   */
  _publishExistingService: function (draftServiceGr) {

      // 1. Publish new offerings
      // 2. Publish existing offerings with changes
      // 3. Delete offerings without a "draft" offering record

      //get offerings to publish first
      var draftOfferingsGr = new GlideRecord(this.CONSTANTS.TABLE.SERVICE_OFFERING);
      draftOfferingsGr.addQuery(this.CONSTANTS.FIELD.PARENT, draftServiceGr.getUniqueValue());
      draftOfferingsGr.query();

      // Update offerings
      // We use validOfferingIds to keep track of the offerings that we've processed (new and updated offerings).
      // Offering that is not in the sys id list, means that we've deleted the draft offering and the published record
      // should be deleted as well.
      var validOfferingIds = '';
      while (draftOfferingsGr.next()) {
          var offeringPublishedRef = draftOfferingsGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF);
          if (offeringPublishedRef)
              validOfferingIds += offeringPublishedRef+',';
          // If it doesn't have a published_ref, then it means it is a newly created offering, so push draft Id.
          else
              validOfferingIds += draftOfferingsGr.getUniqueValue()+',';
          this._publishOffering(draftOfferingsGr, draftServiceGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF));
      }

      var serviceRefTableMappings = {};
      if (this.DPM_ACTIVE)
          serviceRefTableMappings = this.DPM_SB_UTILS.getReferenceTableMappings(draftServiceGr.getTableName());

      serviceRefTableMappings[this.CONSTANTS.TABLE.CMDB_REL_CI] = {
          field: this.CONSTANTS.FIELD.CHILD,
          query: this.CONSTANTS.FIELD.TYPE + '=' + this.CONSTANTS.FIELD_VALUE.PROVIDES_BY_PROVIDES
      };

      // update reference tables
      for (var tableName in serviceRefTableMappings) {
          if (serviceRefTableMappings.hasOwnProperty(tableName)) {
              this.updateReferences(tableName,
                  serviceRefTableMappings[tableName].field,
                  draftServiceGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF),
                  draftServiceGr.getUniqueValue(),
                  (serviceRefTableMappings[tableName].query || null));
          }
      }

      //copy draft data to published record
      var publishedServiceGr = new GlideRecord(draftServiceGr.getTableName());
      publishedServiceGr.get(draftServiceGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF));
      this.utils.copyFields(draftServiceGr, publishedServiceGr, this.CONSTANTS.EXCLUDED_SERVICE_FIELDS());
      if (publishedServiceGr.update() == null)
          throw 'Could not copy draft record data to published record for ' + draftOfferingGr.name;

      //delete draft
      if (!draftServiceGr.deleteRecord())
          throw 'Could not delete draft record for ' + draftServiceGr.name;

      //update published state for service and offerings
      this._publishNewService(publishedServiceGr);
  },

  _publishOffering: function(draftOfferingGr, publishedServiceId) {
      // If published record exists (update offering)
      if (draftOfferingGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF)) {
          
          //copy data from draft to published
          var publishedOfferingGr = new GlideRecord(this.CONSTANTS.TABLE.SERVICE_OFFERING);
          publishedOfferingGr.get(draftOfferingGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF));
          this.utils.copyFields(draftOfferingGr, publishedOfferingGr, this.CONSTANTS.EXCLUDED_OFFERING_FIELDS());
          if (publishedOfferingGr.update() == null)
              throw 'Could not copy draft record data to published record for ' + draftOfferingGr.name;


          //Note: May want a different method for handling commitments
          var subscribeTables = [
              this.CONSTANTS.TABLE.SERVICE_SUBSCRIBE_COMPANY,
              this.CONSTANTS.TABLE.SERVICE_SUBSCRIBE_DEPARTMENT,
              this.CONSTANTS.TABLE.SERVICE_SUBSCRIBE_LOCATION,
              this.CONSTANTS.TABLE.SERVICE_SUBSCRIBE_SYS_USER_GRP,
              this.CONSTANTS.TABLE.SERVICE_SUBSCRIBE_SYS_USER,
              this.CONSTANTS.TABLE.SERVICE_OFFERING_COMMITMENT,
              this.CONSTANTS.TABLE.SC_CAT_ITEM_SUBSCRIBE_MTOM
          ];

          var offeringRefTableMappings = {};
          if (this.DPM_ACTIVE)
              offeringRefTableMappings = this.DPM_SB_UTILS.getReferenceTableMappings(this.CONSTANTS.TABLE.SERVICE_OFFERING);

          offeringRefTableMappings[this.CONSTANTS.TABLE.CMDB_REL_CI] = {
              field: this.CONSTANTS.FIELD.PARENT,
              query: this.CONSTANTS.FIELD.TYPE + '=' + this.CONSTANTS.FIELD_VALUE.DEPENDS_ON_USED_BY
          };
  
          for (var i = 0; i < subscribeTables.length; i++) {
              this.updateReferences(subscribeTables[i],
                  this.CONSTANTS.FIELD.SERVICE_OFFERING,
                  draftOfferingGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF),
                  draftOfferingGr.getUniqueValue());
          }

          for (var tableName in offeringRefTableMappings) {
              if (offeringRefTableMappings.hasOwnProperty(tableName)) {
                  this.updateReferences(tableName,
                      offeringRefTableMappings[tableName].field,
                      draftOfferingGr.getValue(this.CONSTANTS.FIELD.PUBLISHED_REF),
                      draftOfferingGr.getUniqueValue(),
                      (offeringRefTableMappings[tableName].query || null));
              }
          }

          //delete draft
          if (!draftOfferingGr.deleteRecord())
              throw 'Could not delete draft record for ' + draftOfferingGr.name;

          // Else it is a new offering created in SB
      } else {
          draftOfferingGr.setValue(this.CONSTANTS.FIELD.PARENT, publishedServiceId);
          draftOfferingGr.update();
      }
  },

  /**
   * updateReferences
   * deletes the entries of the published record and updates
   * the entries of the draft record to be the published record
   *
   * @param {string} tableName - the mtom table ie cmdb_rel_ci
   * @param {string} refrenceField - the field that contains the reference to the item
   * @param {sysId} publishedId - the id of the record that is published
   * @param {sysId} draftId - the id of the record that is in draft
   * @param {string} encodedQuery - optional: additional query to filter records on
   */
  updateReferences: function(tableName, referenceField, publishedId, draftId, encodedQuery) {
      //delete all of the records with a reference to the publishedId
      this.utils.deleteReferences(tableName, referenceField, publishedId, encodedQuery);

      //update all of the records with a reference to the draft Id, to have
      //a reference to the publishedId instead
      var draftGr = new GlideRecord(tableName);
      draftGr.addQuery(referenceField, draftId);
      if (encodedQuery)
          draftGr.addEncodedQuery(encodedQuery);
      draftGr.query();
      while (draftGr.next()) {
          draftGr.setValue(referenceField, publishedId);
          if (!draftGr.update()) 
              throw 'Could not update ' + tableName + ' references from ' + draftId + ' to ' + publishedId;
      }
  },

  /* Method that deletes orphaned offerings.
   * @param {GlideRecord} publishedServiceGr - GlideRecord of the published parent service.
   * @param {string} validOfferingIds - String with comma separated offering sys ids. These are the sys
   */
  _deleteOrphanedOfferings: function(publishedServiceGr, validOfferingIds) {
      var publishedServiceId = publishedServiceGr.getUniqueValue();

      if (!publishedServiceId)
          throw 'Could not get service id';

      var orphanedOfferings = new GlideRecord(this.CONSTANTS.TABLE.SERVICE_OFFERING);
      orphanedOfferings.addQuery('parent', publishedServiceId);
      orphanedOfferings.addQuery('sys_id', 'NOT IN', validOfferingIds);
      orphanedOfferings.query();

      if (orphanedOfferings.getRowCount() === 0)
          return;

      orphanedOfferings.deleteMultiple();
  },

  type: 'ASBPublishService'
};

Sys ID

465586ea07b2201070e493d0fad3003d

Offical Documentation

Official Docs: