Name

sn_rf.RFActionService

Description

Class for sn_rf_recommendation_action table utility functions.

Script

var RFActionService = Class.create();

RFActionService.serializeEvaluationOutput = function(evaluationOutputs) {
  var ruleOutputs = {};
  // Serialize the rule outputs for generating recommendations
  var evaluationOutputsKeys = evaluationOutputs ? Object.keys(evaluationOutputs) : {};
  for (var idx1 = 0; idx1 < evaluationOutputsKeys.length; idx1++) {
      var output = {};
      var key = evaluationOutputsKeys[idx1];
      var value = evaluationOutputs[key];
      if (value && value.isValidRecord) {
          output[RFConstants.TYPE] = RFConstants.evaluationOutputTypes.REFERENCE;
          output[RFConstants.REFERENCE_TYPE] = value.getTableName();
          output[RFConstants.VALUE] = value.getValue(RFConstants.fields.SYS_ID);
      } else {
          output[RFConstants.TYPE] = RFConstants.evaluationOutputTypes.STRING;
          output[RFConstants.VALUE] = value;
      }
      ruleOutputs[key] = output;
  }
  return JSON.stringify(ruleOutputs);
};

RFActionService.createObjectFromRuleOutputs = function(ruleOutputsString) {
  var ruleOutputsObject = {};
  var ruleOutputsObjectDetails = {
      isAccessible: true,
      ruleOutputsObject: ruleOutputsObject
  };
  try {
      var ruleOutputs = JSON.parse(ruleOutputsString);
      var hiddenKeys = ruleOutputs[RFConstants.evaluatorVariable.HIDDEN_INTERNAL] &&
          ruleOutputs[RFConstants.evaluatorVariable.HIDDEN_INTERNAL][RFConstants.VALUE] || [];
      var keys = Object.keys(ruleOutputs);
      for (var idx1 = 0; idx1 < keys.length; idx1++) {
          var ruleOutput = ruleOutputs[keys[idx1]];
          var value = ruleOutput[RFConstants.VALUE];
          if (ruleOutput[RFConstants.TYPE] == RFConstants.evaluationOutputTypes.REFERENCE) {
              var table = ruleOutput[RFConstants.REFERENCE_TYPE];
              //Check if the record is accessible to logged-in user. Skip ACLs check if the schema element is hidden.
              if (hiddenKeys.indexOf(keys[idx1]) != -1) {
                  var gr = new GlideRecord(table);
              } else {
                  gr = new GlideRecordSecure(table);
              }
              if (gr.isValid() && gr.get(value)) {
                  ruleOutputsObject[keys[idx1]] = gr;
              } else {
                  ruleOutputsObjectDetails.isAccessible = false;
                  ruleOutputsObject[keys[idx1]] = value;
              }
          } else {
              ruleOutputsObject[keys[idx1]] = value;
          }
      }
  } catch (e) {
      new RFLogger("RFActionService - createObjectFromRuleOutputs").logError(e);
      return ruleOutputsObjectDetails;
  }
  return ruleOutputsObjectDetails;
};

RFActionService.discardRecommendation = function(contextRecord, ruleOutputsString, options) {
  var result = {};
  var ruleOutputs = RFActionService.createObjectFromRuleOutputs(ruleOutputsString).ruleOutputsObject;
  var historyId = RFActionService._addInHistory(contextRecord, ruleOutputs, ruleOutputsString, RFConstants.historyStatus.DISCARDED, options.experienceId, RFConstants.actionType.DISCARD);
  if (historyId) {
      result[RFConstants.experienceDetails.MESSAGE] = RFConstants.DISCARD_SUCCESS_MESSAGE;
  } else {
      result[RFConstants.ERROR_CODE] = 40001;
      result[RFConstants.ERROR_MESSAGE] = RFConstants.DISCARD_ERROR_MESSAGE;
      new RFLogger("RFActionService - discardRecommendation").logError(result[RFConstants.ERROR_MESSAGE]);
  }
  return result;
};

RFActionService._addInHistory = function(contextRecord, ruleOutputs, ruleOutputsString, status, experienceId, actionID) {
  var experience = new RFExperienceService(experienceId);
  return RFHistoryService.create(contextRecord, experienceId, actionID, experience.getPrimaryActionId() == actionID, status, ruleOutputs, ruleOutputsString);
};

RFActionService.prototype = {
  tableName: RFConstants.tables.SN_RF_RECOMMENDATION_ACTION,

  initialize: function(grOrSysId) {
      this.rfLogger = new RFLogger("RFActionService");
      if (grOrSysId && grOrSysId.sys_class_name == this.tableName) {
          this.currentRecord = grOrSysId;
      } else if (grOrSysId) {
          var actionGr = new GlideRecord(this.tableName);
          if (actionGr.get(grOrSysId)) {
              this.currentRecord = actionGr;
          }
      }
  },

  hasValidRecord: function() {
      return this.currentRecord && this.currentRecord.sys_class_name == this.tableName;
  },

  isActive: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_ACTIVE);
  },

  getLabel: function() {
      return this.currentRecord.getDisplayValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_LABEL);
  },

  getSysId: function() {
      return this.currentRecord.getValue(RFConstants.fields.SYS_ID);
  },

  getUndoActionSysId: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_UNDO_ACTION);
  },

  getUndoAction: function() {
      var undoActionId = this.getUndoActionSysId();
      if (undoActionId) {
          var action = new RFActionService(undoActionId);
          if (action.hasValidRecord()) {
              return action;
          }
      }
  },

  getType: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_TYPE);
  },

  isServerScript: function() {
      return this.getType() == RFConstants.actionType.SERVER_SCRIPT;
  },

  isSubflow: function() {
      return this.getType() == RFConstants.actionType.SUBFLOW;
  },

  isUXFClientAction: function() {
      return this.getType() == RFConstants.actionType.UXF_CLIENT_ACTION;
  },

  getServerScript: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_SERVER_SCRIPT);
  },

  getSubflow: function() {
      return this.currentRecord[RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_SUBFLOW].getRefRecord();
  },

  getActionKey: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_ACTION_KEY);
  },

  getActionClientPayload: function() {
      return this.currentRecord.getValue(RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_CLIENT_PAYLOAD);
  },

  markCompleteOrRevert: function(contextRecord, ruleOutputsString, isUndo, options) {
      var ruleOutputs = RFActionService.createObjectFromRuleOutputs(ruleOutputsString).ruleOutputsObject;
      var historyId = this._updateHistory(contextRecord, ruleOutputs, ruleOutputsString, isUndo, options);
      if (historyId) {
          return {
              message: RFConstants.EMPTY_STRING
          };
      } else {
          if (isUndo) {
              var exception = new RFExceptionManager("MARK_REVERT_FAILED");
          } else {
              exception = new RFExceptionManager("MARK_COMPLETE_FAILED");
          }
          this.rfLogger.logError(exception.getMessage(), "RFActionService - markCompleteOrRevert");
          return exception.getJSON();
      }
  },

  performAction: function(contextRecord, ruleOutputsString, isUndo, options) {
      var ruleOutputs = RFActionService.createObjectFromRuleOutputs(ruleOutputsString).ruleOutputsObject;
      var errorCode, errorMessage, message;
      var result = {};
      result[RFConstants.STATUS] = RFConstants.INITIALIZED;
      if (this.isServerScript()) {
          var evaluator = new GlideScopedEvaluator();
          evaluator.putVariable(RFConstants.actionVars.CURRENT, contextRecord);
          evaluator.putVariable(RFConstants.actionVars.RULE_OUTPUTS, ruleOutputs);
          result = evaluator.evaluateScript(this.currentRecord, RFConstants.fields.SN_RF_RECOMMENDATION_ACTION_SERVER_SCRIPT);
      } else if (this.isSubflow()) {
          var subflow = this.getSubflow();
          try {
              var inputs = {};
              inputs[RFConstants.actionVars.CURRENT] = contextRecord;
              inputs[RFConstants.actionVars.RULE_OUTPUTS_SUBFLOW] = ruleOutputs;
              var internalName = subflow.getValue(RFConstants.actionVars.INTERNAL_NAME);
              var scopeSysId = subflow.getValue(RFConstants.actionVars.SCOPE);
              var scope = (scopeSysId === RFConstants.actionVars.GLOBAL) ? scopeSysId : subflow.sys_scope.scope;
              var subflowName = scope + RFConstants.actionVars.DOT + internalName;

              var output = sn_fd.FlowAPI.getRunner().subflow(subflowName).inForeground().withInputs(inputs).run();
              result = output.getOutputs();
              this._convertActionResultToCamelCase(result);
          } catch (e) {
              this.rfLogger.logError("Error occured while executing performAction for subflow " + subflow.sys_id + ". Error: " + e);
          }
      }

      if (result && result.status == RFConstants.SUCCESS) {
          this._updateHistory(contextRecord, ruleOutputs, ruleOutputsString, isUndo, options);
          return {
              "message": result.message || RFConstants.DEFAULT_ACTION_SUCCESS_MESSAGE
          };
      } else {
          errorMessage = (result && result.errorMessage) || RFConstants.DEFAULT_ACTION_ERROR_MESSAGE;
          errorCode = result && result.errorCode;
      }

      if (!errorCode) {
          var exception = new RFExceptionManager("UNKNOWN_ERROR");
          errorCode = exception.getCode();
          errorMessage = exception.getMessage();
      }
      this.rfLogger.logError("Error occurred while performing action " + this.getSysId() +
          ". Error: " + errorMessage, "RFActionService - performAction");
      return {
          "errorCode": errorCode,
          "errorMessage": errorMessage
      };
  },

  getDetails: function(contextRecord, evaluationOutputs, experienceId, needUndo) {
      var details;
      try {
          if (needUndo && this.hasValidRecord()) {
              var undoAction = this.getUndoAction();
              if (undoAction) {
                  details = undoAction._getDetails(contextRecord, evaluationOutputs, experienceId, true, this.getSysId());
              } else {
                  details = {};
                  details[RFConstants.actionDetails.TYPE] = RFConstants.actionType.DISABLED;
                  details[RFConstants.actionDetails.ACTION_SYS_ID] = this.getSysId();
                  details[RFConstants.actionDetails.LABEL] = this.getLabel();
              }
          } else if (!needUndo && this.hasValidRecord()) {
              details = this._getDetails(contextRecord, evaluationOutputs, experienceId, false);
          }
      } catch (e) {
          this.rfLogger.logError("Error occurred while getting details for action " + this.getSysId() +
              ". Error: " + e, "RFActionService - getDetails");
      }
      return details;
  },

  _getDetails: function(contextRecord, evaluationOutputs, experienceId, isUndo, undoOf) {
      var details = {};
      details[RFConstants.actionDetails.TYPE] = this.getType();
      details[RFConstants.actionDetails.ACTION_SYS_ID] = this.getSysId();
      details[RFConstants.actionDetails.LABEL] = this.getLabel();
      details[RFConstants.actionDetails.IS_UNDO] = isUndo;
      details[RFConstants.actionDetails.ADDITIONALPARAMETERS] = {};

      if (isUndo) {
          details[RFConstants.actionDetails.ADDITIONALPARAMETERS][RFConstants.actionDetails.UNDO_OF] = undoOf;
      }
      details[RFConstants.actionDetails.RULE_OUTPUTS] = RFActionService.serializeEvaluationOutput(evaluationOutputs);
      details[RFConstants.actionDetails.ADDITIONALPARAMETERS][RFConstants.actionDetails.EXPERIENCE_ID] = experienceId;
      if (this.isUXFClientAction()) {
          details[RFConstants.actionDetails.ACTION_KEY] = this.getActionKey();
          details[RFConstants.actionDetails.CLIENT_PAYLOAD] = new RFPillParserUtils().getParsedValue(this.getActionClientPayload(), contextRecord, evaluationOutputs);
      }
      details[RFConstants.actionDetails.ADDITIONALPARAMETERS] = JSON.stringify(details[RFConstants.actionDetails.ADDITIONALPARAMETERS]);
      return details;
  },

  _convertActionResultToCamelCase: function(result) {
      if (!result) {
          return;
      }
      result.errorCode = result.error_code;
      result.errorMessage = result.error_message;
  },

  _updateHistory: function(contextRecord, ruleOutputs, ruleOutputsString, isUndo, options) {
      if (isUndo) {
          var historyId = RFHistoryService.markReverted(contextRecord, options.experienceId, options.undoOf, ruleOutputs);
      } else {
          historyId = RFActionService._addInHistory(contextRecord, ruleOutputs, ruleOutputsString, RFConstants.historyStatus.COMPLETED, options.experienceId, this.getSysId());
      }
      return historyId;
  },

  type: "RFActionService"
};

Sys ID

09d6be32c7433010dd7ab6c427c2602e

Offical Documentation

Official Docs: