Name

global.OnCallWorkflowUtilsSNC

Description

No description available

Script

var OnCallWorkflowUtilsSNC = Class.create();
OnCallWorkflowUtilsSNC.prototype = {

  initialize: function() {
  	this._log = new GSLog('com.snc.on_call_rotation.log.level', this.type);
  	this._onCallCommon = new OnCallCommon();
  },

  TABLES: {
  	ON_CALL_ESCALATION_RESPONSE: 'on_call_escalation_response',
  	ON_CALL_PUSH_REQUEST: 'on_call_push_request'
  },

  COMMUNICATION_RESPONSE: {
  	REJECTED: 'rejected'
  },

  EMAIL_CHANNEL_ACCEPT_RESPONSES: ['ACC', 'ACCFROM', 'ACCFROM:', 'ACCEPT', 'ACCEPTFROM', 'ACCEPTFROM:'],

  EMAIL_CHANNEL_REJECT_RESPONSES: ['REJ', 'REJFROM', 'REJFROM:', 'REJECT', 'REJECTFROM', 'REJECTFROM:'],

  getDeviceDetails: function(recordClass, currentEscalateeId) {
  	var deviceDetails = {};
  	if (recordClass == 'sys_user') {
  		var notifyUtils = new NotifyUtil();
  		deviceDetails.smsDevice = notifyUtils.getUniquePhoneNumbersForUsersAndGroups([], [currentEscalateeId], [], notifyUtils.numberType.sms, false);
  		deviceDetails.voiceDevice = notifyUtils.getUniquePhoneNumbersForUsersAndGroups([], [currentEscalateeId], [], notifyUtils.numberType.voice, false);
  		deviceDetails.emailDevice = this.getAvailableEmailDevice(currentEscalateeId);
  	} else {
  		var cmnNotifDevice = new GlideRecord('cmn_notif_device');
  		cmnNotifDevice.get(currentEscalateeId);
  		if (cmnNotifDevice) {
  			var type = cmnNotifDevice.getValue('type');
  			var phoneNumber = cmnNotifDevice.getValue('phone_number');
  			var emailAddress = cmnNotifDevice.getValue('email_address');
  			if (type == 'SMS' && JSUtil.notNil(phoneNumber)) {
  				deviceDetails.smsDevice = [phoneNumber];
  				deviceDetails.device_phone_number = phoneNumber;
  			} else if (type == 'Voice' && JSUtil.notNil(phoneNumber)) {
  				deviceDetails.voiceDevice = [phoneNumber];
  				deviceDetails.device_phone_number = phoneNumber;
  			} else if (type == 'Email' && JSUtil.notNil(emailAddress)) {
  				deviceDetails.emailDevice = emailAddress;
  				deviceDetails.device_email_address = emailAddress;
  			}
  		}
  	}
  	return deviceDetails;
  },
  
  getAvailableEmailDevice: function(userId) {
  	var email = new GlideRecord("cmn_notif_device");
  	email.addQuery("user", userId);
  	email.addQuery("type", "email");
  	email.orderBy("order");
  	email.addActiveQuery();
  	email.query();

  	while (email.next()) {
  		// if there is no schedule the device is always available
  		if (email.getElement("schedule").nil())
  			return email;

  		// check is the device is available based on its schedule
  		var gSchedule = new GlideSchedule(email.getValue("schedule"));
  		if(gSchedule.isInSchedule(new GlideDateTime()))
  			return email;
  	}

  	return null;
  },
  
  getUserName: function(userId) {
  	var userGr = new GlideRecord('sys_user');
  	userGr.get(userId);
  	return userGr.getValue('name');
  },

  getGroupName: function(groupId) {
  	var groupGr = new GlideRecord('sys_user_group');
  	groupGr.get(groupId);
  	return groupGr.getValue('name');
  },

  getDeviceName: function(deviceId) {
  	var deviceGr = new GlideRecord('cmn_notif_device');
  	deviceGr.get(deviceId);
  	if (deviceGr && deviceGr.getValue('type') == 'Voice' && deviceGr.getValue('phone_number'))
  		return deviceGr.getValue('name');
  	return null;
  },
  
  getPhoneNumber: function(deviceId) {
  	var deviceGr = new GlideRecord('cmn_notif_device');
  	deviceGr.get(deviceId);
  	if (deviceGr && deviceGr.getValue('type') == 'Voice' && deviceGr.getValue('phone_number'))
  		return deviceGr.getValue('phone_number');
  	return null;
  },

  getCatchAll: function(currentRotaID, rota) {
  	var catchAllString = "";
  	var catchAllType = rota.getCatchAllType(currentRotaID);
  	var userGr;
  	if (catchAllType == 'group_manager' || catchAllType == 'individual') {
  		var catchAllUser = rota.getCatchAll(currentRotaID);
  		userGr = new GlideRecord('sys_user');
  		userGr.addActiveQuery();
  		if (userGr.get(catchAllUser)) {
  			catchAllString += gs.getMessage("- {0} (Catch All)", [userGr.getDisplayValue()]) + " \n";
  		}
  	}
  	else if (catchAllType == 'all') {
  		// get all members for this roster
  		var catchAllusers = "";
  		var catchAllRoster = rota.getCatchAll(currentRotaID);
  		rotaMemberGr = new GlideRecord('cmn_rota_member');
  		rotaMemberGr.addQuery('roster', catchAllRoster);
  		rotaMemberGr.query();
  		while (rotaMemberGr.next()) {
  			userGr = new GlideRecord('sys_user');
  			userGr.addActiveQuery();
  			if (userGr.get(rotaMemberGr.member + '')) {
  				catchAllusers += userGr.getDisplayValue() + ', ';
  			}
  		}
  		if (catchAllusers.length > 0)
  			catchAllusers = catchAllusers.slice(0, - 2);
  		catchAllString += gs.getMessage("- {0} (Catch All)", [catchAllusers]) + " \n";
  	}
  	return catchAllString;
  },
  
  getRotasFromEscalationPlan: function(groupId, gdt, rota, taskGr) {
  	var rotas = {};
  	var escalationPlan = rota.getEscalationPlan(groupId, new GlideDateTime(gdt), null, taskGr);
  	for(var i = 0;i < escalationPlan.length; i++) {
  		var escalatee = escalationPlan[i];
  		if (escalatee.rotaId) {
  			if (!rotas[escalatee.rotaId])
  				rotas[escalatee.rotaId] = [];
  			rotas[escalatee.rotaId].push({
  				userId: escalatee.userId,
  				userIds: escalatee.userIds,
  				escalationGroups: escalatee.escalationGroups,
  				deviceId: escalatee.deviceId,
  				deviceIds: escalatee.deviceIds,
  				reminderNum: escalatee.reminderNum
  			});
  		}

  		for (var j = 0; j < escalatee.additionalEscalatees.length; j++) {
  			var additionalEscalatee = escalatee.additionalEscalatees[j];
  			if(!rotas[additionalEscalatee.rotaId])
  				rotas[additionalEscalatee.rotaId] = [];
  			rotas[additionalEscalatee.rotaId].push({
  				userId: additionalEscalatee.userId,
  				userIds: additionalEscalatee.userIds,
  				escalationGroups: additionalEscalatee.escalationGroups,
  				deviceId: additionalEscalatee.deviceId,
  				deviceIds: additionalEscalatee.deviceIds,
  				reminderNum: additionalEscalatee.reminderNum});
  		}
  	}	
  	return rotas;
  },
  
  generateWorknotes: function(rotaMaxLevel, groupName, rotas, rota) {
  	var worknotes = gs.getMessage("Conference escalation is in progress with following escalation plan for {0} group:", [groupName]) + " \n\n";
  	var level = 0;
  	var that = this;
  	while ((rotaMaxLevel + 1) > level) {
  		level++;
  		Object.keys(rotas).forEach(function(key) {
  			if(rotas[key][level-1]) {
  				if (rotas[key][level-1].userId) {
  					var escalateeName = that.getUserName(rotas[key][level-1].userId);
  					worknotes += gs.getMessage("- User: {0} ({1} reminder(s))", [escalateeName, rotas[key][level-1].reminderNum+'']) + ' \n';
  				}
  				if (rotas[key][level-1].userIds) {
  					for (var i = 0; i < rotas[key][level-1].userIds.length; i++) {
  						var escalateeName = that.getUserName(rotas[key][level-1].userIds[i]);
  						worknotes += gs.getMessage("- User: {0} ({1} reminder(s))", [escalateeName, rotas[key][level-1].reminderNum+'']) + ' \n';
  					}
  				}
  				if (rotas[key][level-1].escalationGroups) {
  					for (var i = 0; i < rotas[key][level-1].escalationGroups.length; i++) {
  						var groupName = that.getGroupName(rotas[key][level-1].escalationGroups[i]);
  						worknotes += gs.getMessage("- Group: {0}", [groupName]) + ' \n';
  					}
  				}
  				if (rotas[key][level-1].deviceId) {
  					var deviceName = that.getDeviceName(rotas[key][level-1].deviceId);
  					if (deviceName)
  						worknotes += gs.getMessage("- Device: {0} ({1} reminder(s))", [deviceName, rotas[key][level-1].reminderNum+'']) + ' \n';
  				}
  				if (rotas[key][level-1].deviceIds) {
  					for (var i = 0; i < rotas[key][level-1].deviceIds.length; i++) {
  						var deviceName = that.getDeviceName(rotas[key][level-1].deviceIds[i]);
  						if (deviceName)
  							worknotes += gs.getMessage("- Device: {0} ({1} reminder(s))", [deviceName, rotas[key][level-1].reminderNum+'']) + ' \n';
  					}
  				}
  			} else if (level == rotas[key].length + 1 ) {
  				worknotes +=  that.getCatchAll(key, rota);
  			}
  		});
  	}
  	return worknotes;
  },

  escalateToCatchAll: function (currentRotaID, group, current) {
  	var notifyCommTask = new sn_comm_management.CommTaskNotifyAjax();
  	var rota = new OnCallRotation();
  	var catchAllType = rota.getCatchAllType(currentRotaID);
  	if (catchAllType == 'group_manager' || catchAllType == 'individual') {
  		var catchAllUser = rota.getCatchAll(currentRotaID);
  		var userGr = new GlideRecord('sys_user');
  		userGr.addActiveQuery();
  		if (userGr.get(catchAllUser)) {
  			var callInitiated = notifyCommTask.call(userGr.getUniqueValue(), current, group.sys_id);
  		}
  	}
  	else if (catchAllType == 'all') {
  		// get all members for this roster
  		var catchAllRoster = rota.getCatchAll(currentRotaID);
  		rotaMemberGr = new GlideRecord('cmn_rota_member');
  		rotaMemberGr.addQuery('roster', catchAllRoster);
  		rotaMemberGr.query();
  		while (rotaMemberGr.next()) {
  			var userGr = new GlideRecord('sys_user');
  			userGr.addActiveQuery();
  			if (userGr.get(rotaMemberGr.member + '')) {
  				var callInitiated = notifyCommTask.call(userGr.getUniqueValue(), current, group.sys_id);
  			}
  		}
  	}
  },

  getCatchAllUsers: function (currentRotaID) {
  	var rota = new OnCallRotation();
  	var catchAllType = rota.getCatchAllType(currentRotaID);
  	var catchAllUsers = [];

  	if (catchAllType == 'group_manager' || catchAllType == 'individual') {
  		var catchAllUser = rota.getCatchAll(currentRotaID);
  		var userGr = new GlideRecord('sys_user');
  		userGr.addActiveQuery();
  		if (userGr.get(catchAllUser)) {
  			catchAllUsers.push(userGr.getUniqueValue());
  		}
  	}
  	else if (catchAllType == 'all') {
  		// get all members for this roster
  		var catchAllRoster = rota.getCatchAll(currentRotaID);
  		rotaMemberGr = new GlideRecord('cmn_rota_member');
  		rotaMemberGr.addQuery('roster', catchAllRoster);
  		rotaMemberGr.query();
  		while (rotaMemberGr.next()) {
  			var userGr = new GlideRecord('sys_user');
  			userGr.addActiveQuery();
  			if (userGr.get(rotaMemberGr.member + '')) {
  				catchAllUsers.push(userGr.getUniqueValue());
  			}
  		}
  	}

  	return catchAllUsers;
  },

  escalateToCatchAllByPreferences: function(currentRotaID, group, current) {
  	var notifyCommTask = new sn_comm_management.CommTaskNotifyAjax();

  	var rota = new OnCallRotation();
  	var catchAllType = rota.getCatchAllType(currentRotaID);
  	var catchAllUsers = [];

  	if (catchAllType == 'group_manager' || catchAllType == 'individual') {
  		var catchAllUser = rota.getCatchAll(currentRotaID);
  		var userGr = new GlideRecord('sys_user');
  		userGr.addActiveQuery();
  		if (userGr.get(catchAllUser)) {
  			catchAllUsers.push(userGr.getUniqueValue());
  		}
  	}
  	else if (catchAllType == 'all') {
  		// get all members for this roster
  		var catchAllRoster = rota.getCatchAll(currentRotaID);
  		rotaMemberGr = new GlideRecord('cmn_rota_member');
  		rotaMemberGr.addQuery('roster', catchAllRoster);
  		rotaMemberGr.query();
  		while (rotaMemberGr.next()) {
  			var userGr = new GlideRecord('sys_user');
  			userGr.addActiveQuery();
  			if (userGr.get(rotaMemberGr.member + '')) {
  				catchAllUsers.push(userGr.getUniqueValue());
  			}
  		}
  	}
  	for (var i = 0; i < catchAllUsers.length; i++) {
  		var userId = catchAllUsers[i];
  		var userPrefs = this.getPreferencePhoneNumbers(userId, 1);
  		if (userPrefs.length > 0) {
  			this.callUserPreferredNumbers(userId, current, group.sys_id, userPrefs);
  		}
  		else {
  			notifyCommTask.call(userId, current, group.sys_id);
  		}
  	}
  },

  startWorkflowForGroup: function (groupId, current, onCallConferenceCallEscalationByTCMWorkflowId, table, sysId, parentEscalationLevelId) {
  	var wf = new Workflow();
  	wf.startFlow(onCallConferenceCallEscalationByTCMWorkflowId, current, current.operation(), { group: groupId, table: table, sysid: sysId, parent_escalation_level: parentEscalationLevelId });
  },

  checkIfPrimaryAnsweredCall: function(currentEscalatee, conferenceCallSysId) {
  	var participant = new GlideRecord('notify_participant');
  	participant.addActiveQuery();
  	participant.addQuery('notify_conference_call', conferenceCallSysId);
  	if (currentEscalatee.type == 'user')
  		participant.addQuery('user', currentEscalatee.id);
  	else
  		participant.addQuery('phone_number', currentEscalatee.phone_number);
  	participant.query();
  	if (participant.hasNext())
  		return true;
  	return false;
  },

  getRotasAndUpdateFirstReminderJoinedStatus: function (groupId, gdt, hasFirstReminderJoined, firstReminderSent, conferenceCallSysId, taskGr) {
  	var rotas = {};
  	var rota = new OnCallRotation();
  	var escalationPlan = rota.getEscalationPlan(groupId, new GlideDateTime(gdt), null, taskGr);
  	for (var i = 0; i < escalationPlan.length; i++) {
  		var escalatee = escalationPlan[i];
  		if (escalatee.rotaId) {
  			if (!rotas[escalatee.rotaId])
  				rotas[escalatee.rotaId] = [];
  			if (i == 0 && firstReminderSent && escalatee.reminderNum == 0) {
  				rotas[escalatee.rotaId].push({
  					escalationGroups: escalatee.escalationGroups
  				});
  			} else {
  				rotas[escalatee.rotaId].push({
  					userId: escalatee.userId,
  					userIds: escalatee.userIds,
  					escalationGroups: escalatee.escalationGroups,
  					deviceId: escalatee.deviceId,
  					deviceIds: escalatee.deviceIds,
  					reminderNumber: escalatee.reminderNum
  				});
  			}
  			if (i == 0 && firstReminderSent) {
  				escalatee.reminderNum--;
  				if (escalatee.userId)
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'user', id: escalatee.userId }, conferenceCallSysId);
  				if (escalatee.userIds) {
  					for (var k = 0; k < escalatee.userIds.length; k++) {
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'user', id: escalatee.userIds[k] }, conferenceCallSysId);
  					}
  				}
  				if (escalatee.deviceId) {
  					var phoneNumber = this.getPhoneNumber(escalatee.deviceId);
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'device', phone_number: phoneNumber }, conferenceCallSysId);
  				}
  				if (escalatee.deviceIds) {
  					for (var k = 0; k < escalatee.deviceIds.length; k++) {
  						var phoneNumber = this.getPhoneNumber(escalatee.deviceIds[k]);
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'device', phone_number: phoneNumber }, conferenceCallSysId);
  					}
  				}
  			}
  			while (escalatee.reminderNum > 0) {
  				rotas[escalatee.rotaId].push({
  					userId: escalatee.userId,
  					userIds: escalatee.userIds,
  					deviceId: escalatee.deviceId,
  					deviceIds: escalatee.deviceIds,
  					reminderNumber: escalatee.reminderNum
  				});
  				escalatee.reminderNum--;
  			}
  		}
  		for (var j = 0; j < escalatee.additionalEscalatees.length; j++) {
  			var additionalEscalatee = escalatee.additionalEscalatees[j];
  			if (!rotas[additionalEscalatee.rotaId])
  				rotas[additionalEscalatee.rotaId] = [];
  			if (i == 0 && firstReminderSent && additionalEscalatee.reminderNum == 0) {
  				rotas[additionalEscalatee.rotaId].push({
  					escalationGroups: additionalEscalatee.escalationGroups
  				});
  			} else {
  				rotas[additionalEscalatee.rotaId].push({
  					userId: additionalEscalatee.userId,
  					userIds: additionalEscalatee.userIds,
  					escalationGroups: additionalEscalatee.escalationGroups,
  					deviceId: additionalEscalatee.deviceId,
  					deviceIds: additionalEscalatee.deviceIds,
  					reminderNumber: additionalEscalatee.reminderNum
  				});
  			}
  			if (i == 0 && firstReminderSent) {
  				additionalEscalatee.reminderNum--;
  				if (additionalEscalatee.userId)
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'user', id: additionalEscalatee.userId }, conferenceCallSysId);
  				if (additionalEscalatee.userIds) {
  					for (var k = 0; k < additionalEscalatee.userIds.length; k++) {
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'user', id: additionalEscalatee.userIds[k] }, conferenceCallSysId);
  					}
  				}
  				if (additionalEscalatee.deviceId) {
  					var phoneNumber = this.getPhoneNumber(additionalEscalatee.deviceId);
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'device', phone_number: phoneNumber }, conferenceCallSysId);
  				}
  				if (additionalEscalatee.deviceIds) {
  					for (var k = 0; k < additionalEscalatee.deviceIds.length; k++) {
  						var phoneNumber = this.getPhoneNumber(additionalEscalatee.deviceIds[k]);
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({ type: 'device', phone_number: phoneNumber }, conferenceCallSysId);
  					}
  				}
  			}
  			while (additionalEscalatee.reminderNum > 0) {
  				rotas[additionalEscalatee.rotaId].push({
  					userId: additionalEscalatee.userId,
  					userIds: additionalEscalatee.userIds,
  					deviceId: additionalEscalatee.deviceId,
  					deviceIds: additionalEscalatee.deviceIds,
  					reminderNumber: additionalEscalatee.reminderNum
  				});
  				additionalEscalatee.reminderNum--;
  			}
  		}
  	}

  	return {
  		rotas: rotas,
  		hasFirstReminderJoined: hasFirstReminderJoined,
  		currentRotaID: rota.getCurrentRotaID()
  	};
  },

  getRotasAndUpdateFirstReminderJoinedStatusByPreferences: function(groupId, gdt, hasFirstReminderJoined, firstReminderSent, conferenceCallSysId, taskGr) {
  	var rotas = {};
  	var rota = new OnCallRotation();
  	var escalationPlan = rota.getEscalationPlan(groupId, new GlideDateTime(gdt), null, taskGr);
  	for(var i = 0;i < escalationPlan.length; i++) {
  		var escalatee = escalationPlan[i];
  		if (escalatee.rotaId) {
  			if (!rotas[escalatee.rotaId])
  				rotas[escalatee.rotaId] = [];

  			if (i == 0 && firstReminderSent) {
  				if (escalatee.userId)
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'user', id: escalatee.userId}, conferenceCallSysId);
  				if (escalatee.userIds) {
  					for (var k = 0; k < escalatee.userIds.length; k++) {
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'user', id: escalatee.userIds[k]}, conferenceCallSysId);
  					}
  				}
  				if (escalatee.deviceId) {
  					var phoneNumber = this.getPhoneNumber(escalatee.deviceId);
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'device', phone_number: phoneNumber}, conferenceCallSysId);
  				}
  				if (escalatee.deviceIds) {
  					for (var k = 0; k < escalatee.deviceIds.length; k++) {
  						var phoneNumber = this.getPhoneNumber(escalatee.deviceIds[k]);
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'device', phone_number: phoneNumber}, conferenceCallSysId);
  					}
  				}
  			}

  			var contactAttempt = 1;
  			while (contactAttempt <= escalatee.reminderNum + 1) {
  				if (i == 0 && firstReminderSent && contactAttempt == 1) {
  					rotas[escalatee.rotaId].push({
  						escalationGroups: escalatee.escalationGroups,
  						deviceId: escalatee.deviceId,
  						deviceIds: escalatee.deviceIds,
  						contactAttempt: contactAttempt,
  						escalationLevel: escalatee.order,
  						escalatee: escalatee
  					});
  				}
  				else {
  					var escalateeObj = {
  						userId: escalatee.userId,
  						userIds: escalatee.userIds,
  						deviceId: escalatee.deviceId,
  						deviceIds: escalatee.deviceIds,
  						contactAttempt: contactAttempt,
  						escalationLevel: escalatee.order,
  						escalatee: escalatee
  					};
  					if (contactAttempt == 1) {
  						escalateeObj.escalationGroups = escalatee.escalationGroups
  					}
  					rotas[escalatee.rotaId].push(escalateeObj);
  				}
  				contactAttempt++;
  			}
  		}

  		for(var j = 0; j < escalatee.additionalEscalatees.length; j++) {
  			var additionalEscalatee = escalatee.additionalEscalatees[j];
  			if(!rotas[additionalEscalatee.rotaId])
  				rotas[additionalEscalatee.rotaId] = [];

  			if (i == 0 && firstReminderSent) {
  				if (additionalEscalatee.userId)
  				hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'user', id: additionalEscalatee.userId}, conferenceCallSysId);
  				if (additionalEscalatee.userIds) {
  					for (var k = 0; k < additionalEscalatee.userIds.length; k++) {
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'user', id: additionalEscalatee.userIds[k]}, conferenceCallSysId);
  					}
  				}
  				if (additionalEscalatee.deviceId) {
  					var phoneNumber = this.getPhoneNumber(additionalEscalatee.deviceId);
  					hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'device', phone_number: phoneNumber}, conferenceCallSysId);
  				}
  				if (additionalEscalatee.deviceIds) {
  					for (var k = 0; k < additionalEscalatee.deviceIds.length; k++) {
  						var phoneNumber = this.getPhoneNumber(additionalEscalatee.deviceIds[k]);
  						hasFirstReminderJoined = hasFirstReminderJoined || this.checkIfPrimaryAnsweredCall({type: 'device', phone_number: phoneNumber}, conferenceCallSysId);
  					}
  				}
  			}

  			var contactAttempt = 1;
  			while (contactAttempt <= additionalEscalatee.reminderNum + 1) {
  				if (i == 0 && firstReminderSent && contactAttempt == 1) {
  					rotas[additionalEscalatee.rotaId].push({
  						escalationGroups: additionalEscalatee.escalationGroups,
  						deviceId: additionalEscalatee.deviceId,
  						deviceIds: additionalEscalatee.deviceIds,
  						contactAttempt: contactAttempt,
  						escalationLevel: additionalEscalatee.order,
  						escalatee: additionalEscalatee
  					});
  				}
  				else {
  					var escalateeObj = {
  						userId: additionalEscalatee.userId,
  						userIds: additionalEscalatee.userIds,
  						deviceId: additionalEscalatee.deviceId,
  						deviceIds: additionalEscalatee.deviceIds,
  						contactAttempt: contactAttempt,
  						escalationLevel: additionalEscalatee.order,
  						escalatee: additionalEscalatee
  					};
  					if (contactAttempt == 1) {
  						escalateeObj.escalationGroups = additionalEscalatee.escalationGroups;
  					}
  					rotas[additionalEscalatee.rotaId].push(escalateeObj);
  				}
  				contactAttempt++;
  			}
  		}
  	}
  	
  	return {
  		rotas: rotas,
  		hasFirstReminderJoined: hasFirstReminderJoined,
  		currentRotaID: rota.getCurrentRotaID()
  	};
  },
  
  getEscalatees: function(escalationPlan, processedRotas) {
  	var escalatees = [];
  	var reminderTime = {};

  	for (var i = 0; i < escalationPlan.length; i++) {
  		var escalatee = escalationPlan[i];
  		var reminderDelay = escalatee.timeBetweenReminders ? escalatee.timeBetweenReminders.getNumericValue() / 1000 : 0;
  		var reminders = escalatee.reminderNum;
  		var timeToNextStep = escalatee.timeToNextStep ? escalatee.timeToNextStep.getNumericValue() / 1000: 0;
  		if(!reminderTime[escalatee.rotaId])
  			reminderTime[escalatee.rotaId] = 0;
  		if (processedRotas.indexOf(escalatee.rotaId) == -1) {

  			var users = [];
  			var groups = [];
  			var devices = [];

  			if (escalatee.getUserId())
  				users.push(escalatee.getUserId());
  			if (escalatee.getUserIds() && escalatee.getUserIds().length > 0)
  				users = users.concat(escalatee.getUserIds());

  			for (var j = 0; j < users.length; j++) {
  				var time = reminderTime[escalatee.rotaId];
  				var escalateeGr = new GlideRecord('sys_user');
  				if (escalateeGr.get(users[j])) {
  					escalatees.push({type: 'User', name: escalateeGr.getValue('name'), reminderTime: time});
  					var reminderNum = reminders;
  					while (reminderNum > 0) {
  						time = time + reminderDelay;
  						escalatees.push({type: 'User', name: escalateeGr.getValue('name'), reminderTime: time});
  						reminderNum--;
  					}
  				}
  			}

  			if (escalatee.getUserIds() && escalatee.getUserIds().length > 0)
  				groups = escalatee.getEscalationGroups();

  			for (var j = 0; j < groups.length; j++) {
  				var time = reminderTime[escalatee.rotaId];
  				var escalateeGr = new GlideRecord('sys_user_group');
  				if (escalateeGr.get(groups[j])) {
  					escalatees.push({type: 'Group', name: escalateeGr.getValue('name'), reminderTime: time});
  				}
  			}

  			if (escalatee.getDeviceId())
  				devices.push(escalatee.getDeviceId());
  			if (escalatee.getDeviceIds() && escalatee.getDeviceIds().length > 0)
  				devices = devices.concat(escalatee.getDeviceIds());

  			for (var j = 0; j < devices.length; j++) {
  				var time = reminderTime[escalatee.rotaId];
  				var escalateeGr = new GlideRecord('cmn_notif_device');
  				if (escalateeGr.get(devices[j])) {
  					escalatees.push({type: 'Device', name: escalateeGr.getValue('name'), reminderTime: time});
  					var reminderNum = reminders;
  					while (reminderNum > 0) {
  						time = time + reminderDelay;
  						escalatees.push({type: 'Device', name: escalateeGr.getValue('name'), reminderTime: time});
  						reminderNum--;
  					}
  				}
  			}

  			if (escalatee.cmnRotaEscStepDefId)
  				reminderTime[escalatee.rotaId] = reminderTime[escalatee.rotaId] + reminderDelay * reminders + timeToNextStep;
  			else if(escalatee.rotaId)
  				reminderTime[escalatee.rotaId] = reminderTime[escalatee.rotaId] + reminderDelay * (reminders + 1);

  		}

  		if(escalationPlan[i].additionalEscalatees) {
  			for(var j = 0; j < escalationPlan[i].additionalEscalatees.length; j++){
  				var additionalEscalatee = escalationPlan[i].additionalEscalatees[j];
  				var reminderDelay = additionalEscalatee.timeBetweenReminders ? additionalEscalatee.timeBetweenReminders.getNumericValue() / 1000 : 0;
  				var reminders = additionalEscalatee.reminderNum;
  				var timeToNextStep = additionalEscalatee.timeToNextStep ? additionalEscalatee.timeToNextStep.getNumericValue() / 1000: 0;
  				if(!reminderTime[additionalEscalatee.rotaId])
  					reminderTime[additionalEscalatee.rotaId] = 0;
  				if (processedRotas.indexOf(additionalEscalatee.rotaId) == -1) {

  					var users = [];
  					var groups = [];
  					var devices = [];

  					if (additionalEscalatee.getUserId())
  						users.push(additionalEscalatee.getUserId());
  					if (additionalEscalatee.getUserIds() && additionalEscalatee.getUserIds().length > 0)
  						users = users.concat(additionalEscalatee.getUserIds());

  					for (var k = 0; k < users.length; k++) {
  						var time = reminderTime[additionalEscalatee.rotaId];
  						var escalateeGr = new GlideRecord('sys_user');
  						if (escalateeGr.get(users[k])) {
  							escalatees.push({type: 'User', name: escalateeGr.getValue('name'), reminderTime: time});
  							var reminderNum = reminders;
  							while (reminderNum > 0) {
  								time = time + reminderDelay;
  								escalatees.push({type: 'User', name: escalateeGr.getValue('name'), reminderTime: time});
  								reminderNum--;
  							}
  						}
  					}

  					if (additionalEscalatee.getUserIds() && additionalEscalatee.getUserIds().length > 0)
  						groups = additionalEscalatee.getEscalationGroups();

  					for (var k = 0; k < groups.length; k++) {
  						var time = reminderTime[additionalEscalatee.rotaId];
  						var escalateeGr = new GlideRecord('sys_user_group');
  						if (escalateeGr.get(groups[k])) {
  							escalatees.push({type: 'Group', name: escalateeGr.getValue('name'), reminderTime: time});
  						}
  					}

  					if (additionalEscalatee.getDeviceId())
  						devices.push(additionalEscalatee.getDeviceId());
  					if (additionalEscalatee.getDeviceIds() && additionalEscalatee.getDeviceIds().length > 0)
  						devices = devices.concat(additionalEscalatee.getDeviceIds());

  					for (var k = 0; k < devices.length; k++) {
  						var time = reminderTime[additionalEscalatee.rotaId];
  						var escalateeGr = new GlideRecord('cmn_notif_device');
  						if (escalateeGr.get(devices[k])) {
  							escalatees.push({type: 'Device', name: escalateeGr.getValue('name'), reminderTime: time});
  							var reminderNum = reminders;
  							while (reminderNum > 0) {
  								time = time + reminderDelay;
  								escalatees.push({type: 'Device', name: escalateeGr.getValue('name'), reminderTime: time});
  								reminderNum--;
  							}
  						}
  					}

  					if (additionalEscalatee.cmnRotaEscStepDefId)
  						reminderTime[additionalEscalatee.rotaId] = reminderTime[additionalEscalatee.rotaId] + reminderDelay * reminders + timeToNextStep;
  					else
  						reminderTime[additionalEscalatee.rotaId] = reminderTime[additionalEscalatee.rotaId] + reminderDelay * (reminders + 1);

  				}
  			}
  		}
  	}

  	escalatees.sort(function(a, b) {
  		return a.reminderTime - b.reminderTime;
  	});
  	return escalatees;
  },
  
  getUser: function(userId) {
  	var userGr = new GlideRecord("sys_user");
  	if (userGr.get(userId)) {
  		return {
  			recordClass: 'sys_user',
  			id: userId,
  			name: userGr.getValue('name'),
  			email: userGr.getValue('email')
  		};
  	}
  	return null;
  },

  getDevice: function (deviceId) {
  	var deviceGr = new GlideRecord('cmn_notif_device');
  	if (deviceGr.get(deviceId)) {
  		return {
  			recordClass: 'cmn_notif_device',
  			id: deviceId,
  			name: deviceGr.getValue('name'),
  			type: deviceGr.getValue('type'),
  			email: deviceGr.getValue('email_address')
  		};
  	}
  	return null;
  },

  getOnCallGroupNotifyNumber: function() {
  	if(this.isNotifyPluginInstalled()){
  		var notifyNumberGr = new GlideRecord('notify_number');
  		notifyNumberGr.addQuery('notify_group.name', 'On-Call Group');
  		notifyNumberGr.addActiveQuery();
  		notifyNumberGr.query();
  		if(notifyNumberGr.next())
  			return notifyNumberGr.number;
  	}
  },

  getOnCallGroupNotifyNumberSysId: function () {
  	if(this.isNotifyPluginInstalled()){
  		var notifyNumberGr = new GlideRecord('notify_number');
  		notifyNumberGr.addQuery('notify_group.name', 'On-Call Group');
  		notifyNumberGr.addActiveQuery();
  		notifyNumberGr.query();
  		if (notifyNumberGr.next())
  			return notifyNumberGr.getUniqueValue();
  	}
  },

   /**
   * Add all phone numbers of the user to a conference call
   *
   * @param participant
   * @param conferenceCall
   * @param groupId
   * @param phoneNumbers - all phone numbers based on user preferences
   * @returns {boolean}
   */
  callUserPreferredNumbers: function(participant, conferenceCall, groupId, phoneNumbers) {
  	var record = new GlideRecord('sys_user');
  	var user;
  	if (record.get(participant))
			user = record;

  	var from = conferenceCall.notify_number.number + '';
  	var to;

  	// got a from number?
  	if (!from) {
  		gs.info(gs.getMessage("Conference call record doesn't have any notify number"));
  		return false;
  	}

  	// all Phone numbers called
  	for (var i = 0; i < phoneNumbers.length; i++) {
  		// add to conference call
  		var notify = new sn_notify.NotifyScoped();
  		notify.call(from, phoneNumbers[i], conferenceCall, (!user ? null : user.getUniqueValue()), (!groupId ? null : groupId));	
  	}
  	return true;
  },

  // Get preferred phone numbers for a user
  getPreferencePhoneNumbers: function(userSysId, contactAttempt) {
  	var onContactPrefUtil = new OnCallContactPreferenceUtil();
  	var userPrefs = onContactPrefUtil.getUserPreferences(userSysId, contactAttempt, null, 'voice');
  	var phoneNums = [];
  	if (userPrefs.length > 0) {
  		for (var i = 0; i < userPrefs.length ; i++) {
  			var pref = userPrefs[i];
  			if (pref.number)
  				phoneNums.push(pref.number);
  		}
  	} 
  	return phoneNums;
  },

  addEscalatee: function (userId, preferredPhoneNumbers, scratchpad) {
  	if (!preferredPhoneNumbers)
  		preferredPhoneNumbers = [];
  	if (scratchpad.processedEscalatees.indexOf(userId) == -1) {
  		scratchpad.processedEscalatees.push(userId);
  	}
  	for (var i = 0; i < preferredPhoneNumbers.length; i++) {
  		var phoneNumber = preferredPhoneNumbers[i];
  		if (scratchpad.processedPhoneNumbers.indexOf(phoneNumber) == -1) {
  			scratchpad.processedPhoneNumbers.push(phoneNumber);
  		}
  	}
  	return scratchpad;
  },

  addPhoneNumber: function (phoneNumber, scratchpad) {
  	if (scratchpad.processedPhoneNumbers.indexOf(phoneNumber) == -1)
  		scratchpad.processedPhoneNumbers.push(phoneNumber);
  	return scratchpad;
  },

  getNotifyCallStatusResponse: function (phoneNumber, sysId, contextSysCreatedOn) {
  	var response = '';
  	var notifyCallStatus = new GlideRecord("notify_call_status");
  	notifyCallStatus.addQuery("notify_call.direction", "Outbound");
  	notifyCallStatus.addQuery("notify_call.phone_number", phoneNumber);
  	notifyCallStatus.addQuery("notify_call.source", sysId);
  	if (contextSysCreatedOn)
  		notifyCallStatus.addQuery("sys_created_on", ">", contextSysCreatedOn);
  	notifyCallStatus.addQuery("status", "input");
  	notifyCallStatus.orderByDesc("sys_created_on");
  	notifyCallStatus.query();
  	if (notifyCallStatus.next()) {
  		response = notifyCallStatus.getValue("digits");
  	}
  	return response;
  },

  clearNotifyMessageNumbers: function (sourceId) {
  	if (this.isNotifyPluginInstalled()) {
  		if (sourceId) {
  			var messageNumberGr = new GlideRecord("on_call_message_number");
  			messageNumberGr.addQuery("source", sourceId);
  			messageNumberGr.query();
  			if (messageNumberGr.hasNext()) {
  				messageNumberGr.deleteMultiple();
  			} else { // fall back during upgrade - TODO: remove it after couple of releases
  				var message = new GlideRecord("notify_message");
  				if(message.isValidField('message_number') ) { 
  					message.addQuery("source", sourceId);					
  					message.addQuery("direction", "outbound");					
  					message.query();				
  					while (message.next()) {	
  						message.setValue("message_number", "");	
  						message.update();	
  					}
  				}
  			}
  		}
  	}
  },
  
  addEscalateePerRota: function(scratchpad) {
  	var ocwUtils = new OnCallWorkflowUtils();
  	var group = scratchpad.group;
  	var rotas = scratchpad.rotas;
  	group.currentLevel++;
  	group.currentEscalateesInThisLevel = [];
  	group.rotasInThisIteration = [];
  	group.rotasInThisIterationIndex = 0;

  	Object.keys(rotas).forEach(function (key) {
  		if (rotas[key][group.currentLevel - 1]) {
  			var eachRota = {
  				id: key,
  				escalatees: [],
  				escalationLevel: rotas[key][group.currentLevel - 1].escalationLevel,
  				contactAttempt: rotas[key][group.currentLevel - 1].contactAttempt,
  				escalatee: rotas[key][group.currentLevel - 1].escalatee,
  				escalationGroups: rotas[key][group.currentLevel - 1].escalationGroups
  			};
  			if (rotas[key][group.currentLevel - 1].userId) {
  				var phoneNums = ocwUtils.getPreferencePhoneNumbers(rotas[key][group.currentLevel - 1].userId, rotas[key][group.currentLevel - 1].contactAttempt);
  				eachRota.escalatees.push({
  					id: rotas[key][group.currentLevel - 1].userId,
  					type: 'user',
  					phoneNumbers: phoneNums,
  					contactAttempt: rotas[key][group.currentLevel - 1].contactAttempt,
  					escalationLevel: rotas[key][group.currentLevel - 1].escalationLevel,
  					escalatee: rotas[key][group.currentLevel - 1].escalatee,
  					rotaId: key
  				});
  				scratchpad = ocwUtils.addEscalatee(rotas[key][group.currentLevel - 1].userId, phoneNums, scratchpad);
  			}
  			if (rotas[key][group.currentLevel - 1].userIds) {
  				for (var i = 0; i < rotas[key][group.currentLevel - 1].userIds.length; i++) {
  					var phoneNums = ocwUtils.getPreferencePhoneNumbers(rotas[key][group.currentLevel - 1].userIds[i], rotas[key][group.currentLevel - 1].contactAttempt);
  					eachRota.escalatees.push({
  						id: rotas[key][group.currentLevel - 1].userIds[i],
  						type: 'user',
  						phoneNumbers: phoneNums,
  						contactAttempt: rotas[key][group.currentLevel - 1].contactAttempt,
  						escalationLevel: rotas[key][group.currentLevel - 1].escalationLevel,
  						escalatee: rotas[key][group.currentLevel - 1].escalatee,
  						rotaId: key
  					});
  					scratchpad = ocwUtils.addEscalatee(rotas[key][group.currentLevel - 1].userIds[i], phoneNums, scratchpad);
  				}
  			}
  			if (rotas[key][group.currentLevel - 1].deviceId) {
  				var phoneNumber = ocwUtils.getPhoneNumber(rotas[key][group.currentLevel - 1].deviceId);
  				eachRota.escalatees.push({
  					id: rotas[key][group.currentLevel - 1].deviceId,
  					phone_number: phoneNumber,
  					type: 'device',
  					contactAttempt: rotas[key][group.currentLevel - 1].contactAttempt,
  					escalationLevel: rotas[key][group.currentLevel - 1].escalationLevel,
  					escalatee: rotas[key][group.currentLevel - 1].escalatee,
  					rotaId: key
  				});
  				if (phoneNumber) {
  					scratchpad = ocwUtils.addPhoneNumber(phoneNumber, scratchpad);
  				}
  			}
  			if (rotas[key][group.currentLevel - 1].deviceIds) {
  				for (var i = 0; i < rotas[key][group.currentLevel - 1].deviceIds.length; i++) {
  					var phoneNumber = ocwUtils.getPhoneNumber(rotas[key][group.currentLevel - 1].deviceIds[i]);
  					eachRota.escalatees.push({
  						id: rotas[key][group.currentLevel - 1].deviceIds[i],
  						phone_number: phoneNumber,
  						type: 'device',
  						contactAttempt: rotas[key][group.currentLevel - 1].contactAttempt,
  						escalationLevel: rotas[key][group.currentLevel - 1].escalationLevel,
  						escalatee: rotas[key][group.currentLevel - 1].escalatee,
  						rotaId: key
  					});
  					if (phoneNumber) {
  						scratchpad = ocwUtils.addPhoneNumber(phoneNumber, scratchpad);
  					}
  				}
  			}
  			group.rotasInThisIteration.push(eachRota);
  		} else if (group.currentLevel == rotas[key].length + 1) {
  			//handle catchAll
  			var catchAllUsers = ocwUtils.getCatchAllUsers(key, group, current);
  			var lastLevelInThisRota = rotas[key][rotas[key].length - 1];
  			if (catchAllUsers && catchAllUsers.length > 0 && lastLevelInThisRota) {
  				var eachRota = {
  					id: key,
  					escalatees: [],
  					escalationLevel: lastLevelInThisRota.escalationLevel + 1,
  					contactAttempt: 1,
  					escalatee: lastLevelInThisRota.escalatee,
  					catchAll: true
  				};

  				for (var i = 0; i < catchAllUsers.length; i++) {
  					var phoneNums = ocwUtils.getPreferencePhoneNumbers(catchAllUsers[i], 1);
  					eachRota.escalatees.push({
  						id: catchAllUsers[i],
  						type: 'user',
  						phoneNumbers: phoneNums,
  						contactAttempt: 1,
  						escalationLevel: lastLevelInThisRota.escalationLevel + 1,
  						escalatee: lastLevelInThisRota.escalatee,
  						rotaId: key
  					});
  				}

  				group.rotasInThisIteration.push(eachRota);
  			}
  		}
  	});
  	return scratchpad;	
  },
  
  getEscalationResponse: function(wfcontextId, source, table, user) {
  	var gr = new GlideRecord(this.TABLES.ON_CALL_ESCALATION_RESPONSE);
  	gr.addQuery('table', table);
  	gr.addQuery('source', source);
  	gr.addQuery('user', user);
  	gr.addQuery('wf_context', wfcontextId);
  	gr.query();
  	return gr;
  },
  	
  createEscalationResponse: function(wfcontextId, source, table, user) {
  	var gr = this.getEscalationResponse(wfcontextId, source, table, user);
  	if (gr.hasNext())
  		return;
  	gr.initialize();
  	gr.wf_context = wfcontextId;
  	gr.source = source;
  	gr.table = table;
  	gr.user = user;
  	if (gr.insert())
  		return gr;
  },
  
  cleanEscalationResponse: function(wfcontextId) {
  	if (! wfcontextId)
  		return;
  	var gr = new GlideRecord(this.TABLES.ON_CALL_ESCALATION_RESPONSE);
  	gr.addQuery('wf_context', wfcontextId);
  	gr.deleteMultiple();
  },
  
  updateEscalationResponse: function(user, table, source, response) {
  	var gr = new GlideRecord(this.TABLES.ON_CALL_ESCALATION_RESPONSE);
  	gr.addQuery('table', table);
  	gr.addQuery('source', source);
  	gr.addQuery('user', user);
  	gr.query();
  	while (gr.next()) {
  		gr.response = response;
  		gr.update();
  	}
  },
  
  getWFContextsWithRejectedEscalation: function(user, table, source) {
  	var wfContextIds = [];				
  	var gr = new GlideRecord(this.TABLES.ON_CALL_ESCALATION_RESPONSE);
  	gr.addQuery('table', table);
  	gr.addQuery('source', source);
  	gr.addQuery('user', user);
  	gr.query();
  	while (gr.next())
  		wfContextIds.push(gr.wf_context + '');
  	
  	var wfContextIdResponse = {};
  	var gr1 = new GlideRecord(this.TABLES.ON_CALL_ESCALATION_RESPONSE);
  	gr1.addQuery('wf_context', 'IN', wfContextIds);
  	gr1.query();
  	while (gr1.next()) {
  		var wfcontextId = gr1.wf_context + '';
  		if(wfContextIdResponse[wfcontextId] == undefined)
  			wfContextIdResponse[wfcontextId] = true;
  		if(wfContextIdResponse[wfcontextId] == true && gr1.response != this.COMMUNICATION_RESPONSE.REJECTED)
  			wfContextIdResponse[wfcontextId] = false;	
  	}
  	return wfContextIdResponse;
  },

  checkIfResponseReceivedAndPopulateRejectedUsers: function(inputParamObj) {

  	if (this._log.atLevel(GSLog.DEBUG))
  		this._log.logDebug("[checkIfResponseReceivedAndPopulateRejectedUsers] inputParamObj: " + JSON.stringify(inputParamObj));

  	var response = {};
  	response["rejectedUserIds"] = inputParamObj.rejectedUserIds;

  	var i = 0;

  	if (this.isNotifyPluginInstalled()) {
  		for (i = 0; i < inputParamObj.processedPhoneNumber.length; i++) {
  			var processedPhoneNumberObj = inputParamObj.processedPhoneNumber[i];
  			var acceptResponse = "ACC";
  			var rejectResponse = "REJ";
  			if (processedPhoneNumberObj.message_counter != "0") {
  				acceptResponse = processedPhoneNumberObj.message_counter + "ACC";
  				rejectResponse = processedPhoneNumberObj.message_counter + "REJ";
  			}

  			// is there an inbound SMS from the escalatee phone number
  			var message = new GlideRecord("notify_message");
  			message.addQuery("direction", "inbound");
  			message.addQuery("phone_number", processedPhoneNumberObj.phoneNumber);
  			message.addQuery("sys_created_on", ">", inputParamObj.contextSysCreatedOn);
  			message.orderBy("sys_created_on");
  			message.query();

  			// we only care about no response or the 1st valid response
  			if (message.next()) {
  				var body = message.getValue('body').trim().toUpperCase();

  				if (body === acceptResponse) {
  					response["acknowledged"] = true;
  					response["responsedReceived"] = true;
  					return response;
  				} else if (body === rejectResponse) {
  					response["acknowledged"] = false;
  					if (response.rejectedUserIds.indexOf(processedPhoneNumberObj.user_id) == -1)
  						response.rejectedUserIds.push(processedPhoneNumberObj.user_id);
  				}
  			}
  		}

  		for (i = 0; i < inputParamObj.processedVoiceNumber.length; i++) {
  			var processedVoiceNumberObj = inputParamObj.processedVoiceNumber[i];			
  			var notifyCallResponse = this.getNotifyCallStatusResponse(processedVoiceNumberObj.phoneNumber, inputParamObj.currentSysId, inputParamObj.contextSysCreatedOn);

  			if (notifyCallResponse == 1) {
  				response["acknowledged"] = true;
  				response["responsedReceived"] = true;
  				return response;
  			} else if (notifyCallResponse == 2) {
  				response["acknowledged"] = false;
  				if (response.rejectedUserIds.indexOf(processedVoiceNumberObj.user_id) == -1)
  					response.rejectedUserIds.push(processedVoiceNumberObj.user_id);
  			}
  		}
  	}

  	var className = inputParamObj.currentSysClassName;
  	className = className.charAt(0).toUpperCase() + className.slice(1);
  
  	//Having both old and new email message to avoid issue during upgrade if a user replies to an old email
  	var emailMessage = gs.getMessage("{0} was escalated.\nTo assign yourself to the {1}, reply to this email with 'ACC' in the message body.\nTo reject and move the {1} to the next person in the escalation path, reply to this email with 'REJ'", [inputParamObj.currentNumber, className]);
  
  	var emailMessageOld = gs.getMessage("You are being asked to assign yourself to {0}. To accept and assign yourself to the {1} reply to this email with 'ACC'. To reject reply to this email with 'REJ'. Rejecting will progress this assignment to the next process in escalation.", [inputParamObj.currentNumber, className]);

  	if (inputParamObj.isCurrentLevelCatchAll) {
  	
  		emailMessage = gs.getMessage("Task {0} was escalated but no on-call user accepted it in time. Please investigate.\nTo assign yourself to the task, reply to this email with 'ACC' in the message body.\nTo reject and end the escalation, reply to this email with 'REJ'", inputParamObj.currentNumber);
  	
  		emailMessageOld = gs.getMessage("A task with number {0} was raised and escalated but no on-call user has accepted it in time. Please investigate. To assign yourself to the task reply to this email with 'ACC'. To reject reply to this email with 'REJ'. Rejecting will end this escalation.", inputParamObj.currentNumber);
  	}

  	for (i = 0; i < inputParamObj.processedUserForEmail.length; i++) {
  		// is there an inbound email from the escalatee
  		var email = new GlideRecord("sys_email");
  		email.addQuery("user_id", inputParamObj.processedUserForEmail[i]);
  		email.addQuery("type", "received");
  		email.addQuery("sys_created_on", ">", inputParamObj.contextSysCreatedOn);
  		email.orderBy("sys_created_on");
  		var orEmail = email.addQuery("body_text", "CONTAINS", emailMessage);
  		orEmail.addOrCondition("body_text", "CONTAINS", emailMessageOld);
  		email.query();

  		while (email.next()) {
  			var emailRes = this.parseEmailResponse(email.body_text, inputParamObj.currentNumber);				
  			if (emailRes === 'ACC') {
  				response["acknowledged"] = true;
  				response["responsedReceived"] = true;
  				return response;
  			} else if (emailRes === 'REJ') {
  				response["acknowledged"] = false;
  				if (response.rejectedUserIds.indexOf(email.getValue('user_id')) == -1)
  					response.rejectedUserIds.push(email.getValue('user_id'));
  			}
  		}
  	}

  	if (this.isSlackPluginInstalled()) {
  		for (i = 0; i < inputParamObj.processedUserForSlack.length; i++) {
  			var slackResponseGR = new GlideRecord("sn_slack_ah_v2_inbound");
  			slackResponseGR.addQuery("user", inputParamObj.processedUserForSlack[i]);
  			slackResponseGR.addQuery("context_id", inputParamObj.wfContextId);
  			slackResponseGR.query();

  			while (slackResponseGR.next()) {
  				var action = slackResponseGR.getValue('response_action');		
  				if (action === "Accept") {
  					response["acknowledged"] = true;
  					response["responsedReceived"] = true;
  					return response;
  				} else if (action === "Reject") {
  					response["acknowledged"] = false;
  					if (response.rejectedUserIds.indexOf(slackResponseGR.getValue('user')) == -1)
  						response.rejectedUserIds.push(slackResponseGR.getValue('user'));
  				}
  			}
  		}
  	}

  	if (this.isMobilePushInstalled() && inputParamObj && inputParamObj.processedUserForMobile) {
  		for (i = 0; i < inputParamObj.processedUserForMobile.length; i++) {
  			var processedUserForMobile = inputParamObj.processedUserForMobile[i];
  			var onCallPushRequestGr = new GlideRecord(this.TABLES.ON_CALL_PUSH_REQUEST);
  			onCallPushRequestGr.addActiveQuery();
  			onCallPushRequestGr.addQuery("acceptor", processedUserForMobile);
  			onCallPushRequestGr.addQuery("source_table", inputParamObj.currentSysClassName);
  			onCallPushRequestGr.addQuery("document_id", inputParamObj.currentSysId);
  			onCallPushRequestGr.query();
  			while (onCallPushRequestGr.next()) {
  				var onCallPushResponse = onCallPushRequestGr.getValue('state');
  				if (onCallPushResponse === "accepted") {
  					response["acknowledged"] = true;
  					response["responsedReceived"] = true;
  					return response;
  				} else if (onCallPushResponse === "rejected") {
  					response["acknowledged"] = false;
  					if (response.rejectedUserIds.indexOf(onCallPushRequestGr.getValue("acceptor")) === -1)
  						response.rejectedUserIds.push(onCallPushRequestGr.getValue("acceptor"));
  				}
  			}
  		}
  	}
  	
  	if (this.isTeamsPluginInstalled() && inputParamObj && inputParamObj.processedUserForTeams) {
  		var teamsUtil = new OnCallTeamsUtils();
  		var teamsOutboundMessagesGr = teamsUtil.getTeamsOutboundMessageGr(inputParamObj.processedUserForTeams.join(","), inputParamObj.wfContextId);
  		
  		if (teamsOutboundMessagesGr.next()) {
  			var outboundPayload = {};
  			try {
  				outboundPayload = teamsOutboundMessagesGr.getValue("payload") ? JSON.parse(teamsOutboundMessagesGr.getValue("payload")) : "";
  			} catch (e) {
  				this._log.logError("[checkIfResponseReceivedAndPopulateRejectedUsers] Error in parsing the outbound message payload");
  			}
  			var messageState = outboundPayload.sumittedAction + "";
  			if (messageState == teamsUtil.TEAMS_MESSAGE_STATE.ACCEPTED) {
  				response["acknowledged"] = true;
  				response["responsedReceived"] = true;
  				return response;
  			} else if (messageState == teamsUtil.TEAMS_MESSAGE_STATE.REJECTED) {
  				response["acknowledged"] = false;
  				if (response.rejectedUserIds.indexOf(teamsOutboundMessagesGr.getValue("recipient")) === -1)
  					response.rejectedUserIds.push(teamsOutboundMessagesGr.getValue("recipient"));
  			}
  		}
  	}

  	response["responsedReceived"] = false;

  	if (this._log.atLevel(GSLog.DEBUG))
  		this._log.logDebug("[checkIfResponseReceivedAndPopulateRejectedUsers] response: " + JSON.stringify(response));		

  	return response;
  },

  parseEmailResponse: function (emailBodyStr, taskNumber) {
  	var match;

  	if (this.isStartingWithOneOfTheWords(emailBodyStr, this.EMAIL_CHANNEL_ACCEPT_RESPONSES))
  		match = 'ACC';
  	else if (this.isStartingWithOneOfTheWords(emailBodyStr, this.EMAIL_CHANNEL_REJECT_RESPONSES))
  		match = 'REJ';

  	return match;
  },
  
  isStartingWithOneOfTheWords: function(str, words) {
  	str = str.trim();
  	var i;
  	for (i = 0; i < words.length; i++) {
  		if (new RegExp('^' + words[i] + '([^a-zA-Z\d\s:]|$)', 'i').test(str))
  			return true;
  	}
  	return false;
  },

  createMessageNumber: function(phoneNumber, messageNumber, table, source, userSysId) {
  	if (phoneNumber && !JSUtil.nil(messageNumber)) {
  		var recentUsedNumberGr = new GlideRecord("on_call_message_number");
  		recentUsedNumberGr.setValue('phone_number',  phoneNumber);
  		recentUsedNumberGr.setValue('message_number',  messageNumber);
  		recentUsedNumberGr.setValue('table',  table);
  		recentUsedNumberGr.setValue('source',  source);
  		if (userSysId)
  			recentUsedNumberGr.setValue("user", userSysId);
  		return recentUsedNumberGr.insert() !== null;
  	}
  },

  isNotifyPluginInstalled: function() {
  	return this._onCallCommon.isNotifyPluginInstalled();
  },

  isSlackPluginInstalled: function() {
  	return this._onCallCommon.isSlackPluginInstalled();
  },

  isMobilePushInstalled: function() {
  	return this._onCallCommon.isMobilePushInstalled();
  },
  
  isTeamsPluginInstalled: function() {
  	return this._onCallCommon.isTeamsPluginInstalled();
  },

  type: 'OnCallWorkflowUtilsSNC'
};

Sys ID

3151fd9d73422300cbb654eb7df6a7b4

Offical Documentation

Official Docs: