Name

sn_nb_action.RuleServiceImpl

Description

A service to manage rules and interact with rule handlers

Script

var RuleServiceImpl = Class.create();
RuleServiceImpl.prototype = {
  initialize: function() {
      this.nextBestActionDAO = sn_nb_action.NextBestActionUtil.getNextBestActionDAO();
      this._log = new global.GSLog(sn_nb_action.Constants.PROP_LOG_LEVEL, this.type);
  },

  getBestActions: function(currentRecord, actionTypes, recommendationType, fields) {
      var rules = {};
      if (!actionTypes) {
          actionTypes = this.nextBestActionDAO.loadActionTypesByTable();
          if (!actionTypes) {
              this._log.error("There are no action types defined.");
              return false;
          }
      }
      var rulesRecord = this.nextBestActionDAO.getRules(currentRecord, fields);
      if (!rulesRecord) {
          this._log.error("There are no rules defined or rules are inactive for table " + currentRecord.getTableName());
          return false;
      }
      var currentActions = {};
      var hasActions = false;
      while (rulesRecord.next()) {
          rules[rulesRecord.getUniqueValue()] = true;
          var recommendedActionsArr = this._evaluateRule(currentRecord, rulesRecord, recommendationType);
          if (recommendedActionsArr) {
              var ruleActions = this._processActions(recommendedActionsArr, rulesRecord, currentActions, actionTypes);
              if (ruleActions) {
                  hasActions = true;
                  currentActions = Object.extend(currentActions, ruleActions);
              }
          }
      }
      if (hasActions)
          return {
              'currentActions': currentActions,
              'currentRules': rules
          };

      return {
          'currentActions': false,
          'currentRules': rules
      };
  },
  _processActions: function(recommendedActionsArr, ruleRecord, currentActions, actionTypes) {
      var ruleActions = {};
      var hasActions = false;
      for (var i = 0; i < recommendedActionsArr.length; i++) {
          var actionRecord = recommendedActionsArr[i].getAction();
          if (!sn_nb_action.NextBestActionUtil.isValidRecord(actionRecord))
              continue;
          var actionSysId = actionRecord.getUniqueValue();
          var actionTableName = actionRecord.getTableName();
          var actionTypeDetail = actionTypes[actionTableName];
          try {
              if (actionTypeDetail) {
                  var newActionDetailObj = sn_nb_action.ActionDetail.createFromRule(ruleRecord, actionTypeDetail, i + 1, recommendedActionsArr[i]);
                  if (currentActions.hasOwnProperty(actionSysId) || ruleActions.hasOwnProperty(actionSysId))
                      this._processEvaluatedAction(currentActions, ruleActions, newActionDetailObj, actionSysId, ruleRecord, i + 1, recommendedActionsArr[i]);
                  else {
                      ruleActions[actionSysId] = [newActionDetailObj];
                      hasActions = true;
                  }
              } else
                  this._log.error("Undefined action type " + [ruleRecord.getUniqueValue(), actionTableName, actionSysId]);
          } catch (ex) {
              this._log.error("Error processing recommended action: " + recommendedActionsArr[i].getHint() + " " + ex.message);
          }
      }
      if (hasActions)
          return ruleActions;
      return false;
  },
  _processEvaluatedAction: function(currentActions, ruleActions, newActionDetailObj, actionSysId, ruleRecord, intraorder, recommendedAction) {
      var processedActionDetArray, duplicateActionDetObject;
      if (currentActions.hasOwnProperty(actionSysId)) {
          processedActionDetArray = currentActions[actionSysId];
          duplicateActionDetObject = sn_nb_action.NextBestActionUtil.getDuplicateActionDetail(processedActionDetArray, newActionDetailObj);
          if (duplicateActionDetObject) {
              //action detail with same action input was recommended by another rule
              sn_nb_action.ActionDetail.updateFromRule(duplicateActionDetObject, ruleRecord, intraorder, recommendedAction);
          } else
              processedActionDetArray.push(newActionDetailObj);
      } else { //same rule duplicate recommendation
          processedActionDetArray = ruleActions[actionSysId];
          duplicateActionDetObject = sn_nb_action.NextBestActionUtil.getDuplicateActionDetail(processedActionDetArray, newActionDetailObj);
          if (!duplicateActionDetObject)
              processedActionDetArray.push(newActionDetailObj);
          else {
  			// update groups for the existing action from new action 
              sn_nb_action.ActionDetail.updateFromRule(duplicateActionDetObject, ruleRecord, intraorder, recommendedAction);
          }
      }
  },
  _evaluateRule: function(currentRecord, ruleRecord, recommendationType) {
      var ruleRoles = ruleRecord.getValue(sn_nb_action.Constants.COL_ROLES);
      if (gs.nil(ruleRoles) || gs.hasRole(ruleRoles)) {
          var ruleTableName = ruleRecord.getValue(sn_nb_action.Constants.COL_SYS_CLASS_NAME);
          var ruleHandler = sn_nb_action.NextBestActionUtil.getRuleTypeHandler(ruleTableName);
          if (ruleHandler && typeof ruleHandler.evaluateRule == "function") {
              try {
                  var actualRuleRecord = new GlideRecord(ruleTableName);
                  if (actualRuleRecord.get(ruleRecord.getUniqueValue())) {
                      var recommendedActionsArr = ruleHandler.evaluateRule(currentRecord, actualRuleRecord, recommendationType);
                      if (recommendedActionsArr && Array.isArray(recommendedActionsArr) && recommendedActionsArr.length > 0)
                          return recommendedActionsArr;
                  }
              } catch (ex) {
                  this._log.error("Failed to evaluate action(s) for rule " + ruleRecord.getUniqueValue());
              }
          } else
              this._log.error("Could not find implementaion for rule type " + ruleTableName);
      }
      return false;
  },
  isValidRule: function(ruleRecord) {
      var ruleTableName = ruleRecord.getValue(sn_nb_action.Constants.COL_SYS_CLASS_NAME);
      var ruleHandler = sn_nb_action.NextBestActionUtil.getRuleTypeHandler(ruleTableName);
      if (ruleHandler && typeof ruleHandler.isValidRule == "function") {
          return ruleHandler.isValidRule(ruleRecord);
      } else
          this._log.error("Could not find implementaion for rule type " + ruleTableName);
      return false;
  },
  type: 'RuleServiceImpl'
};

Sys ID

246f463d3b3e1010c24e870044efc4e4

Offical Documentation

Official Docs: