Name

global.MatchingDimensionProcessor

Description

Processes each of the supported dimension and aggregates their score to be used for agent recommendation.

Script

var MatchingDimensionProcessor = Class.create();

var MAX_AGENTS_PER_GROUP = 1000; //just to protect against big data 
var ERROR_MESSAGE_NO_GROUP = gs.getMessage("Selected Group has no agents");

MatchingDimensionProcessor.prototype = Object.extendsObject(AbstractAjaxProcessor,{
  initialize: function(request, responseXML, gc) {
  	this.request = request;
      this.responseXML = responseXML;
      this.gc = gc;
  	this.users = [];
  	this.resourceType = "sys_user";
  },
  
  processDimensions : function(task, taskTableName, dimensions, users, resourceType) {
  	this.users = [];
  	if(!gs.nil(resourceType) && gs.tableExists(resourceType))
  		this.resourceType = resourceType;
  	else
  		this.resourceType = "sys_user";
  		
  	var taskRecord;
  	if(task instanceof GlideRecord || task instanceof GlideRecordSecure){
  		taskRecord = task;
  	}else{
  		taskRecord = new GlideRecord(taskTableName);
  		taskRecord.get(task);
  	}
  	var overallReturn = {};
  	overallReturn.info = [];
  	var hasInitialListToFilterFrom;

  	// Checking if a parameter is there in args which tells whether empty filter array is sent intentionally.

  	for(var key in dimensions) {
  		if(dimensions[key].args.hasInitialListToFilterFrom != undefined) {
  			hasInitialListToFilterFrom = dimensions[key].args.hasInitialListToFilterFrom;
  			break;
  		}
  	}
  	
  	if (!JSUtil.nil(task) && !taskRecord.active){
  		overallReturn.msg = gs.getMessage("The record is read-only!");
  		return overallReturn;
  	}
  	if(JSUtil.nil(task) || JSUtil.nil(dimensions) || dimensions.length == 0) {
  		var infoObj = {};
  		infoObj.type = "WARNING";
  		infoObj.msg = "Insufficient data for the request";
  		var reason;
  		if (JSUtil.nil(task))
  			reason = "invalid task";
  		if (JSUtil.nil(dimensions) || dimensions.length)
  			reason = "invalid dimensions";
  		infoObj.msg = infoObj.msg + ", reason=" + reason;			
  		overallReturn.info.push(infoObj);
  		overallReturn.msg = gs.getMessage("No criteria or task to be processed");
  		overallReturn.result = "failure";
  		return overallReturn;
  	}

  	if(!JSUtil.nil(users) || hasInitialListToFilterFrom === false){
  		var userDataObj = {};
  		var userGR = new GlideRecord(this.resourceType);
  		userGR.addEncodedQuery("sys_idIN" + users.join());
  		userGR.setLimit(MAX_AGENTS_PER_GROUP + 1);
  		userGR.addActiveQuery();
  		userGR.query();
  		if(new CSMUtil().isDebugOn())
  			gs.log("MatchingDimensionProcessor::processDimensions user count=" + userGR.getRowCount());
  		if(userGR.getRowCount() > 0 || hasInitialListToFilterFrom === false){
  			if (userGR.getRowCount() > MAX_AGENTS_PER_GROUP) {
  				//We are throwing some data due to max limit so report it in the info
  				var infoObj = {};
  				infoObj.type = "WARNING";
  				infoObj.msg = "Got more than maximum supported agents = " + MAX_AGENTS_PER_GROUP;		
  				overallReturn.info.push(infoObj);
  			}

  			while(userGR.next()) {
  				this.users.push(userGR.getValue("sys_id"));
  				var userObj = {};
  				userObj["displayValue"] = userGR.getValue("name");
  				userObj["value"] = userGR.getValue("sys_id");
  				userObj["userId"] = userGR.getValue("sys_id");
  				userDataObj[userGR.getValue("sys_id")+""] = userObj;
  			}


  			var dimensionResults = {};
  			var totalWeight = 0.0;
  			for (var dimension_sys_id in dimensions){
  				var dimensionResult = {};
  				
  				if (this._isDimensionForRanking(dimensions[dimension_sys_id]))
  					totalWeight += Number(dimensions[dimension_sys_id].weight);
  				else if(new CSMUtil().isDebugOn()){
  					gs.log("processDimensions::Not using for the total weight " + dimension_sys_id);
  				} 
  				
  				dimensionResult.dimension = dimension_sys_id;					
  				var dimRecord = new GlideRecord("matching_dimension");
  				dimRecord.get(dimension_sys_id);
  				if(dimRecord) {
  					var sysId = dimRecord.getValue("sys_id");
  					if(!("loadDefaults" in dimensions[sysId]))
  						dimensions[sysId].loadDefaults = true;
  					if(dimensions[sysId].loadDefaults && (!dimensions[sysId].taskFieldValues || dimensions[sysId].taskFieldValues.length == 0)){
  						var taskGR = taskRecord;
  						if(dimensions['416b4f47932f030045a3f5be867ffb95']){
  				                dimensions['416b4f47932f030045a3f5be867ffb95'].taskFieldValues = [];
  							    var tempArray = [];
  				                var taskSkillRecord = new GlideRecord('task_m2m_skill');
  				                taskSkillRecord.addQuery('task',taskGR.sys_id);
  				                taskSkillRecord.addQuery('mandatory',false);
  				                taskSkillRecord.query();
  				               while(taskSkillRecord.next()){
  				                  dimensions['416b4f47932f030045a3f5be867ffb95'].taskFieldValues.push(taskSkillRecord.skill.sys_id+"");
  							   }
         					} else{
  							var field = "default_field_value";	
  							if(dimRecord.dimension_type == "simple"){
  								field = "applies_to_field";
  							}
  							var defaultValues = taskGR.getValue(dimRecord.getValue(field));
  								if(!JSUtil.nil(defaultValues)){
  									var fieldType = this._getInternalFieldType(taskGR, dimRecord.getValue(field));
  									if(!JSUtil.nil(fieldType)) {
  										if(fieldType == "glide_list")
  											dimensions[sysId].taskFieldValues = defaultValues.split(",");
  										else{
  											dimensions[sysId].taskFieldValues = [];
  											dimensions[sysId].taskFieldValues.push(defaultValues);
  										}
  									}
  								}
  								else{
  									dimensions[sysId].taskFieldValues = [];	
  								}	
              			}
  					}
  					if(dimRecord.getValue("use_reference")== true){
  						var selectedValues = [];
  						var sysId = dimRecord.getValue("sys_id");
  						if(dimensions[sysId].taskFieldValues && dimensions[sysId].taskFieldValues.length>0 ){
  							var selectedSkillIDs = dimensions[sysId].taskFieldValues;
  							var grSkill1 = new GlideRecord(dimRecord.getValue("reference_table"));
  								grSkill1.addQuery("sys_id","IN",selectedSkillIDs.toString());
  								grSkill1.query();
  								while(grSkill1.next()){
  									selectedValues.push({"value":grSkill1.getValue('sys_id'),"displayValue":grSkill1.getValue('name')});
  								}
  						}
  						dimensionResult.selectedValues = selectedValues;
  					}
  				}
  				dimensionResult.dimension_type = dimensions[dimension_sys_id].dimension_type;
  				dimensionResult.weight = dimensions[dimension_sys_id].weight;
  				dimensionResult.name = dimRecord.getDisplayValue();
  				dimensionResult.result = this.processDimension(dimension_sys_id, dimensions[dimension_sys_id], taskRecord);
  				dimensionResults[dimension_sys_id]=dimensionResult;
  				
  			}
  			overallReturn.overallRating = this.getOverallRating(dimensionResults, totalWeight);
  			overallReturn.dimensionResults = dimensionResults;
  			overallReturn.users = this.users;
  			if(JSUtil.nil(this.users) || overallReturn.users.length < 1){
  				overallReturn.msg = gs.getMessage("No agents available");
  			}
  			overallReturn.userDataObj = userDataObj;
  			overallReturn.result = "success";
  		}else{
  			overallReturn.result = "failure";
  			overallReturn.msg = gs.getMessage("No agents available");
  		}
  	}else{
  		overallReturn.result = "failure";
  		overallReturn.msg = gs.getMessage("No agents available");
  	}
  	return overallReturn;
  },
  
  _getInternalFieldType : function (taskGR, fieldName){
  	if(taskGR.getElement(fieldName))
  		return taskGR.getElement(fieldName) && taskGR.getElement(fieldName).getED().getInternalType();
  },
  
  _isDimensionForRanking : function(dimension) {
  	return (dimension.dimension_type == "ranking" || dimension.dimension_type == "ranking_no_display");
  },
  
  getOverallRating : function(dimensionResults, totalWeight){
  	var overallMap = {};
  	if(totalWeight <= 0)
  		totalWeight = 1;
  	//for(var i = 0;i < dimensionResults.length; i++)
  	for(var dimensionResult in dimensionResults){			
  		var dimension = dimensionResults[dimensionResult];
  		if (!this._isDimensionForRanking(dimension)) {
  			if(new CSMUtil().isDebugOn())
  				gs.log("getOverallRating skipping for overall calculation " + JSON.stringify(dimension));
  			continue;
  		}
  			
  		for(var idx in this.users){
  			var user = this.users[idx];
  			var overallRating = overallMap[user] ? overallMap[user] : 0;
  			if (totalWeight && !isNaN(dimension.result[user].rating)) {
  				//overallMap[user] = overallRating + Number((dimension.weight / totalWeight) * dimension.result[user].rating);
  				overallMap[user] = overallRating + Number((dimension.weight / totalWeight) * dimension.result[user].rating);
  			}
  			else 
  				overallMap[user] = 0;
  		}
  	}
  	
  	for(var i=0;i< this.users.length;i++){
  		if(!overallMap.hasOwnProperty(this.users[i])) {
  			overallMap[this.users[i]] = 0;
  		}	
  	}
  	return overallMap;
  },
  
  processScriptedDimension : function(dimensionRecord, dimension, task) {
  	var map = {};
  	map.task = task;
  	map.users = this.users;
  	map.taskFieldValues = dimension.taskFieldValues;
  	//map.initialLoad = dimension.initialLoad;
  	map.args = dimension.args;
  	map.task.__dimensionContext = {
  		users: this.users,
  		taskFieldValues: dimension.taskFieldValues,
  		args: dimension.args
  	};
  	var evaluator = new GlideScopedEvaluator();
  	var dimensionResult = evaluator.evaluateScript(dimensionRecord, "script", map);

  	if(new CSMUtil().isDebugOn())
  		gs.log("MatchingDimensionProcessor::processScriptedDimension " + dimensionRecord.getDisplayValue() + " dimensionResult=" + JSON.stringify(dimensionResult));
  	
  	for(var idx in this.users){
  		var user = this.users[idx];
  		var result = dimensionResult[user];
  		/*if(!result){
  			result = {};
  			result.value = 0;
  			result.displayValue = "NA";
  			result.detailedDisplayValue =  "User not ranked";
  			dimensionResult[user] = result;
  		}
  		else{
  			if(dimension["ranking_method"]=="less is better")
  				result.rating = 1 - result.rating;
  		}*/
  		if(result) {
  			if(dimension["ranking_method"]=="less is better")
  				result.rating = 1 - result.rating;
  		}
  			
  	}
  	
  	return dimensionResult;
  },
  
  processSimpleDimension : function(dimensionRecord, dimension, task) {
  	var contextTableToMatchOn = dimensionRecord.applies_to_table;
  	var contextFieldToMatch = dimensionRecord.applies_to_field;
  	var resourceTable = dimensionRecord.resource_table;
  	var resourceFieldToMatch = dimensionRecord.resource_matching_field;
  	var resourceFieldToReturn = dimensionRecord.resource_field;
  	
  	var taskGR = new GlideRecord(contextTableToMatchOn);
  	taskGR.get(task.getValue("sys_id"));
  	var taskMatchUserMap = {};
  	if(taskGR.isValidRecord()) {
  		//var taskValueToMatch = taskGR.getValue(contextFieldToMatch);
  		var taskValueToMatch = dimension.taskFieldValues;
  		var userGR = new GlideRecord(resourceTable);
  		userGR.addEncodedQuery(resourceFieldToMatch+"IN"+taskValueToMatch.join());
  		userGR.addEncodedQuery(resourceFieldToReturn+"IN"+this.users.join());
  		userGR.query();
  		while(userGR.next()){
  			var user = userGR.getValue(resourceFieldToReturn);
  			taskMatchUserMap[user] = 1;
  		}
  	}
  	var userMap = {};
  	for(var idx in this.users){
  		var user = this.users[idx];
  		var result = {};
  		result.rating = !taskMatchUserMap[user] ? 0 : 1;
  		result.value = !taskMatchUserMap[user] ? 0 : 1;
  		result.displayValue = !taskMatchUserMap[user] ? "No Match" : "Match";
  		result.detailedDisplayValue =  result.displayValue;
  		userMap[user] = result;
  	}
  	return userMap;
  },
  
  processAggregateDimension : function(dimensionRecord, dimension, task) {
  	var aggregate_table = dimensionRecord.aggregate_table;
  	var aggregate_filter = dimensionRecord.aggregate_filter;
  	var aggregate_field = dimensionRecord.aggregate_field;
  	
  	if(new CSMUtil().isDebugOn())
  		gs.log("processAggregateDimension aggregate_table=" + aggregate_table + " aggregate_filter=" +
  	aggregate_filter + " aggregate_field=" + aggregate_field);
  	
  	if(JSUtil.nil(aggregate_table) || JSUtil.nil(aggregate_field))
  		return {};
  	
  	var taskGR = new GlideAggregate(aggregate_table);
  	taskGR.addEncodedQuery(aggregate_filter);
  	taskGR.addEncodedQuery(aggregate_field + "IN" + this.users.join());
  	taskGR.addAggregate("COUNT",aggregate_field);
  	taskGR.addAggregate("MIN", aggregate_field + ".sys_id");
  	taskGR.groupBy(aggregate_field);
  	taskGR.query();
  	var userMap = {};
  	var totalCount = 0;
  	while(taskGR.next()){
  		var count = Number(taskGR.getAggregate("COUNT",aggregate_field));
  		var user = taskGR.getAggregate("MIN", aggregate_field + ".sys_id");
  		userMap[user] = count;
  		totalCount += count;
  	}
  	
  	for(var idx in this.users){
  		var user = this.users[idx];
  		var result = {};
  		result.rating = 0;
  		if (!userMap[user])
  			userMap[user] = 0;
  		if (totalCount){
  			if(dimension["ranking_method"]=="less is better")
  				result.rating = 1 - (userMap[user] / totalCount); //TODO : Do based on the flag
  			else
  				result.rating = (userMap[user] / totalCount);
  		}
  		result.value = userMap[user];
  		result.displayValue = "" + userMap[user];
  		result.detailedDisplayValue =  userMap[user];
  		userMap[user] = result;
  	}
  	return userMap;
  },
  
  
  processDimension : function (dimension_sys_id, dimension, task){
  	var result = {};
  	var dimensionRecord = new GlideRecord("matching_dimension");
  	dimensionRecord.get(dimension_sys_id);
  	if(dimensionRecord.dimension_type == "script") {
  		result = this.processScriptedDimension(dimensionRecord, dimension, task);
  	} else if(dimensionRecord.dimension_type == "aggregate"){			
  		result = this.processAggregateDimension(dimensionRecord, dimension, task);
  	} else if(dimensionRecord.dimension_type == "simple"){
  		result = this.processSimpleDimension(dimensionRecord, dimension, task);
  	}
  	this.users = Object.keys(result);
  	this.dropAgentsPerThreshhold(dimensionRecord, dimension, result);
  	return result;
  },
  
  dropAgentsPerThreshhold : function(dimensionRecord, dimension, result){
  	//Based on the below/above the set threshold values, drop the agent
  	if(new CSMUtil().isDebugOn())
  		gs.log("------ " + dimensionRecord.getDisplayValue() + ":" + dimensionRecord.sys_id + " dropAgentsPerThreshhold threshold=" + dimension.threshold);
  	if (JSUtil.nil(dimension.threshold))
  		return;
  	var idx = 0;
  	while (idx < this.users.length) {
  		var user = this.users[idx];
  		var userResult = result[user];
  		if ((dimension.ranking_method == "more is better" && userResult.value < dimension.threshold) ||
  			   (dimension.ranking_method == "less is better" && userResult.value > dimension.threshold)) {
  			 delete result[user];
  			 this.users.splice(idx,1);
  		} else {
  			idx++;
  		}
  	}
  	return result;
  },
  
  logResults : function(results) {
  	if(gs.nil(this.resourceType))
  		this.resourceType = "sys_user";
  	
  	var headerStr1 = "\t  User\t\tOverall\t";
  	var headerStr2="";
  	for(var i in results.dimensionResults) {
  		var grDimension = new GlideRecord("matching_dimension");
  		grDimension.get( results.dimensionResults[i].dimension);
  		//var dimensionResult = results.dimensionResults[i].result;
  		headerStr2 += grDimension.getDisplayValue("name") + ":[Rating    Value   Display   Detailed_Display]";
  	}
  	
  	for(var userIdx in results.users) {
  		var user = results.users[userIdx];	
  		var gr = new GlideRecord(this.resourceType);
  		gr.get(user);
  		var userName = ("             " + gr.getDisplayValue()).slice(-14);
  		var overAll = ("      " + results.overallRating[user].toFixed(2)).slice(-7);
  		var rowStr2 = "";
  		for(var i in results.dimensionResults) {
  			var grDimension = new GlideRecord("matching_dimension");
  			grDimension.get( results.dimensionResults[i].dimension);
  			var dimensionResult = results.dimensionResults[i].result;
  			var userDimensionResult = dimensionResult[user];
  			var rating = ("\t" + userDimensionResult.rating).slice(-7);
  			var value = ("      " + userDimensionResult.value).slice(-12);
  			var display = ("      " + userDimensionResult.displayValue).slice(-12);
  			var detailedDisplay = ("  " + userDimensionResult.detailedDisplayValue).slice(-45);
  			rowStr2 += rating + "  " + value + "  " + display + "   " + detailedDisplay + " ";
  			//rowStr2 = rating + "  " + value ;
  		}
  	}
  },
  
  getAWDataFromDimension:function(){
  	var sw = new GlideStopWatch();
  	var tableName = this.getParameter("sysparm_taskTableName");
  	var taskId = this.getParameter("sysparm_taskSysID");
  	var selectedDimensions  = new JSON().decode(this.getParameter("sysparm_selDimension"));
  	var selectedDimValues = new JSON().decode(this.getParameter("sysparm_selDimValues"));
  	var taskGrp = this.getParameter("sysparm_taskGrp");
  	var assignmentWorkbenchID = this.getParameter("sysparm_assignmentWorkbenchID");
  	var initialLoad = this.getParameter("sysparm_initialLoad");
  	var dimensions = {};
  	var gr = new GlideRecordSecure("matching_dimension_for_assignment");
  	gr.addQuery('dimension','IN',selectedDimensions.toString());
  	
  	if(assignmentWorkbenchID){
  		gr.addQuery('matching_rule',assignmentWorkbenchID);
  	}
  	gr.orderBy("order");
  	gr.query();
  	while(gr.next()){
  		var taskFieldValues = [];
  		if(selectedDimValues && selectedDimValues[gr.getValue("dimension")]){
  			var valArr = selectedDimValues[gr.getValue("dimension")];
  			if(valArr && valArr.length > 0){
  				for(var j = 0;j<valArr.length;j++)
  				taskFieldValues.push(valArr[j]);
  			}
  		}
  		var initial_load = (initialLoad == "true");
  		
  		dimensions[gr.getValue("dimension")] = 
  			{
  				"dimension_type":gr.getValue("dimension_type"), 
  				"weight":gr.getValue("weight"),
  				"threshold":gr.getValue("threshold"),
  				"ranking_method":gr.getValue("ranking_method"),
  				"initialLoad":initial_load,
  				"loadDefaults" : initial_load,
  				"taskFieldValues":taskFieldValues,
  				"args":{}
  			};
  	}
  	var awData = {};
  	awData.info = [];
  	var assignmentGroup = taskGrp;
  	if(JSUtil.nil(taskGrp)){
  		var infoObj = {};
  		infoObj.type = "WARNING";
  		infoObj.msg = "Insufficient data for the request";
  		var reason = "no group";
  		infoObj.msg = infoObj.msg + ", reason=" + reason;			
  		awData.info.push(infoObj);
  		awData.msg = gs.getMessage("Select group to show Recommendation");
  		awData.result = "failure";
  	}	
  	else{
  		var reference = this.getReferenceQuery(taskId);
  		var grpRecord = new GlideRecordSecure('sys_user_group');
  		grpRecord.addQuery('sys_id',assignmentGroup);
  	    grpRecord.query();
  	    if(grpRecord.next()){
  	    	var assignmentGrpObj = {};
  			assignmentGrpObj['grpName'] = grpRecord.getValue("name");
  			assignmentGrpObj['grpId'] = assignmentGroup;
  			var userDataObj = {};
  			var userGR = new GlideRecordSecure("sys_user");
  			var groupGR = userGR.addJoinQuery("sys_user_grmember","sys_id","user");
  			userGR.setLimit(MAX_AGENTS_PER_GROUP + 1);
  			userGR.addEncodedQuery(reference);
  			userGR.addActiveQuery();
  			groupGR.addCondition("group", assignmentGroup);
  			userGR.query();
  			
  			if(new CSMUtil().isDebugOn())
  				gs.log("MatchingDimensionProcessor::getAWDataFromDimension user count=" + userGR.getRowCount());
  			
  			var users = [];
  			while(userGR.next()) {
  				users.push(userGR.getValue("sys_id"));
  			}
  			awData = this.processDimensions(taskId,tableName,dimensions,users);
  			awData.grpObj = assignmentGrpObj;
  	    }
  	    else{
  	    	awData.result = "failure";
  			awData.msg = gs.getMessage("Invalid group selection");
  	    }
  	}
  	var response = new JSON().encode(awData);
  	if(new CSMUtil().isDebugOn())
  		sw.log("MatchingDimensionProcessor::getAWDataFromDimension");
  	return response;
  },
  
  getReferenceQuery: function(taskId){
          var query = '';
          var taskTable = '';
          var reference_qual = '';
      
          var taskGR = new GlideRecordSecure("task");
          var taskExists = taskGR.get(taskId);
          if(taskExists)
              taskTable = taskGR.sys_class_name;
          
          //Doing the query again to get the specific ref qualifier for the child table instead of the generic task table one.
          var taskTableGR = new GlideRecord(taskTable); 
          var taskTableExists = taskTableGR.get(taskId);
          if(taskTableExists){
              var field = taskTableGR.getElement('assigned_to');
              reference_qual = field.getED().getReferenceQualifier();
          }
          
          if (JSUtil.notNil(reference_qual)) {
              if (reference_qual.startsWith("javascript:")) {
                  var globals = new Packages.java.util.HashMap();
                  query = GlideEvaluator.evaluateStringWithGlobals(reference_qual, globals);
              } else {
                  query = reference_qual;
              }
          }
      return query;
  },

  getAWConfig:function(){
  	var resultString = '';
  	if (GlidePluginManager.isActive('com.snc.assignment_workbench')) {
  	var tableName = this.getParameter("sysparm_taskTableName");
  	var taskId = this.getParameter("sysparm_taskSysID");
  	var grpName = this.getParameter("sysparm_taskGrpName");
  	var taskData = {};
  	taskData['tableName'] = tableName;
  	taskData['taskId'] = taskId;
  	taskData['grpName'] = grpName;
  	var awConfig = MatchingRuleForAssignment.getConfigData(taskData);
  	resultString =  new JSON().encode(awConfig);
  	}
  	return resultString; 
  },
  
  getFilterValues:function(){
  	var groupSysId = this.getParameter("sysparm_groupSysId");
  	var criteriaSysId = this.getParameter("sysparm_criteriaSysId");
  	var filterName = this.getParameter('sysparm_filterName');
  	var filterParam = {};
  	filterParam['group_sys_id'] = groupSysId;
  	filterParam['criteria_sys_id'] = criteriaSysId;
  	var filterData = new MatchingDimensionFilterProcessor().getFilterData(filterParam);
  	return new JSON().encode(filterData);
  },
  // get all the dimensions for matching rule
  getConditions : function (table, id) {
  	var conditions = [];
  	var gr = new GlideRecord("matching_dimension_for_assignment");
  	gr.addQuery('assignment_workbench',id);
  	gr.query();
  	while (gr.next()) {
  		conditions.push(gr.getValue("sys_id"));
  	}
  	return conditions;
  },
  
  _performAssignment: function (taskID, taskTableName, agentID, groupID){
  	var taskGR = new GlideRecordSecure(taskTableName);
  	taskGR.addQuery('sys_id',taskID);
  	taskGR.query();
  	if(taskGR.next()){
  		taskGR.setValue("assigned_to", agentID);
  		taskGR.setValue("assignment_group", groupID);
  		taskGR.update();
  	}
  },

  handleAssign:function(){
  	var taskSysID = this.getParameter("sysparm_taskSysID");
  	var taskTableName = this.getParameter("sysparm_taskTableName");
  	var selectedAgentID = this.getParameter("sysparm_selectedUserID");
  	var grpId = this.getParameter("sysparm_grpId");
  	
  	//perform the assignment
  	this._performAssignment(taskSysID, taskTableName, selectedAgentID, grpId);
  	
  	
  	var grpName = this.getParameter("sysparm_grpName");
  	var picked_recommended = this.getParameter("sysparm_picked_recommended");
  	var selection = this.getParameter("sysparm_selection");
  	var firstAgent = this.getParameter("sysparm_firstAgent");
  	var fetchTime = this.getParameter("sysparm_fetchTime");
  	var renderTime = this.getParameter("sysparm_renderTime");
  	var reportData = {};
  	reportData['event.type'] = 'agent.selection';
  	reportData['selectionType'] = 'manual_assignment';
  	reportData['taskSysID'] = taskSysID;
  	reportData['taskTableName'] = taskTableName;
  	reportData['grpId'] = grpId;
  	reportData['grpName'] = grpName;
  	reportData['picked_recommended'] = picked_recommended;
  	reportData['selection'] = selection;
  	reportData['firstAgent'] = firstAgent;
  	reportData['fetchTime'] = fetchTime;
  	reportData['renderTime'] = renderTime;
  	var matchingDimensionUtil = new MatchingDimensionUtil();
  	matchingDimensionUtil.logAnalytics(reportData);
  	var result = {};
  	result.success = true;
  	return new JSON().encode(result);
  },
  
  type: 'MatchingDimensionProcessor'
});

Sys ID

4ecd401fc32212001c845cb981d3aed7

Offical Documentation

Official Docs: