Name

global.AWAStatsUtils

Description

No description available

Script

var AWAStatsUtils = Class.create();
AWAStatsUtils.prototype = {
  initialize: function () {
  },

  getAllStats: function () {
  	var stats = {
  		agents: this.getAgents(),
  		channels: this.getChannels()
  	};

  	stats['workloadCalculation'] = sn_awa.StatsUtil.getWorkloadRecalculateProcessingTime();
  	return stats;
  },

  getAgents: function () {
      var agents = {};
      // Get agents
      var agg = new GlideAggregate('awa_agent_presence');
      agg.setWorkflow(false);
      agg.addAggregate('COUNT', 'current_presence_state');
      agg.query();
      while (agg.next() && agg.canRead()) {
          var ps = agg.current_presence_state.name;
          var stateCount = agg.getAggregate('COUNT', 'current_presence_state');
          agents[ps] = stateCount;
      }
      return agents;
  },

  getChannels: function () {
      var channels = [];
      var gr = GlideRecordSecure('awa_service_channel');
      gr.setWorkflow(false);
      gr.query();
      while (gr.next()) {
          var channel = {
              sys_id: gr.getUniqueValue(),
              name: gr.getValue('name'),
              active: gr.getValue('active') === '1',
              condition: gr.getValue('condition') || '',
              utilization_condition: gr.getValue('utilization_condition') || '',
              workitem_table: gr.getValue('workitem_table'),
          };
          channel.responders = this.getChannelResponders(gr);
          channel.responderSummary = this.getChannelResponderSummary(channel);
          channel.queryPerformance = this.getChannelQueryPerformanceMetrics(channel);
          channel.queues = this.getChannelQueues(gr);
          channel.queueSummary = this.getChannelQueueSummary(channel.queues);
          channel.agents = this.getChannelAgents(gr);
          channel.agentSummary = this.getChannelAgentSummary(channel.agents);
          channel.workItemSummary = this.getChannelWorkItemSummary(channel);
          channels.push(channel);
      }
      var self = this;
      channels.forEach(function (channel) {
          self.updateChannelWorkItemSummaryWithDuplicateInformation(channel.queues, channel.workItemSummary);
      });
      return channels;
  },

  getChannelQueryPerformanceMetrics: function (channel) {
      return {
          maxQueryTime: sn_awa.StatsUtil.getMaxQueryTimeForChannel(channel.sys_id),
          minQueryTime: sn_awa.StatsUtil.getMinQueryTimeForChannel(channel.sys_id),
          meanQueryTime: Math.round(sn_awa.StatsUtil.getMeanQueryTimeForChannel(channel.sys_id)),
          medianQueryTime: sn_awa.StatsUtil.getMedianQueryTimeForChannel(channel.sys_id),
          totalQueryCount: sn_awa.StatsUtil.getTotalQueryCountForChannel(channel.sys_id),
      };
  },

  getChannelResponderSummary: function (channel) {
      return {
          respondersExist: (channel.responders).length === 3,
          "ChannelEligibilityResponderStats": {
              entryCount: sn_awa.StatsUtil.getTotalOnEntryCountForChannelAndResponder(channel.sys_id, "ChannelEligibilityResponder"),
              exitCount: sn_awa.StatsUtil.getTotalOnExitCountForChannelAndResponder(channel.sys_id, "ChannelEligibilityResponder"),
              changeCount: sn_awa.StatsUtil.getTotalOnChangeCountForChannelAndResponder(channel.sys_id, "ChannelEligibilityResponder"),
          },
          "WorkItemResponderStats": {
              entryCount: sn_awa.StatsUtil.getTotalOnEntryCountForChannelAndResponder(channel.sys_id, "WorkItemResponder"),
              exitCount: sn_awa.StatsUtil.getTotalOnExitCountForChannelAndResponder(channel.sys_id, "WorkItemResponder"),
              changeCount: sn_awa.StatsUtil.getTotalOnChangeCountForChannelAndResponder(channel.sys_id, "WorkItemResponder"),
          },
          "WorkloadResponderStats": {
              entryCount: sn_awa.StatsUtil.getTotalOnEntryCountForChannelAndResponder(channel.sys_id, "WorkloadResponder"),
              exitCount: sn_awa.StatsUtil.getTotalOnExitCountForChannelAndResponder(channel.sys_id, "WorkloadResponder"),
              changeCount: sn_awa.StatsUtil.getTotalOnChangeCountForChannelAndResponder(channel.sys_id, "WorkloadResponder"),
          }
      };
  },

  getChannelResponders: function (channelGr) {
      var recordWatcherResponders = [];
      var gr = GlideRecordSecure('sys_rw_action');
      gr.setWorkflow(false);
      gr.addQuery('context', 'CONTAINS', channelGr.sys_id);
      gr.query();
      while (gr.next()) {
          var recordWatcherResponder = {
              sys_id: gr.getUniqueValue(),
              responder_key: gr.getValue('responder_key')
          };
          recordWatcherResponders.push(recordWatcherResponder);
      }
      return recordWatcherResponders;
  },

  getChannelAgents: function (channelGr) {
      var channelAgents = [];
      var gr = GlideRecordSecure('awa_agent_channel_availability');
      gr.addQuery('service_channel', channelGr.getUniqueValue());
      gr.setWorkflow(false);
      gr.query();
      while (gr.next()) {
          var agent = {
              sys_id: gr.getUniqueValue(),
              agent: gr.getValue('agent'),
              available: gr.getValue('available') === 1,
              presence_state: gr.getValue('presence_state')
          };
          channelAgents.push(agent);
      }
      return channelAgents;
  },

  getChannelAgentSummary: function (channelAgents) {
      var agentSummary = {};
      var agg = new GlideAggregate('awa_agent_presence');
      agg.setWorkflow(false);
      var agentIds = channelAgents.map(function (agent) { return agent.agent; });
      agg.addQuery('agent', agentIds);
      agg.addAggregate('COUNT', 'current_presence_state');
      agg.query();
      while (agg.next() && agg.canRead()) {
          var ps = agg.current_presence_state.name;
          var stateCount = agg.getAggregate('COUNT', 'current_presence_state');
          agentSummary[ps] = stateCount;
      }
      return agentSummary;
  },

  getChannelQueueSummary: function (channelQueues) {
      return {
          total: channelQueues.length,
          inSchedule: channelQueues.filter(function (queue) { return queue.queueInSchedule === true; }).length,
          outOfSchedule: channelQueues.filter(function (queue) { return queue.queueInSchedule === false; }).length,
          inactive: channelQueues.filter(function (queue) { return queue.active === false; }).length
      };
  },

  getChannelQueues: function (channelGr) {
      var queues = [];
      var gr = GlideRecordSecure('awa_queue');
      gr.setWorkflow(false);
      gr.addQuery('service_channel', channelGr.getUniqueValue());
      gr.query();
      while (gr.next()) {
          var queue = {
              sys_id: gr.getUniqueValue(),
              name: gr.getValue('name'),
              active: gr.getValue('active') === '1',
              agents: this.getQueueAgents(gr),
              queueInSchedule: this.getQueueInSchedule(gr),
              serviceChannel: channelGr.getUniqueValue(),
          };
          queue.agentSummary = this.getQueueAgentSummary(queue);
          queue.workItemSummary = this.getQueueWorkItemSummary(queue);
          queue.queuePerformanceSummary = this.getQueuePerformanceSummary(queue);
          queues.push(queue);
      }
      return queues;
  },

  getQueuePerformanceSummary: function (queue) {
      return {
          maxRoutingTime: sn_awa.StatsUtil.getMaxRoutingTimeForQueue(queue.sys_id),
          minRoutingTime: sn_awa.StatsUtil.getMinRoutingTimeForQueue(queue.sys_id),
          meanRoutingTime: Math.round(sn_awa.StatsUtil.getMeanRoutingTimeForQueue(queue.sys_id)),
          medianRoutingTime: sn_awa.StatsUtil.getMedianRoutingTimeForQueue(queue.sys_id),
          totalRoutingCount: sn_awa.StatsUtil.getTotalRoutingCountForQueue(queue.sys_id),
      };
  },

  updateChannelWorkItemSummaryWithDuplicateInformation: function (queues, workItemSummary) {
      // Get all duplicate items in the queues
      var agg = GlideAggregate('awa_work_item');
      agg.setWorkflow(false);
      agg.addQuery('queue', queues.map(function (queueObj) { return queueObj.sys_id; }));
      agg.addNullQuery('previous_work_item', null);
      agg.addNotNullQuery('document_id');
      agg.addAggregate('COUNT', '*');
      agg.groupBy('document_id');
      agg.query();

      var numberOfDuplicates = 0;
      while (agg.next() && agg.canRead()) {
          if (agg.getAggregate('COUNT', '*') > 1) { // Duplicate Found
              numberOfDuplicates++;
          }
      }
      workItemSummary.numberOfDuplicates = numberOfDuplicates;
  },

  getQueueInSchedule: function (queueGr) {
      var queueInSchedule = true;
      var scheduleId = queueGr.getValue('schedule');

      if (!scheduleId)
          return true;

      var schedule = new GlideSchedule(scheduleId);
      return schedule.isInSchedule(new GlideDateTime());
  },

  getQueueAgents: function (queueGr) {
      var queueAgents = [];
      var aepGr = GlideRecordSecure('awa_eligibility_pool');
      aepGr.setWorkflow(false);
      aepGr.addQuery('queue', queueGr.getUniqueValue());
      aepGr.query();
      while (aepGr.next()) {
          var groupId = aepGr.getValue('groups');
          var sugGr = GlideRecordSecure('sys_user_grmember');
          sugGr.setWorkflow(false);
          sugGr.addQuery('group', groupId);
          sugGr.query();
          while (sugGr.next()) {
              queueAgents.push(this.getAgentAvailabilityInfo(sugGr.getValue('user')));
          }
      }
      return queueAgents;
  },

  getAgentAvailabilityInfo: function (agentSysId) {
      var agentAvailabilityInfo = {
          'sysId': agentSysId,
          'presenceState': -1,
          'maxCapacity': -1,
          'workload': -1
      };

      var aagGr = new GlideRecordSecure('awa_agent_presence');
      aagGr.setWorkflow(false);
      aagGr.addQuery('agent', agentSysId);
      aagGr.query();

      while (aagGr.next()) {
          var apsGr = new GlideRecordSecure('awa_presence_state');
          apsGr.setWorkflow(false);
          apsGr.addQuery('sys_id', aagGr.getValue('current_presence_state'));
          apsGr.query();
          while (apsGr.next()) {
              agentAvailabilityInfo.presenceState = apsGr.getValue('name');
          }

          var aacGr = new GlideRecordSecure('awa_agent_capacity');
          aacGr.setWorkflow(false);
          aacGr.addQuery('user', agentSysId);
          aacGr.query();
          while (aacGr.next()) {
              agentAvailabilityInfo.maxCapacity = aacGr.getValue('max_capacity') || 0;
              agentAvailabilityInfo.workload = aacGr.getValue('workload') || 0;
          }
      }

      return agentAvailabilityInfo;
  },

  getQueueAgentSummary: function (queueObj) {
      var queueAgentSummary = {
          agentsAvailable: 0,
      };

      var acaGr = new GlideRecordSecure('awa_agent_channel_availability');
      acaGr.setWorkflow(false);
      acaGr.addQuery('service_channel', queueObj.serviceChannel);
      acaGr.addQuery('available', 1);
      acaGr.query();

      var agentIdsInQueue = (queueObj.agents).map(function (agentObj) { return agentObj.sysId; });
      while (acaGr.next()) {
          queueAgentSummary.agentsAvailable = agentIdsInQueue.indexOf(acaGr.getValue('agent')) !== -1 ? queueAgentSummary.agentsAvailable + 1 : queueAgentSummary.agentsAvailable;
      }

      return queueAgentSummary;
  },

  /**
   * Queries the database and returns a summary of the work pending, queued, rejected,
   * and total work items for the queue.
   * @param {Object} queue object
   */
  getQueueWorkItemSummary: function (queue) {
      var queueSysID = queue.sys_id;

      var workItemSummary = {
          numberPendingAcceptance: 0,
          numberQueued: 0,
          numberRejected: 0,
          numberOfTotalWorkItems: 0
      };

      // Count queued and pending acceptance
      var stateGA = new GlideAggregate('awa_work_item');
      stateGA.addQuery('queue', queueSysID);
      stateGA.addQuery('state', 'IN', 'pending_accept,queued');
      stateGA.addActiveQuery();
      stateGA.addAggregate('COUNT', 'state');
      stateGA.query();

      while (stateGA.next()) {
          var count = stateGA.getAggregate('COUNT', 'state');
          var state = stateGA.getValue('state');
          if (state === 'pending_accept') {
              workItemSummary.numberPendingAcceptance = parseInt(count, 10);
          } else if (state == 'queued') {
              workItemSummary.numberQueued = parseInt(count, 10);
          }
      }

      // Count rejected
      var rejectedGA = new GlideAggregate('awa_work_item');
      rejectedGA.addQuery('rejected', true);
      rejectedGA.addQuery('queue', queueSysID);
      rejectedGA.addAggregate('COUNT');
      rejectedGA.query();
      rejectedGA.next();
      workItemSummary.numberRejected = parseInt(rejectedGA.getAggregate('COUNT'), 10);

      // Count total work items for this queue
      var totalGA = new GlideAggregate('awa_work_item');
      totalGA.addAggregate('COUNT');
      totalGA.addQuery('queue', queueSysID);
      totalGA.query();
      totalGA.next();
      workItemSummary.numberOfTotalWorkItems = parseInt(totalGA.getAggregate('COUNT'), 10);

      return workItemSummary;
  },

  getChannelWorkItemSummary: function (channel) {
      var workItemSummary = {
          numberPendingAcceptance: 0,
          numberQueued: 0,
          numberOfDuplicates: 0,
          numberRejected: 0,
          numberOfTotalWorkItems: 0,
          numberOfItemsMeetingChannelConditions: 0,
          numberOfItemsMeetingUtilizationCondition: 0,
          numberOfItemsMeetingChannelAndUtilzationConditions: 0,
      };

      (channel.queues).forEach(function (queue) {
          workItemSummary.numberPendingAcceptance += queue.workItemSummary.numberPendingAcceptance;
          workItemSummary.numberQueued += queue.workItemSummary.numberQueued;
          workItemSummary.numberOfDuplicates += queue.workItemSummary.numberOfDuplicates;
          workItemSummary.numberRejected += queue.workItemSummary.numberRejected;
          workItemSummary.numberOfTotalWorkItems += queue.workItemSummary.numberOfTotalWorkItems;
      });

      // Get all records matching condition
      var aggCondition = new GlideAggregate(channel.workitem_table);
      aggCondition.addEncodedQuery(channel.condition);
      aggCondition.setWorkflow(false);
      aggCondition.addAggregate('COUNT');
      aggCondition.query();
      if (aggCondition.next() && aggCondition.canRead()) {
          workItemSummary.numberOfItemsMeetingChannelConditions = aggCondition.getAggregate('COUNT');
      }
      // Get all records matching utilization condition
      var aggUtilization = new GlideAggregate(channel.workitem_table);
      aggUtilization.addEncodedQuery(channel.utilization_condition);
      aggUtilization.setWorkflow(false);
      aggUtilization.addAggregate('COUNT');
      aggUtilization.query();
      if (aggUtilization.next() && aggUtilization.canRead()) {
          workItemSummary.numberOfItemsMeetingUtilizationCondition = aggUtilization.getAggregate('COUNT');
      }

      // Get all records matching both condition and utilization condition
      var bothConditions = new GlideAggregate(channel.workitem_table);
      bothConditions.addEncodedQuery(channel.condition);
      bothConditions.addEncodedQuery(channel.utilization_condition);
      bothConditions.setWorkflow(false);
      bothConditions.addAggregate('COUNT');
      bothConditions.query();
      if (bothConditions.next() && bothConditions.canRead()) {
          workItemSummary.numberOfItemsMeetingChannelAndUtilzationConditions = bothConditions.getAggregate('COUNT');
      }

      return workItemSummary;
  },
  type: 'AWAStatsUtils'
};

Sys ID

0c13aac253320010a0bdddeeff7b1229

Offical Documentation

Official Docs: