Name

sn_sow_on_call.OnCallRotationSowSNC

Description

ServiceNow On-Call Rotation for SOW implementation

Script

var OnCallRotationSowSNC = Class.create();

OnCallRotationSowSNC.LOG_PROPERTY = 'com.snc.on_call_rotation.log.level';

OnCallRotationSowSNC.prototype = {
  initialize: function() {
  	this._log = new global.GSLog(OnCallRotationSowSNC.LOG_PROPERTY, this.type);
  	global.OnCallRotation.prototype.prepareOnCallGroupsDataGroup = OnCallRotationSowSNC.methods.prepareOnCallGroupsDataGroup.bind(this);
  	global.OnCallRotation.prototype.prepareOnCallGroupsDataRota = OnCallRotationSowSNC.methods.prepareOnCallGroupsDataRota.bind(this);
  	global.OnCallRotation.prototype.prepareOnCallGroupsDataRoster = OnCallRotationSowSNC.methods.prepareOnCallGroupsDataRoster.bind(this);
  	global.OnCallRotation.prototype.prepareOnCallGroupsDataMember = OnCallRotationSowSNC.methods.prepareOnCallGroupsDataMember.bind(this);
  	global.OnCallRotation.prototype.prepareOnCallGroupsDataUser = OnCallRotationSowSNC.methods.prepareOnCallGroupsDataUser.bind(this);
  	global.OnCallRotation.prototype._getGroupsWithRotasByName = OnCallRotationSowSNC.methods._getGroupsWithRotasByName.bind(this);
  	this._onCallRotation = new global.OnCallRotation();
  },

  _getUsers: function(userSysIds) {
  	return this._onCallRotation._getUsers(userSysIds);
  },
  
  processIndividualOCData: function (groupsData, gdt) {
  	return this._onCallRotation.processIndividualOCData(groupsData, gdt);
  },

  simulateEscalationToAllRotas: function (indicator) {
  	return this._onCallRotation.simulateEscalationToAllRotas(indicator);
  },

  getOnCallGroupData: function(dateTime, offset, groupsLimit, textSearch, excludeGroupSysIds, showOnlyActiveGroups) {
  	dateTime = dateTime || '';
  	textSearch = textSearch || '';
  	offset = offset || 0;
  	excludeGroupSysIds = excludeGroupSysIds || '';

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[getOnCallGroupData] dateTime: ' + dateTime);

  	this._recommendedGroups = (excludeGroupSysIds || '').split(',');
  	return this._onCallRotation.getOnCallGroupData(dateTime, offset, groupsLimit, textSearch, excludeGroupSysIds, showOnlyActiveGroups);
  },

  getOnCallGroupDataByGroupSysId: function(dateTime, groupSysIds) {
  	dateTime = dateTime || '';
  	groupSysIds = groupSysIds || '';

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[getOnCallGroupDataByGroupSysId] dateTime: ' + dateTime + ' groupSysIds: ' + groupSysIds);

  	this._recommendedGroups = (groupSysIds || '').split(',');
  	return this._onCallRotation.getOnCallGroupDataByGroupSysId(dateTime, groupSysIds);
  },

  /**
  * This returns the next request time in UTC factoring:
  * 1. End of current and Start next shift
  * 2. End of current and Start next cover record
  * 3. End of current and Start next Time Off record
  * 4. End of current and Start next Extra Time record
  */
  _getNextRequestDateTimeUTC: function(rotaGr, gdt) {
  	if (!rotaGr)
  		return null;

  	gdt = gdt || new GlideDateTime();

  	var span = this.getSpanByGdt(rotaGr.getValue('schedule', gdt));
  	if (!span)
  		return null;

  	return span.getEnd() + '';
  },

  _getRosterCount: function(rotaGr) {
  	var rosterCount = 0;

  	if (!rotaGr)
  		return rosterCount;

  	var groupSysId = rotaGr.getValue('group');
  	var rotaSysId = rotaGr.getUniqueValue();
  	var ga = new GlideAggregate('cmn_rota_roster');
  	ga.addAggregate('COUNT');
  	ga.addQuery('rota', rotaSysId);
  	ga.addQuery('active', true);
  	ga.query();

  	rosterCount = parseInt(ga.next() ? ga.getAggregate('COUNT') : 0);

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_getRosterCount] rosterCount: ' + rosterCount);

  	return rosterCount;
  },

  /**
  * This returns rota details message used by UIB/WEP oncall macroponent
  * example is: 2 members on-call from 8:00 AM yesterday to 5:00 PM today
  */
  _getRotaDetailsMsg: function(dateTime) {
  	var msg = '';

  	if (!dateTime || !dateTime.start || !dateTime.end)
  		return msg;

  	var start = dateTime.start;
  	var end = dateTime.end;

  	msg = gs.getMessage('From {0} to {1}', [start, end]);

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_getRotaDetailsMsg] msg: ' + msg);

  	return msg;
  },

  getDaysDifference: function(startDateTime, endDateTime) {
  	var start = new GlideDate();
  	
  	start.setValue(startDateTime.getLocalDate());
  	var end = new GlideDate();
  	end.setValue(endDateTime.getLocalDate());

  	var diff = GlideDate.subtract(start, end);
  	return diff.getRoundedDayPart();
  },
  _getRotaHumanizedDetailsMsg: function(dateTime) {
  	var msg = '';

  	if (!dateTime || !dateTime.start || !dateTime.end)
  		return msg;

  	var start = dateTime.start;
  	var end = dateTime.end;

  	var gdt = new GlideDateTime();
  	gdt.setDisplayValue(start);
  	var startGdt = new GlideDateTime(gdt);
  	gdt.setDisplayValue(end);
  	var endGdt = new GlideDateTime(gdt);
  	endGdt.addSeconds(-1);

  	var dayDiff = 0;
  	msg = gs.getMessage('From {0} to {1}', [startGdt.getDisplayValue(), endGdt.getDisplayValue()]);
  	
  	var nowGdt = new GlideDateTime();
  	var startEndDaysDiff = this.getDaysDifference(startGdt, endGdt);

  	var startDayDiff = this.getDaysDifference(nowGdt, startGdt);
  	var endDayDiff = this.getDaysDifference(nowGdt, endGdt);
  	if (startEndDaysDiff === 0) {
  		if (endDayDiff === 0) {
  			msg = gs.getMessage('From {0} to {1} today', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  		}
  		else if (endDayDiff === -1) {
  			msg = gs.getMessage('From {0} to {1} yesterday', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  		}
  		else if (endDayDiff === 1) {
  			msg = gs.getMessage('From {0} to {1} tomorrow', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  		}
  	} else {
  		if (startDayDiff === 0) {
  			if (endDayDiff === 1) {
  				msg = gs.getMessage('From {0} today to {1} tomorrow', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  			} else {
  				msg = gs.getMessage('From {0} today to {1}', [startGdt.getTime().getDisplayValue(), endGdt.getDisplayValue()]);
  			}
  		}
  		else if (startDayDiff === -1) {
  			if (endDayDiff === 0) {
  				msg = gs.getMessage('From {0} yesterday to {1} today', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  			}
  			else if (endDayDiff === 1) {
  				msg = gs.getMessage('From {0} yesterday to {1} tomorrow', [startGdt.getTime().getDisplayValue(), endGdt.getTime().getDisplayValue()]);
  			}  else {
  				msg = gs.getMessage('From {0} yesterday to {1}', [startGdt.getTime().getDisplayValue(), endGdt.getDisplayValue()]);
  			}
  		}
  		else if (startDayDiff === 1) {
  			msg = gs.getMessage('From {0} tomorrow to {1}', [startGdt.getTime().getDisplayValue(), endGdt.getDisplayValue()]);
  		}
  	}

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_getRotaHumanizedDetailsMsg] msg: ' + msg);

  	return msg;
  },

  _getLocation: function(userSysId) {
  	if (!userSysId)
  		return;

  	var userGr = new GlideRecord('sys_user');
  	if (!userGr.get(userSysId))
  		return;

  	var locationGr = userGr.location.getRefRecord();
  	if (locationGr && locationGr.canRead())
  		return {
  			city: {
  				display_value: locationGr.getDisplayValue("city")
  			}
  		};
  },

  contains: function (arr, obj) {
  	var i = arr.length;
  	while (i--)
  		if (arr[i] === obj)
  			return true;
  	return false;
  },

  getSpanByGdt: global.OnCallRotationSNC._getSpanByGdt,

  getRotaTime: global.OnCallRotationSNC._getRotaTime,

  type: 'OnCallRotationSowSNC'
};

OnCallRotationSowSNC.methods = {

  prepareOnCallGroupsDataGroup: function(groupGr, group) {
  	if (!group)
  		return;

  	group.isRecommended = this.contains(this._recommendedGroups, group.sys_id);
  	return group;
  },

  prepareOnCallGroupsDataRota: function(rotaGr, rota) {
  	if (!rota)
  		return null;

  	var rotaTime = this.getRotaTime(rotaGr.getValue('schedule'));
  	var rosterCount = this._getRosterCount(rotaGr);
  	var membersMsg = '';
  	if (rosterCount < 1)
  		membersMsg = gs.getMessage('No members currently available');
  	else if (rosterCount === 1)
  		membersMsg = gs.getMessage('{0} member on-call', [rosterCount + '']);
  	else
  		membersMsg = gs.getMessage('{0} members on-call', [rosterCount + '']);

  	rota.details = {
  		"members": membersMsg,
  		"default": this._getRotaDetailsMsg(rotaTime),
  		"humanized": this._getRotaHumanizedDetailsMsg(rotaTime)
  	};
  	rota.nextRequestDateTimeUTC = this._getNextRequestDateTimeUTC(rotaGr);
  	return rota;
  },

  prepareOnCallGroupsDataRoster: function(rosterGr, roster) {
  	if (!roster)
  		return;

  	return roster;
  },

  prepareOnCallGroupsDataMember: function(memberGr, member) {
  	if (!member)
  		return;

  	return member;
  },

  prepareOnCallGroupsDataUser: function(glideUser, user) {
  	if (!user || !user.sys_id)
  		return;

  	var location = this._getLocation(user.sys_id + "");
  	user.city = location && location.city ? location.city.display_value : '';
  	return user;
  },
  
  _getGroupsWithRotasByName: function(textSearch) {
  	var gr = new GlideRecord('cmn_rota');
  	var encodedQuery = 'active=true^group.active=true^ORDERBYgroup.name';
  	if (textSearch)
  		encodedQuery += '^group.nameLIKE' + textSearch;

  	gr.addEncodedQuery(encodedQuery);
  	gr.query();
  	
  	var groupKeys = {};
  	while (gr.next()) {
  		groupKeys[gr.group.getRefRecord().getUniqueValue()] = true;
  	}

  	
  	
  	return Object.keys(groupKeys);
  }
};

Sys ID

a962c877535630100999ddeeff7b12a2

Offical Documentation

Official Docs: