Name

sn_nb_action.ActionServiceImpl

Description

A service to manage actions and interact with action handlers

Script

var ActionServiceImpl = Class.create();
ActionServiceImpl.prototype = {
  initialize: function() {
      this.nextBestActionDAO = sn_nb_action.NextBestActionUtil.getNextBestActionDAO();
      this._log = new global.GSLog(sn_nb_action.Constants.PROP_LOG_LEVEL, this.type);
  },
  getActionsForUnsavedChanges: function(contextRecord, currentRecord, recommendationType, currentActions) {
      var actionDetails = [];
      var actionDetailsInNewState = [];
      var actionDetailsInCompletedState = [];
      var actionDetailsInSkippedState = [];
      var result = {};
      result.contextId = contextRecord.getUniqueValue();
      result.contextState = contextRecord.getValue(sn_nb_action.Constants.COL_STATE);
      var ruleOrderObj = this._getRuleOrder(currentActions);
      for (var key in currentActions) {
          if (currentActions.hasOwnProperty(key)) {
              for (var i = 0; i < currentActions[key].length; i++) {
                  var currentDetail = currentActions[key][i];
                  var detailObject = this._getActionDetailObject(currentRecord, currentDetail, ruleOrderObj);
                  this._pushToDetailOrders(detailObject, actionDetails, actionDetailsInNewState, actionDetailsInCompletedState, actionDetailsInSkippedState);
              }
          }
      }
      actionDetailsInNewState.sort(this._sortByActionScore);
      actionDetails = this._appendActionDetails(actionDetails, actionDetailsInNewState);
      actionDetails = this._appendActionDetails(actionDetails, actionDetailsInCompletedState);
      actionDetails = this._appendActionDetails(actionDetails, actionDetailsInSkippedState);
      result.actionDetails = actionDetails;
      return result;
  },
  getActions: function(contextRecord, currentRecord, recommendationType, currentActions) {
      var states = [sn_nb_action.Constants.STATE_NEW, sn_nb_action.Constants.STATE_IN_PROGRESS,
          sn_nb_action.Constants.STATE_COMPLETED, sn_nb_action.Constants.STATE_SKIPPED, sn_nb_action.Constants.STATE_IN_ERROR, sn_nb_action.Constants.STATE_ERROR_SKIPPED
      ];
      var ruleOrderObj = this._getRuleOrderObj(contextRecord, sn_nb_action.Constants.STATE_NEW, recommendationType);
      var actionDetailRecords = this.nextBestActionDAO.getAllActionDetails(contextRecord, states, recommendationType);
      var result = {};
      result.contextId = contextRecord.getUniqueValue();
      result.contextState = contextRecord.getValue(sn_nb_action.Constants.COL_STATE);
      var actionDetails = [];
      var actionDetailsInNewState = [];
      var actionDetailsInCompletedState = [];
      var actionDetailsInSkippedState = [];
      if (actionDetailRecords) {
          while (actionDetailRecords.next()) {

              if (!gs.nil(actionDetailRecords[sn_nb_action.Constants.COL_RULE]))
                  this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecords);

              var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecords);
              var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecords, actionDetailOrders);
              if (!this._hasActiveActionDetailOrder(actionDetObj) && !this._persistActionDetail(actionDetObj))
                  continue;
              else if (actionDetObj.getState() == sn_nb_action.Constants.STATE_NEW && actionDetObj.getParentActionId()) {
                  var hideRA = this.hideRecommendation(actionDetailRecords);
                  if (hideRA)
                      continue;
              }

              try {
                  var actionDetail = this._fetchActionDetailProps(currentRecord, actionDetailRecords, actionDetObj, ruleOrderObj);
                  this._pushToDetailOrders(actionDetail, actionDetails, actionDetailsInNewState, actionDetailsInCompletedState, actionDetailsInSkippedState);
              } catch (ex) {
                  this._log.error("Cannot fetch details for action detail " + actionDetailRecords.getUniqueValue());
              }
          }
          actionDetailsInNewState.sort(this._sortByActionScore);
          actionDetails = this._appendActionDetails(actionDetails, actionDetailsInNewState);
          actionDetails = this._appendActionDetails(actionDetails, actionDetailsInCompletedState);
          actionDetails = this._appendActionDetails(actionDetails, actionDetailsInSkippedState);
      }
      result.actionDetails = actionDetails;
      return result;
  },
  _pushToDetailOrders: function(detailObject, actionDetails, actionDetailsInNewState, actionDetailsInCompletedState, actionDetailsInSkippedState) {
      if (detailObject) {
          if (detailObject.actionState.value == sn_nb_action.Constants.STATE_IN_PROGRESS)
              actionDetails.push(detailObject);
          else if (detailObject.actionState.value == sn_nb_action.Constants.STATE_NEW)
              actionDetailsInNewState.push(detailObject);
          else if (detailObject.actionState.value == sn_nb_action.Constants.STATE_COMPLETED)
              actionDetailsInCompletedState.push(detailObject);
          else
              actionDetailsInSkippedState.push(detailObject);
      }
  },
  _getActionTypeRecord: function(currentDetail) {
      var actionTypeRecord = new GlideRecord(sn_nb_action.Constants.TBL_ACTION_TYPE_DEFINITION);
      actionTypeRecord.get(currentDetail.actionTypeSysId);
      return actionTypeRecord;
  },
  _getActionRecord: function(currentDetail) {
      var actionRecord = new GlideRecord(currentDetail.actionTypeTable);
      actionRecord.get(currentDetail.actionSysId);
      return actionRecord;
  },
  executeAction: function(contextRecord, currentRecord, actionDetailSysId, actionMetadata) {
      var actionDetailRecord;
      if (sn_nb_action.NextBestActionUtil.isValidString(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      // if actionDetailSysId still contains actionSysId value try fetching actionDetailRecord again
      if (!sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionDetailSysId);
      var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
      var actionHandler = this._getActionHandler(actionDetailRecord);
      var actionObj = actionHandler.executeAction(currentRecord, actionRecord, actionDetailRecord[sn_nb_action.Constants.COL_ACTION_INPUTS], sn_nb_action.Constants.TBL_ACTION_DETAIL, actionDetailRecord.getUniqueValue(), actionMetadata);
      actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);
      actionObj[sn_nb_action.Constants.COL_STATE] = actionDetailRecord[sn_nb_action.Constants.COL_STATE];
      return actionObj;
  },
  useAction: function(contextRecord, currentRecord, actionDetailSysId) {
      var actionDetailRecord;
      if (sn_nb_action.NextBestActionUtil.isValidString(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      // if actionDetailSysId still contains actionSysId value try fetching actionDetailRecord again
      if (!sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionDetailSysId);

      if (this.hideRecommendation(actionDetailRecord)) {
          return this._getHideActionResponse();
      }
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);

          var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecord);
          var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecord, actionDetailOrders);

          var currentState = actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE);
          if (actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE) != sn_nb_action.Constants.STATE_NEW && actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE) != sn_nb_action.Constants.STATE_IN_PROGRESS) {
              this._log.error("Cannot use action detail " + actionDetailRecord.getUniqueValue() + ", state : " + currentState);
              return false;
          }

          if (!this._hasActiveActionDetailOrder(actionDetObj)) {
              this._log.error("Action detail " + actionDetailRecord.getUniqueValue() + ", cannot be started by user: " + gs.getUserDisplayName());
              return false;
          }

          var actionHandler = this._getActionHandler(actionDetailRecord);
          if (actionHandler && typeof actionHandler.initializeAction === "function") {
              var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
              if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
                  try {
                      if (!sn_nb_action.NextBestActionUtil.isValidString(actionDetailRecord.attribute)) {
                          var actionObj = actionHandler.initializeAction(currentRecord, actionRecord, actionDetailRecord[sn_nb_action.Constants.COL_ACTION_INPUTS], sn_nb_action.Constants.TBL_ACTION_DETAIL, actionDetailRecord.getUniqueValue());
                          var actionState = sn_nb_action.Constants.STATE_IN_PROGRESS;
                          if (actionObj.actionState && actionObj.actionState != null && actionObj.actionState != "")
                              actionState = actionObj.actionState;
                          if (actionObj.actionAttr && actionObj.actionAttr != null) {
                              this.nextBestActionDAO.setActionAttribute(actionDetailRecord, actionObj.actionAttr);
                              actionDetObj.setAttribute(JSON.stringify(actionObj.actionAttr));
                          } else
                              actionObj.actionAttr = "";
                          this.nextBestActionDAO.setActionState(actionDetailRecord, actionState);
                          actionDetObj.setState(actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE));
                          actionDetObj.setStateDisplayValue(actionDetailRecord.getDisplayValue(sn_nb_action.Constants.COL_STATE));
                          this._log.debug("Action " + actionRecord.getUniqueValue() + " initialized.");
                      }
                      return this._fetchActionDetailProps(currentRecord, actionDetailRecord, actionDetObj);
                  } catch (ex) {
                      this._log.error("Failed to initialize action " + actionRecord.getUniqueValue() + "; " + ex);
                  }
              } else
                  this._log.error("Could not find the action recommended in detail " + actionDetailRecord.getUniqueValue());
          } else
              this._log.error("Could not find the handler for action recommended in detail " + actionDetailRecord.getUniqueValue());
      } else
          this._log.warn("Could not find action detail for action " + actionDetailSysId);
      return false;

  },

  dismissAction: function(contextRecord, currentRecord, actionDetailSysId) {
      var actionDetailRecord;
      if (sn_nb_action.NextBestActionUtil.isValidString(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      // if actionDetailSysId still contains actionSysId value try fetching actionDetailRecord again
      if (!sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionDetailSysId);
      if (this.hideRecommendation(actionDetailRecord)) {
          return this._getHideActionResponse();
      }
      var currentState = actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE);
      if (currentState == sn_nb_action.Constants.STATE_NEW) {
          this._changeState(actionDetailRecord, sn_nb_action.Constants.STATE_SKIPPED);
          return;
      }
      if (currentState == sn_nb_action.Constants.STATE_IN_PROGRESS || currentState == sn_nb_action.Constants.STATE_IN_ERROR) {
          var actionHandler = this._getActionHandler(actionDetailRecord);
          if (actionHandler) {
              var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
              if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
                  try {
                      if (typeof actionHandler.dismissAction === "function") {
                          actionHandler.dismissAction(currentRecord, actionRecord, actionDetailRecord.getValue(sn_nb_action.Constants.COL_ATTRIBUTE));
                      }
                  } catch (ex) {
                      this._log.error("Failed to dismiss the recommended actions " + actionRecord.getUniqueValue());
                  }
              }
          } else
              this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
      }
      return;
  },

  getActionDetail: function(contextRecord, currentRecord, actionDetailSysId) {
      var actionDetailRecord;
      if (sn_nb_action.NextBestActionUtil.isValidString(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      // if actionDetailSysId still contains actionSysId value try fetching actionDetailRecord again
      if (!sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionDetailSysId);

      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);

          var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecord);
          var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecord, actionDetailOrders);

          var currentState = actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE);
          if (currentState == sn_nb_action.Constants.STATE_NEW && !this._hasActiveActionDetailOrder(actionDetObj)) {
              this._log.error("Action detail " + actionDetailRecord.getUniqueValue() + ", cannot be fetched by user: " + gs.getUserDisplayName());
              return false;
          }
          return this._fetchActionDetailProps(currentRecord, actionDetailRecord, actionDetObj);
      } else
          this._log.warn("Could not find action detail for the sys id " + actionDetailSysId);
      return false;
  },
  _getActionScore: function(actionDetObj, ruleOrderObj) {
      var actionScore = 0;
      var state = actionDetObj.getState();
      if (!gs.nil(ruleOrderObj)) {
          var actionOrders = [];
          var ruleActionOrderObj = actionDetObj.getRules();
          for (var rule in ruleActionOrderObj)
              actionOrders.push(ruleActionOrderObj[rule]);
          actionOrders.sort(this._compareByInterOrder);
          if (state == sn_nb_action.Constants.STATE_NEW)
              actionScore = new sn_nb_action.NextBestActionRanking().getActionScore(actionOrders, ruleOrderObj);
          if (gs.nil(actionOrders))
              return false;
      }
      return actionScore;
  },
  _getTag: function(actionTypeRecord) {
      var tag = '';
      var rendererRecord = actionTypeRecord[sn_nb_action.Constants.COL_RENDERER].getRefRecord();
      if (sn_nb_action.NextBestActionUtil.isValidRecord(rendererRecord))
          tag = rendererRecord.getValue(sn_nb_action.Constants.COL_TAG) || "";
      return tag;
  },
  _getIconName: function(actionTypeRecord) {
      var iconName = '';
      var designIconRecord = actionTypeRecord[sn_nb_action.Constants.COL_ICON].getRefRecord();
      if (sn_nb_action.NextBestActionUtil.isValidRecord(designIconRecord))
          iconName = designIconRecord.getValue(sn_nb_action.Constants.COL_NAME) || "";
      return iconName;
  },
  _getHint: function(rules) {
      var rAOrderArray = sn_nb_action.NextBestActionUtil.getObjectValues(rules);
      rAOrderArray.sort(this._compareByInterOrder);
      if (rAOrderArray.length > 0)
          return rAOrderArray[0].getHint();
      return false;
  },
  _getAttribute: function(actionDetObj) {
      var attribute = actionDetObj.getAttribute();
      var attrVal;
      if (!gs.nil(attribute))
          attrVal = JSON.parse(attribute);
      if (!sn_nb_action.NextBestActionUtil.isValidString(attrVal))
          attrVal = "";
      return attrVal;

  },
  _getActionDetailObject: function(currentRecord, currentDetail, ruleOrderObj) {
      var actionTypeRecord = this._getActionTypeRecord(currentDetail);
      var actionRecord = this._getActionRecord(currentDetail);
      var actionDetObj = sn_nb_action.ActionDetail.createFromUnsavedRecord(currentDetail, currentDetail.actionTypeTable, currentDetail.actionTypeSysId, actionRecord.getUniqueValue(), currentDetail.actionInputs);
      this._setTitleAndDescription(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetObj);
      this._setCallToActions(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetObj);
      this._setCustomAttributes(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetObj);
      var actionType = actionTypeRecord.getDisplayValue(sn_nb_action.Constants.COL_TITLE);
      var tag = this._getTag(actionTypeRecord);
      var iconName = this._getIconName(actionTypeRecord);
      var hint = this._getHint(currentDetail.ruleSysIds);
      var actionScore = this._getActionScore(actionDetObj, ruleOrderObj);
      var attrVal = this._getAttribute(actionDetObj);
      var actionDetail = {
          actionId: actionDetObj.getAction(),
          actionDetailId: actionDetObj.getId(),
          actionType: actionType,
          actionState: {
              label: actionDetObj.getStateDisplayValue(),
              value: actionDetObj.getState()
          },
          title: actionDetObj.getTitle(),
          description: actionDetObj.getDescription(),
          recommendationHint: hint,
          callToActions: actionDetObj.getCallToActions(),
          renderer: tag,
          iconName: iconName,
          createdOn: actionDetObj.getCreatedOn(),
          updatedOn: actionDetObj.getUpdatedOn(),
          attributes: attrVal,
          actionScore: actionScore,
          customAttributes: actionDetObj.getCustomAttribute()
      };
      if (actionDetObj.getState() == sn_nb_action.Constants.STATE_IN_ERROR ||
          actionDetObj.getState() == sn_nb_action.Constants.STATE_ERROR_SKIPPED) {
          actionDetail['errorMessage'] = actionDetObj.getErrorMessage();
      }
      return actionDetail;
  },
  _fetchActionDetailProps: function(currentRecord, actionDetailRecord, actionDetObj, ruleOrderObj) {
      this._addTitleAndDescription(currentRecord, actionDetailRecord, actionDetObj);
      this._addCallToActions(currentRecord, actionDetailRecord, actionDetObj);
      this._addCustomAttributes(currentRecord, actionDetailRecord, actionDetObj);
      this._addCustomPreviewExpereince(currentRecord, actionDetailRecord, actionDetObj);
      if (actionDetailRecord.state == sn_nb_action.Constants.STATE_IN_ERROR || actionDetailRecord.state == sn_nb_action.Constants.STATE_ERROR_SKIPPED) {
          this._addErrorMessage(actionDetailRecord, actionDetObj);
      }
      var attrVal = JSON.parse(actionDetObj.getAttribute());
      if (!sn_nb_action.NextBestActionUtil.isValidString(attrVal))
          attrVal = "";
      var actionType = "";
      var tag = "";
      var iconName = "";
      //to handle upgrade scenario for completed guidances
      var currentState = actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE);
      if (currentState == sn_nb_action.Constants.STATE_COMPLETED && attrVal.recommender && !attrVal.hasOwnProperty('actionOutputs'))
          attrVal = this._updateActionDetailAttributes(actionDetailRecord);
      var actionTypeRecord = actionDetailRecord[sn_nb_action.Constants.COL_ACTION_TYPE].getRefRecord();
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionTypeRecord)) {
          actionType = actionTypeRecord.getDisplayValue(sn_nb_action.Constants.COL_TITLE);
          var rendererRecord = actionTypeRecord[sn_nb_action.Constants.COL_RENDERER].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(rendererRecord))
              tag = rendererRecord.getValue(sn_nb_action.Constants.COL_TAG) || "";
          var designIconRecord = actionTypeRecord[sn_nb_action.Constants.COL_ICON].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(designIconRecord))
              iconName = designIconRecord.getValue(sn_nb_action.Constants.COL_NAME) || "";
      }
      var actionScore = 0;
      if (!gs.nil(ruleOrderObj)) {
          var actionOrders = [];
          var ruleActionOrderObj = actionDetObj.getRules();
          for (var rule in ruleActionOrderObj) {
              if (ruleActionOrderObj[rule].isActive())
                  actionOrders.push(ruleActionOrderObj[rule]);
          }
          actionOrders.sort(this._compareByInterOrder);
          if (actionDetailRecord.state == sn_nb_action.Constants.STATE_NEW)
              actionScore = new sn_nb_action.NextBestActionRanking().getActionScore(actionOrders, ruleOrderObj);
          var hint = this._getHint(ruleActionOrderObj);
      }
      var actionDetail = {
          actionId: actionDetObj.getAction(),
          actionDetailId: actionDetObj.getId(),
          actionType: actionType,
          actionState: {
              label: actionDetObj.getStateDisplayValue(),
              value: actionDetObj.getState()
          },
          title: actionDetObj.getTitle(),
          description: actionDetObj.getDescription(),
          recommendationHint: hint,
          callToActions: actionDetObj.getCallToActions(),
          renderer: tag,
          iconName: iconName,
          createdOn: actionDetObj.getCreatedOn(),
          updatedOn: actionDetObj.getUpdatedOn(),
          attributes: attrVal,
          actionScore: actionScore,
          customAttributes: actionDetObj.getCustomAttribute(),
          customExperience: actionDetObj.getPreviewExperience(),
          actionGroups: actionDetObj.getActionGroupsAsCommaSeparatedString()
      };
      if (actionDetObj.getState() == sn_nb_action.Constants.STATE_IN_ERROR ||
          actionDetObj.getState() == sn_nb_action.Constants.STATE_ERROR_SKIPPED) {
          actionDetail['errorMessage'] = actionDetObj.getErrorMessage();
      }
      return actionDetail;
  },

  //Returns true if Action Detail Record has atleast one active Action Detail Order Record
  _hasActiveActionDetailOrder: function(actionDetObj) {
      var ruleActionOrderObj = actionDetObj.getRules();
      for (var rule in ruleActionOrderObj) {
          if (ruleActionOrderObj[rule].isActive())
              return true;
      }
      return false;
  },

  //updates the attributes of the action detail record
  _updateActionDetailAttributes: function(actionDetailRecord) {
      var attributes = JSON.parse(actionDetailRecord.getValue('attribute'));
      var actionDetails = this._getActionAttributes(actionDetailRecord);
      attributes['actionOutputs'] = actionDetails['actionOutputs'];
      attributes = JSON.stringify(attributes);
      actionDetailRecord.setValue('attribute', attributes);
      actionDetailRecord.update();
      return JSON.parse(attributes);
  },

  /*
   * Checks if current user on basis of roles should be allowed access the recommendation
   */
  _isAccessible: function(actionDetObj) {
      var ruleActionOrderObj = actionDetObj.getRules();
      for (var rule in ruleActionOrderObj) {
          if (gs.hasRole(ruleActionOrderObj[rule].getRoles()))
              return true;
      }
      return false;
  },

  // Returns true if a recommendation needs to persist even when rule recommending it is not satisfied anymore
  _persistActionDetail: function(actionDetObj) {
      var currentState = actionDetObj.getState();
      if (currentState == sn_nb_action.Constants.STATE_IN_PROGRESS || currentState == sn_nb_action.Constants.STATE_COMPLETED || currentState == sn_nb_action.Constants.STATE_SKIPPED)
          return true;
      return false;
  },

  ignoreAction: function(contextRecord, actionSysId) {
      var actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionSysId);
      if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
          this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);

      var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecord);
      var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecord, actionDetailOrders);

      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          return this._changeState(actionDetailRecord, sn_nb_action.Constants.STATE_IGNORED);
      } else
          this._log.warn("Could not find action detail for action " + actionSysId);
      return false;
  },

  skipAction: function(contextRecord, actionSysId, actionDetailSysId, actionInitialAttributes) {
      var actionDetailRecord;
      if (gs.nil(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionSysId);
      else
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      var attributes = actionDetailRecord.getValue('attribute');
      if (actionDetailRecord.state != sn_nb_action.Constants.STATE_SKIPPED && actionInitialAttributes && actionInitialAttributes.id == sn_nb_action.Constants.TBL_DECISION_TREE && gs.nil(attributes)) {
          this.nextBestActionDAO.setActionAttribute(actionDetailRecord, actionInitialAttributes.attributes);
      }
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);

          var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecord);
          var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecord, actionDetailOrders);
          var state = sn_nb_action.Constants.STATE_SKIPPED;
          if (actionDetailRecord.state == sn_nb_action.Constants.STATE_IN_ERROR) {
              state = sn_nb_action.Constants.STATE_ERROR_SKIPPED;
          }
          return this._changeState(actionDetailRecord, state);
      } else
          this._log.warn("Could not find action detail for action " + actionSysId);
      return false;
  },

  completeAction: function(contextRecord, actionSysId, actionDetailSysId, actionDetails, actionInitialAttributes) {
      var actionDetailRecord;
      if (gs.nil(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionSysId);
      else
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      if (actionDetailRecord.state != sn_nb_action.Constants.STATE_SKIPPED && actionInitialAttributes && actionInitialAttributes.id == sn_nb_action.Constants.TBL_DECISION_TREE && gs.nil(actionDetailRecord.getValue(sn_nb_action.Constants.COL_ATTRIBUTE)))
          this.nextBestActionDAO.setActionAttribute(actionDetailRecord, actionInitialAttributes.attributes);

      var attributes = JSON.parse(actionDetailRecord.getValue('attribute'));
      if (actionDetails) {
          for (var key in actionDetails)
              attributes[key] = actionDetails[key];
          attributes = JSON.stringify(attributes);
          actionDetailRecord.setValue('attribute', attributes);
          actionDetailRecord.update();
      }
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);

          var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecord);
          var actionDetObj = sn_nb_action.ActionDetail.createFromRecord(actionDetailRecord, actionDetailOrders);
          return this._changeState(actionDetailRecord, sn_nb_action.Constants.STATE_COMPLETED);
      } else
          this._log.warn("Could not find action detail for action " + actionSysId);
      return false;
  },

  progressAction: function(actionDetailSysId) {
      var actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          if (!gs.nil(actionDetailRecord[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecord);
          return this._changeState(actionDetailRecord, sn_nb_action.Constants.STATE_IN_PROGRESS);
      } else
          this._log.warn("Could not find action detail for action " + actionSysId + " when trying to set RA in_progress");
      return false;
  },

  _changeState: function(actionDetailRecord, state) {
      var currentState = actionDetailRecord.getValue(sn_nb_action.Constants.COL_STATE);
      if (currentState == sn_nb_action.Constants.STATE_NEW &&
          (state != sn_nb_action.Constants.STATE_IN_PROGRESS &&
              state != sn_nb_action.Constants.STATE_IGNORED &&
              state != sn_nb_action.Constants.STATE_SKIPPED &&
              state != sn_nb_action.Constants.STATE_COMPLETED &&
              state != sn_nb_action.Constants.STATE_IN_ERROR)) {
          this._log.error("Action state is new, it cannot be changed to " + state);
          return false;
      }

      if (currentState == sn_nb_action.Constants.STATE_IN_PROGRESS &&
          (state != sn_nb_action.Constants.STATE_SKIPPED &&
              state != sn_nb_action.Constants.STATE_COMPLETED &&
              state != sn_nb_action.Constants.STATE_IN_ERROR)) {
          this._log.error("Action state is in use, it cannot be changed to " + state);
          return false;
      }

      if (currentState == sn_nb_action.Constants.STATE_IGNORED ||
          currentState == sn_nb_action.Constants.STATE_SKIPPED ||
          currentState == sn_nb_action.Constants.STATE_COMPLETED) {
          this._log.error("Action state is " + currentState + ", it cannot be changed");
          return false;
      }
      return this.nextBestActionDAO.setActionState(actionDetailRecord, state);
  },

  hideRecommendation: function(actionDetailRecord) {
      var hash = actionDetailRecord.getValue(sn_nb_action.Constants.COL_PARENT_RA_ID);
      //for upgrade scenarios when hash is empty
      if (gs.nil(hash))
          return false;
      var stateAttributesList = this.nextBestActionDAO.getStatesAttributesListFromActionDetails(hash, actionDetailRecord);
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.hideRecommendation === "function") {
                      var hideAction = actionHandler.hideRecommendation(stateAttributesList, actionRecord);
                      return hideAction;
                  }
              } catch (ex) {
                  this._log.error("Failed to get hideAction value of recommended action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
  },
  _getHideActionResponse: function() {
      var response = {};
      response.actionStatus = sn_nb_action.Constants.STATUS_ERROR;
      response.statusCode = sn_nb_action.Constants.ERROR_405;
      response.errorMessage = sn_nb_action.Constants.RA_PERFORMED_MESSAGE;
      return response;
  },
  _setCallToActions: function(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetailObj) {
      var actionHandler = sn_nb_action.NextBestActionUtil.getActionTypeHandler(actionTypeRecord);
      if (actionHandler) {
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getActions === "function") {
                      var callToActions = actionHandler.getActions(actionRecord);
                      actionDetailObj.setCallToActions(callToActions);
                  }
              } catch (ex) {
                  this._log.error("Failed to get call to actions of recommended action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Error in implementing _setCallToActions");
  },
  _addCallToActions: function(currentRecord, actionDetailRecord, actionDetailObj) {
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getActions === "function") {
                      var callToActions = actionHandler.getActions(actionRecord);
                      actionDetailObj.setCallToActions(callToActions);
                  }
              } catch (ex) {
                  this._log.error("Failed to get call to actions of recommended action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
  },
  _getActionAttributes: function(actionDetailRecord) {
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getActionAttributes === "function") {
                      var actionAttributes = actionHandler.getActionAttributes(actionRecord, actionDetailRecord.getValue(sn_nb_action.Constants.COL_ATTRIBUTE));
                      return actionAttributes;
                  }
              } catch (ex) {
                  this._log.error("Failed to get action attributes of recommended action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
  },
  _setTitleAndDescription: function(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetailObj) {
      var actionHandler = sn_nb_action.NextBestActionUtil.getActionTypeHandler(actionTypeRecord);
      if (actionHandler) {
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getTitle === "function") {
                      title = actionHandler.getTitle(currentRecord, actionRecord, currentDetail.actionInputs);
                      if (sn_nb_action.NextBestActionUtil.isValidString(title))
                          actionDetailObj.setTitle(title);
                  }
                  if (actionHandler && typeof actionHandler.getDescription === "function") {
                      desc = actionHandler.getDescription(currentRecord, actionRecord, currentDetail.actionInputs);
                      if (sn_nb_action.NextBestActionUtil.isValidString(desc))
                          actionDetailObj.setDescription(desc);
                  }
              } catch (ex) {
                  this._log.error("Failed to get title/description of action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Error in implementing _setTitleAndDescription");
  },
  _addTitleAndDescription: function(currentRecord, actionDetailRecord, actionDetailObj) {
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getTitle === "function") {
                      var title = actionHandler.getTitle(currentRecord, actionRecord, actionDetailRecord[sn_nb_action.Constants.COL_ACTION_INPUTS]);
                      if (sn_nb_action.NextBestActionUtil.isValidString(title))
                          actionDetailObj.setTitle(title);
                  }
                  if (actionHandler && typeof actionHandler.getDescription === "function") {
                      var desc = actionHandler.getDescription(currentRecord, actionRecord, actionDetailRecord[sn_nb_action.Constants.COL_ACTION_INPUTS]);
                      if (sn_nb_action.NextBestActionUtil.isValidString(desc))
                          actionDetailObj.setDescription(desc);
                  }
              } catch (ex) {
                  this._log.error("Failed to get title/description of action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
  },
  _addCustomPreviewExpereince: function(currentRecord, actionDetailRecord, actionDetailObj) {

      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          try {
              if (typeof actionHandler.getCustomAttributes === "function") {
                  var previewExpereince = actionHandler.getPreviewExperience(currentRecord, actionRecord);
                  actionDetailObj.setPreviewExperience(previewExpereince);
              }
          } catch (ex) {
              this._log.error("Failed to get custom preview expereince of action " + actionRecord.getUniqueValue());
          }
      }
  },
  _setCustomAttributes: function(actionTypeRecord, actionRecord, currentRecord, currentDetail, actionDetailObj) {
      var actionHandler = sn_nb_action.NextBestActionUtil.getActionTypeHandler(actionTypeRecord);
      if (actionHandler) {
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getCustomAttributes === "function") {
                      var previewFields = actionHandler.getCustomAttributes(currentRecord, actionRecord, currentDetail.actionInputs);
                      actionDetailObj.setCustomAttribute(previewFields);
                  }
              } catch (ex) {
                  this._log.error("Failed to get custom attributes of action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type");
  },
  _addCustomAttributes: function(currentRecord, actionDetailRecord, actionDetailObj) {
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          var actionRecord = actionDetailRecord[sn_nb_action.Constants.COL_RECOMMENDED].getRefRecord();
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord)) {
              try {
                  if (typeof actionHandler.getCustomAttributes === "function") {
                      var previewFields = actionHandler.getCustomAttributes(currentRecord, actionRecord,
                          actionDetailRecord[sn_nb_action.Constants.COL_ACTION_INPUTS]);
                      actionDetailObj.setCustomAttribute(previewFields);
                  }
              } catch (ex) {
                  this._log.error("Failed to get custom attributes of action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementaion for action type " + actionDetailRecord.getUniqueValue());
  },

  _getActionHandler: function(actionDetailRecord) {
      var actionTypeRecord = actionDetailRecord[sn_nb_action.Constants.COL_ACTION_TYPE].getRefRecord();
      return sn_nb_action.NextBestActionUtil.getActionTypeHandler(actionTypeRecord);
  },

  // Called by NextBestActionService to check if action can handle tablename of rule record.
  isActionAllowed: function(tableName, actionRecord) {
      var actionTableName = actionRecord.getValue(sn_nb_action.Constants.COL_SYS_CLASS_NAME);
      var actionHandler = sn_nb_action.NextBestActionUtil.getActionTypeHandlerForTable(actionTableName);
      if (actionHandler && typeof actionHandler.isActionAllowed === "function")
          return actionHandler.isActionAllowed(tableName, actionRecord);
      else
          this._log.error("Could not find the handler for action table name" + actionTableName);
      return false;
  },

  _sortByActionScore: function(a, b) {
      if (b.actionScore > a.actionScore)
          return 1;
      if (b.actionScore < a.actionScore)
          return -1;
      return 0;
  },

  //Append Action Details
  _appendActionDetails: function(actionDetails, actionDetailsNotInUse) {
      var length = actionDetailsNotInUse.length;
      for (var i = 0; i < length; i++)
          actionDetails.push(actionDetailsNotInUse[i]);
      return actionDetails;
  },

  _getRuleOrder: function(currentActions) {
      var ruleOrderObj = {};
      for (var recommended in currentActions) {
          if (currentActions.hasOwnProperty(recommended)) {
              var actionDetails = currentActions[recommended];
              for (var i = 0; i < actionDetails.length; i++) {
                  var actionDetail = actionDetails[i];
                  for (var rule in actionDetail.ruleSysIds) {
                      if (actionDetail.ruleSysIds.hasOwnProperty(rule)) {
                          var actionDetailOrder = actionDetail.ruleSysIds[rule];
                          ruleOrderObj[rule] = actionDetailOrder.interOrder;
                      }
                  }
              }
          }
      }
      var sortedArray = this._sortProperties(ruleOrderObj);
      ruleOrderObj = {};
      var length = sortedArray.length;
      for (var index = 0; index < length; index++)
          ruleOrderObj[sortedArray[index][0]] = sortedArray[index][1];
      var order = 1;
      for (var key in ruleOrderObj) {
          if (ruleOrderObj.hasOwnProperty(key)) {
              ruleOrderObj[key] = order;
              order = order + 1;
          }
      }
      return ruleOrderObj;
  },

  /**
   * Get all rules sorted on order
   *
   * @return Object
   **/
  _getRuleOrderObj: function(contextRecord, states, recommendationType) {
      var actionDetailRecords = this.nextBestActionDAO.getAllActionDetails(contextRecord, states, recommendationType);
      var ruleOrderObj = {};
      while (actionDetailRecords && actionDetailRecords.next()) {
          if (!gs.nil(actionDetailRecords[sn_nb_action.Constants.COL_RULE]))
              this.nextBestActionDAO.updateActionDetailOnUpgrade(actionDetailRecords);
          var actionDetailOrders = this.nextBestActionDAO.getActionDetailOrders(actionDetailRecords, true);
          while (actionDetailOrders && actionDetailOrders.next())
              ruleOrderObj[actionDetailOrders.getValue('rule')] = actionDetailOrders.getValue('inter_order');
      }
      var sortedArray = this._sortProperties(ruleOrderObj);
      ruleOrderObj = {};
      var length = sortedArray.length;
      for (var index = 0; index < length; index++)
          ruleOrderObj[sortedArray[index][0]] = sortedArray[index][1];
      var order = 1;
      for (var key in ruleOrderObj) {
          if (ruleOrderObj.hasOwnProperty(key)) {
              ruleOrderObj[key] = order;
              order = order + 1;
          }
      }
      return ruleOrderObj;
  },

  _sortProperties: function(obj) {
      var sortable = [];
      for (var key in obj)
          if (obj.hasOwnProperty(key))
              sortable.push([key, obj[key]]);
      sortable.sort(function(a, b) {
          return a[1] - b[1];
      });
      return sortable;
  },

  _compareByInterOrder: function(a, b) {
      if (a.getInterOrder() > b.getInterOrder())
          return 1;
      if (a.getInterOrder() < b.getInterOrder())
          return -1;
      return 0;
  },
  errorOutAction: function(contextRecord, actionSysId, actionDetailSysId, actionInitialAttributes) {
      var actionDetailRecord;
      if (gs.nil(actionDetailSysId))
          actionDetailRecord = this.nextBestActionDAO.getActionDetail(contextRecord, actionSysId);
      else
          actionDetailRecord = this.nextBestActionDAO.getActionDetailBySysId(actionDetailSysId);

      var attributes = actionDetailRecord.getValue('attribute');
      if (actionDetailRecord.state != sn_nb_action.Constants.STATE_SKIPPED && actionInitialAttributes && actionInitialAttributes.id == sn_nb_action.Constants.TBL_DECISION_TREE && gs.nil(attributes)) {
          this.nextBestActionDAO.setActionAttribute(actionDetailRecord, actionInitialAttributes.attributes);
      }
      if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
          return this._changeState(actionDetailRecord, sn_nb_action.Constants.STATE_IN_ERROR);
      } else
          this._log.warn("Could not find action detail for action " + actionSysId);
      return false;
  },
  _addErrorMessage: function(actionDetailRecord, actionDetailObj) {
      var actionHandler = this._getActionHandler(actionDetailRecord);
      if (actionHandler) {
          if (sn_nb_action.NextBestActionUtil.isValidRecord(actionDetailRecord)) {
              try {
                  if (typeof actionHandler.getErrorMessage === "function") {
                      var errorMessage = actionHandler.getErrorMessage(actionDetailRecord.getValue(sn_nb_action.Constants.COL_ATTRIBUTE));
                      if (sn_nb_action.NextBestActionUtil.isValidString(errorMessage))
                          actionDetailObj.setErrorMessage(errorMessage);
                  }
              } catch (ex) {
                  this._log.error("Failed to get error message of action " + actionRecord.getUniqueValue());
              }
          }
      } else
          this._log.error("Could not find implementation for action type " + actionDetailRecord.getUniqueValue());
  },
  type: 'ActionServiceImpl'
};

Sys ID

7ad6f1713b3e1010c24e870044efc4ac

Offical Documentation

Official Docs: