Name
global.AWADiagnosticUtils
Description
Utility class for AWA related diagnostic content
Script
var AWADiagnosticUtils = Class.create();
AWADiagnosticUtils.prototype = {
initialize: function() {},
allWarnings: [],
snVersions: ["aspen", "berlin", "calgary", "dublin", "eureka", "fuji", "geneva", "helsinki", "istanbul", "jakarta",
"kingston", "london", "madrid", "newyork", "orlando", "paris", "quebec", "rome", "sandiego", "tokyo"
],
getVersion: function() {
var prop = gs.getProperty('glide.buildtag');
var underScoreSplit = prop.split("__");
var splited = underScoreSplit[0].split("-");
var version = splited[1];
var patch = '';
return [version, patch];
},
availablePresenceStates: function() {
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.setWorkflow(false);
scGr.query();
var channelNames = [];
var warnings = [];
while (scGr.next()) {
var psGr = new GlideRecord('awa_presence_state');
psGr.addQuery('available_to_receive_work_items', true);
psGr.addQuery('service_channels', 'CONTAINS', scGr.sys_id);
psGr.addActiveQuery();
psGr.setWorkflow(false);
psGr.query();
if (psGr.getRowCount() == 0) {
channelNames.push(scGr.getDisplayValue());
warnings.push(scGr.getDisplayValue() + " has no available presence state");
}
}
if (channelNames.length > 0) {
this.allWarnings.push([gs.getMessage("Service Channels without any available presence state {0}", JSON.stringify(warnings))]);
return false;
} else {
return true;
}
},
adminIsActive: function() {
var userGr = new GlideRecord("sys_user");
userGr.addQuery("sys_id", "6816f79cc0a8016401c5a33be04be441");
userGr.setWorkflow(false);
userGr.query();
if (userGr.next() && userGr.getValue("active") === "1") {
return true;
}
this.allWarnings.push([gs.getMessage("admin user is not active")]);
return false;
},
adminUserHasAdminRole: function() {
var roleGr = new GlideRecord('sys_user_has_role');
roleGr.addQuery("user", "6816f79cc0a8016401c5a33be04be441");
roleGr.addQuery("role", "2831a114c611228501d4ea6c309d626d");
roleGr.addActiveQuery();
roleGr.setWorkflow(false);
roleGr.query();
if (!roleGr.hasNext()) {
this.allWarnings.push([gs.getMessage("admin user does not have admin role. Please remove Run as Admin for any scheduled jobs.")]);
return false;
}
return true;
},
guestUserAccount: function() {
var guestGr = new GlideRecord('sys_user');
guestGr.addQuery("sys_id", "5136503cc611227c0183e96598c4f706");
guestGr.setWorkflow(false);
guestGr.query();
if (guestGr.next()) {
if (guestGr.getValue('active') == "1") {
return true;
}
}
this.allWarnings.push([gs.getMessage("guest user not found")]);
return false;
},
respondersCheck: function() {
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.setWorkflow(false);
scGr.query();
var channelNames = [];
var result = true;
while (scGr.next()) {
if (!this.checkResponderForServiceChannel(scGr, 'awa-eligibility-responder', scGr.getValue('workitem_table')))
result = false;
if (!this.checkResponderForServiceChannel(scGr, 'awa-workload-responder', scGr.getValue('workitem_table')))
result = false;
if (!this.checkResponderForServiceChannel(scGr, 'awa-workload-responder', 'awa_work_item'))
result = false;
}
return result;
},
checkResponderForServiceChannel: function(scGr, rName, tableName) {
var rGr = new GlideRecord('sys_rw_action');
rGr.addActiveQuery();
rGr.addQuery('context', 'CONTAINS', "\"sys_id\":\"" + scGr.sys_id + "\"");
rGr.addQuery('table', tableName);
rGr.addQuery('action_prefix', rName);
rGr.setWorkflow(false);
rGr.query();
if (rGr.getRowCount() == 0) {
this.allWarnings.push([gs.getMessage('There is no active {0} ({1}) for the {2} service channel.', [rName, tableName, scGr.getDisplayValue()])]);
return false;
} else if (rGr.getRowCount() > 1) {
this.allWarnings.push([gs.getMessage('There is more than one active {0} ({1}) for the {2} service channel.', [rName, tableName, scGr.getDisplayValue()])]);
return false;
}
if (tableName != 'awa_work_item' && rGr.next()) {
var condition = rGr.getValue('encoded_query');
var scCondition = scGr.getValue('condition');
if (scCondition == null) scCondition = "";
if (scCondition.includes("^OR")) {
this.allWarnings.push([gs.getMessage("Service channel condition includes OR condition")]);
return false;
}
var scConditions = scCondition.substring(0, scCondition.length - 3).split('^NQ');
var utilizationCondition = scGr.getValue('utilization_condition');
if (utilizationCondition == null) utilizationCondition = "";
if (utilizationCondition.includes("^OR")) {
this.allWarnings.push([gs.getMessage("Service channel utilization condition includes OR condition")]);
return false;
}
var utilizationConditions = utilizationCondition.substring(0, utilizationCondition.length - 3).split('^NQ');
for (var i = 0; i < scConditions.length; i++) {
for (var j = 0; j < utilizationConditions.length; j++) {
var combinedCondition = scConditions[i] + '^' + utilizationConditions[j];
if (condition.indexOf(combinedCondition) < 0) {
this.allWarnings.push([gs.getMessage('Service channel conditions are not matched in the {0} for the {1} service channel. Please refer to CS5955451 for workaround', rName, scGr.getDisplayValue())]);
return false;
}
}
}
}
return true;
},
awaEligibilityPoolsHaveAssignmentRules: function() {
var poolGr = new GlideRecord('awa_eligibility_pool');
poolGr.addNullQuery("agent_assignment_rule");
poolGr.setWorkflow(false);
poolGr.query();
var result = true;
if (poolGr.getRowCount() > 0) {
result = false;
}
if (!result) {
allWarnings.push([gs.getMessage("Some awa_eligibility_pool have empty agent_assignment_rule")]);
}
return result;
},
queuesAssignmentEligibility: function() {
var poolGr = new GlideRecord('awa_eligibility_pool');
poolGr.setWorkflow(false);
poolGr.addNotNullQuery("queue");
poolGr.query();
var poolQueues = [];
var result = true;
var queuesWithGroups = [];
while (poolGr.next()) {
if (poolQueues.indexOf(poolGr.getValue("queue")) < 0) {
poolQueues.push(poolGr.getValue("queue"));
}
if (poolGr.getValue("groups") != null && queuesWithGroups.indexOf(poolGr.getValue("queue")) < 0) {
queuesWithGroups.push(poolGr.getValue("queue"));
}
}
var queueGr = new GlideRecord('awa_queue');
queueGr.setWorkflow(false);
queueGr.addActiveQuery();
queueGr.query();
while (queueGr.next()) {
if (poolQueues.indexOf(queueGr.getValue("sys_id")) < 0) {
this.allWarnings.push([gs.getMessage("Queue '{0}'({1}) has no awa_eligibility_pool record", [queueGr.getValue("sys_name"), queueGr.getValue("number")])]);
result = false;
} else if (queuesWithGroups.indexOf(queueGr.getValue("sys_id")) < 0) {
this.allWarnings.push([gs.getMessage("Queue '{0}'({1}) has no group", [queueGr.getValue("sys_name"), queueGr.getValue("number")])]);
result = false;
}
}
return result;
},
duplicateClusterNodes: function() {
var nodeGr = new GlideRecord("sys_cluster_state");
nodeGr.setWorkflow(false);
nodeGr.addQuery("status", "online");
nodeGr.query();
var nodeIds = [];
var result = true;
var duplicates = [];
var warnings = [];
while (nodeGr.next()) {
if (nodeIds.indexOf(nodeGr.getValue("node_id")) < 0) {
nodeIds.push(nodeGr.getValue("node_id"));
} else {
result = false;
duplicates.push(nodeGr.getValue("node_id"));
this.allWarnings.push([gs.getMessage("Node {0} has duplicate records. Please work with SRE team to clean up this table", nodeGr.getValue("node_id"))]);
}
}
return result;
},
quebecUDM: function() {
var versionInfo = this.getVersion();
if (this.snVersions.indexOf(versionInfo[0]) < this.snVersions.indexOf("quebec") && this.snVersions.indexOf(versionInfo[0]) != -1) {
return true;
}
var propGr = new GlideRecord("sys_properties");
propGr.addQuery("name", "com.glide.chat.api_version");
propGr.setWorkflow(false);
propGr.query();
var result = true;
if (propGr.next()) {
result = propGr.getValue("value") === '2.0.0';
}
if (!result) {
allWarnings.push([gs.getMessage("UDM is not enabled. All customers post-rome should be in UDM.")]);
}
return result;
},
queueSchedulesAreGlobal: function() {
var result = true;
var qGr = new GlideRecord('awa_queue');
qGr.addActiveQuery();
qGr.setWorkflow(false);
qGr.query();
while (qGr.next()) {
var sId = qGr.getValue('schedule');
if (gs.nil(sId)) {
continue;
}
var sGr = new GlideRecord('cmn_schedule');
if (!sGr.get(sId)) {
this.allWarnings.push([gs.getMessage('Queue {0} has an invalid schedule reference.', qGr.getDisplayValue())]);
result = false;
}
if ("global" != sGr.getValue('sys_scope')) {
this.allWarnings.push([gs.getMessage('Queue {0} has a schedule in a non-global scope.', qGr.getDisplayValue())]);
result = false;
}
var schedule = new GlideSchedule(sId);
if (!schedule.isValid()) {
this.allWarnings.push([gs.getMessage('Queue {0} has an empty or invalid schedule.', qGr.getDisplayValue())]);
result = false;
}
}
return result;
},
viewCheck: function() {
var result = true;
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.setWorkflow(false);
scGr.query();
var channelNames = [];
while (scGr.next()) {
var vGr = new GlideRecord('sys_db_view');
vGr.addQuery('name', "u_awa_" + scGr.sys_id + "_work_item");
vGr.setWorkflow(false);
vGr.query();
if (vGr.getRowCount() == 0) {
this.allWarnings.push([gs.getMessage('There is no database view for the {0} service channel.', scGr.getDisplayValue())]);
result = false;
continue;
}
vGr.next();
var vtGr = new GlideRecord("sys_db_view_table");
vtGr.addQuery('view', vGr.sys_id);
vtGr.orderByDesc('order');
vtGr.setWorkflow(false);
vtGr.query();
if (vtGr.getRowCount() != 3) {
this.allWarnings.push([gs.getMessage('There are the wrong number of tables ({0}) in the {1} database view.', [vtGr.getRowCount(), vGr.getDisplayValue()])]);
result = false;
continue;
}
vtGr.next();
if (vtGr.getValue('table') != scGr.getValue('workitem_table')) {
this.allWarnings.push([gs.getMessage('Work item table is incorrect in the {0} database view ({1} != {2}))', [vGr.getDisplayValue(), vtGr.getValue('table'), scGr.getValue('workitem_table')])]);
result = false;
}
}
return result;
},
adminDomain: function() {
var domainGr = new GlideRecord('sys_user');
domainGr.addEncodedQuery("sys_id=6816f79cc0a8016401c5a33be04be441^sys_domain!=global^sys_domainISEMPTY");
domainGr.setWorkflow(false);
domainGr.query();
var result = true;
if (domainGr.getRowCount() > 0) {
this.allWarnings.push([gs.getMessage("Admin sys_domain is not global and not empty")]);
result = false;
}
return result;
},
pluginsInstalled: function() {
var neededPlugins = ["com.glide.service-portal.agent-chat", "com.glide.awa", "com.glide.cs", "com.glide.interaction", "com.glide.quickactions", "com.glide.va.sp_widgets", "com.sn_templated_snip", "com.glide.interaction.awa"];
var plugins = [];
var result = true;
var warnings = [];
var pMgr = new GlidePluginManager();
var grPlugin = new GlideRecord('sys_plugins');
var missingPlugins = [];
grPlugin.setWorkflow(false);
grPlugin.query();
var versionInfo = this.getVersion();
if (this.snVersions.indexOf(versionInfo[0]) >= this.snVersions.indexOf("sandiego") || this.snVersions.indexOf(versionInfo[0]) < 0) {
neededPlugins.push("com.glide.sensitive_data_handling");
}
for (var i = 0; i < neededPlugins.length; i++) {
if (!GlidePluginManager.isActive(neededPlugins[i])) {
missingPlugins.push(neededPlugins[i]);
this.allWarnings.push([gs.getMessage("Missing plugin: {0}", neededPlugins[i])]);
result = false;
}
}
return result;
},
userHasSkillRecordsLarge: function() {
var largeCount = 1000;
var versionInfo = this.getVersion();
if ((this.snVersions.indexOf(versionInfo[0]) === this.snVersions.indexOf("rome") && versionInfo[1] >= 1 && versionInfo[1] <= 8) ||
(this.snVersions.indexOf(versionInfo[0]) === this.snVersions.indexOf("sandiego") && versionInfo[1] === 1)) {
var skillGr = new GlideRecord("sys_user_has_skill");
skillGr.setWorkflow(false);
skillGr.query();
if (skillGr.getRowCount() > largeCount) {
this.allWarnings.push([gs.getMessage("More than {0} sys_user_has_skill records, awa assignments may be delayed. We recommend cleaning sys_user_has_skills for any inactive users. PRB PRB1547117", largeCount)]);
return false;
}
}
return true;
},
duplicateServiceChannels: function() {
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.setWorkflow(false);
scGr.query();
var channels = [];
while (scGr.next()) {
var channel = {};
channel.condition = scGr.getValue("condition");
channel.utilizationCondition = scGr.getValue("utilization_condition");
channel.scope = scGr.getValue("sys_scope");
channel.type = scGr.getValue("type");
channel.wiTable = scGr.getValue("workitem_table");
channel.assignedTo = scGr.getValue("assign_to_field");
channel.assignmentGroupField = scGr.getValue("assignment_group_field");
channel.id = scGr.getValue("sys_id");
channel.name = scGr.getValue("name");
channels.push(channel);
}
var duplicates = [];
var result = true;
for (var c1 = 0; c1 < channels.length; c1++) {
for (var c2 = c1 + 1; c2 < channels.length; c2++) {
if (this.channelEqual(channels[c1], channels[c2])) {
duplicates.push([channels[c1].id, channels[c2].id]);
this.allWarnings.push([gs.getMessage("Channels {0} ({1}) and {2} ({3}) may be duplicates", [channels[c1].name, channels[c1].id, channels[c2].name, channels[c2].id])]);
result = false;
}
}
}
return result;
},
channelEqual: function(channel1, channel2) {
return channel1.condition === channel2.condition &&
channel1.utilizationCondition === channel2.utilizationCondition &&
channel1.scope === channel2.scope &&
channel1.type === channel2.type &&
channel1.wiTable === channel2.wiTable &&
channel1.assignedTo === channel2.assignedTo &&
channel1.assignmentGroupField === channel2.assignmentGroupField;
},
chatSetupFulfillers: function() {
var setupGr = new GlideRecord("sys_cs_live_agent_setup");
setupGr.addActiveQuery();
setupGr.setWorkflow(false);
setupGr.query();
var result = true;
while (setupGr.next()) {
var name = setupGr.getValue("sys_name");
if (setupGr.getValue("csm_fulfiller") != "service_workspace") {
result = false;
this.allWarnings.push([gs.getMessage("Chat setup {0} csm_fulfiller is not service_workspace", name)]);
}
if (setupGr.getValue("global_fulfiller") != "service_workspace") {
result = false;
this.allWarnings.push([gs.getMessage("Chat setup {0} global_fulfiller is not service_workspace", name)]);
}
if (setupGr.getValue("hr_fulfiller") != "service_workspace") {
result = false;
this.allWarnings.push([gs.getMessage("Chat setup {0} hr_fulfiller is not service_workspace", name)]);
}
if (setupGr.getValue("itsm_fulfiller") != "service_workspace") {
result = false;
this.allWarnings.push([gs.getMessage("Chat setup {0} itsm_fulfiller is not service_workspace", name)]);
}
}
return result;
},
agentRwResponder: function() {
var presenceGr = new GlideRecord("awa_agent_presence");
presenceGr.addEncodedQuery("current_presence_state.available_to_receive_work_items=true");
presenceGr.setWorkflow(false);
presenceGr.query();
var result = true;
while (presenceGr.next()) {
var agentId = presenceGr.getValue("agent");
var responderGr = new GlideRecord("sys_rw_action");
responderGr.addEncodedQuery("action_prefix=awa.work_item^encoded_querySTARTSWITHassigned_to=" + agentId);
responderGr.setWorkflow(false);
responderGr.query();
if (!responderGr.hasNext()) {
this.allWarnings.push([gs.getMessage("Agent missing rw: ", agentId)]);
result = false;
}
}
return result;
},
checkServiceChannel: function() {
var gr = new GlideRecord("awa_service_channel");
gr.addActiveQuery();
gr.query();
return gr.getRowCount() != 0 ? "true" : "false";
},
checkActiveQueues: function() {
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.query();
var channelNames = [];
while (scGr.next()) {
var qGr = new GlideRecord('awa_queue');
qGr.addQuery('service_channel', scGr.sys_id);
qGr.addActiveQuery();
qGr.query();
if (qGr.getRowCount() == 0) {
channelNames.push(scGr.getDisplayValue());
}
}
return !(channelNames.length > 0) ? "true" : "false";
},
checkInboxLayout: function() {
var scGr = new GlideRecord('awa_service_channel');
scGr.addActiveQuery();
scGr.query();
var numberOfServiceChannels = scGr.getRowCount();
var channels = [];
while (scGr.next()) {
var ilGr = new GlideRecord('awa_inbox_layout');
ilGr.addQuery('service_channel', scGr.sys_id);
ilGr.addQuery('is_default', true);
ilGr.query();
if (ilGr.getRowCount() == 1) channels.push(scGr.getDisplayValue());
}
return channels.length == numberOfServiceChannels ? "true" : "false";
},
checkQueuePriorityRecord: function() {
var qGr = new GlideRecord('awa_queue');
qGr.addActiveQuery();
qGr.query();
var answer = true;
while (qGr.next()) {
var epGr = new GlideRecord('awa_eligibility_pool');
epGr.addQuery('queue', qGr.sys_id);
epGr.orderBy('eligibility');
epGr.query();
while (epGr.next()) {
var groups = epGr.getValue('groups').split(',');
for (var i = 0; i < groups.length; i++) {
var gqpGr = new GlideRecord('awa_group_queue_priority');
gqpGr.addQuery('queue', qGr.sys_id);
gqpGr.addQuery('group', groups[i]);
gqpGr.query();
if (!gqpGr.hasNext()) {
answer = false;
break;
}
}
}
}
return answer ? "true" : "false";
},
runTests: function() {
var status = [];
status.push([gs.getMessage('Is atleast one active queue exist?'), this.checkActiveQueues()]);
status.push([gs.getMessage('Is inbox layout exist for all active service channels?'), this.checkInboxLayout()]);
status.push([gs.getMessage('Is atleast one active Service Channel exist?'), this.checkServiceChannel()]);
status.push([gs.getMessage('Is Queue priority record exist?'), this.checkQueuePriorityRecord()]);
status.push([gs.getMessage('Is all required plugin installed?'), this.pluginsInstalled() ? "true" : "false"]);
status.push([gs.getMessage('Availabe Presence State configured for all Service Channel?'), this.availablePresenceStates() ? "true" : "false"]);
status.push([gs.getMessage('Is all required responder created for service channels?'), this.respondersCheck() ? "true" : "false"]);
status.push([gs.getMessage('Is admin user has admin role?'), this.adminUserHasAdminRole() ? "true" : "false"]);
status.push([gs.getMessage('Is guest user exist?'), this.guestUserAccount() ? "true" : "false"]);
status.push([gs.getMessage('Is UDM enabled?'), this.quebecUDM() ? "true" : "false"]);
status.push([gs.getMessage('Is queue schedule check passed?'), this.queueSchedulesAreGlobal() ? "true" : "false"]);
status.push([gs.getMessage('Is DB view created for service channel?'), this.viewCheck() ? "true" : "false"]);
status.push([gs.getMessage('Is Admin sys_domain is either global or empty?'), this.adminDomain() ? "true" : "false"]);
status.push([gs.getMessage('Is all eligibility pools have assignment rule configured?'), this.awaEligibilityPoolsHaveAssignmentRules() ? "true" : "false"]);
status.push([gs.getMessage('Is any duplicate cluster node check passed?'), this.duplicateClusterNodes() ? "true" : "false"]);
status.push([gs.getMessage('Is user skill related check passed?'), this.userHasSkillRecordsLarge() ? "true" : "false"]);
status.push([gs.getMessage('Is unique service channel check passed?'), this.duplicateServiceChannels() ? "true" : "false"]);
status.push([gs.getMessage('Is Setup fulfiller configuration is correct?'), this.chatSetupFulfillers() ? "true" : "false"]);
status.push([gs.getMessage('Is admin user is active?'), this.adminIsActive() ? "true" : "false"]);
status.push([gs.getMessage('Are all queues properly configured?'), this.queuesAssignmentEligibility() ? "true" : "false"]);
var output = {};
output.status = status;
output.allWarnings = this.allWarnings;
return output;
},
queryQueueCondition: function(documentTable, documentNumber) {
var output = {};
//get document gr
var documentGr = new GlideRecord(documentTable);
documentGr.addQuery('number', documentNumber);
documentGr.query();
documentGr.next();
//get service channels matching documentTable
var serviceChannels = [];
var channelGr = new GlideRecord("awa_service_channel");
channelGr.addQuery('workitem_table', documentTable);
channelGr.addQuery('active', true);
channelGr.query();
while (channelGr.next()) {
serviceChannels.push(channelGr.getValue('sys_id'));
}
//get queues matching service channels to queues array
var queueGr = new GlideRecord("awa_queue");
queueGr.addQuery('service_channel', serviceChannels);
queueGr.addQuery('active', true);
queueGr.query();
var queues = [];
//create a list of objects of queue. Each object stores information of sys_id, condition and name of the queue
while (queueGr.next()) {
var obj = {};
obj.sys_id = queueGr.getValue('sys_id');
obj.condition = queueGr.getValue('condition');
obj.name = queueGr.getValue('name');
queues.push(obj);
}
var validQueues = [];
queues.forEach(function(q, e) {
var valid = GlideFilter.checkRecord(documentGr, q.condition);
if (valid) {
validQueues.push(q.name + " : " + q.sys_id);
}
});
output.validqs = validQueues.map(function(q) {
return [q];
});
return output;
},
getDocumentSysId: function(documentTable, documentNumber) {
var documentSysId = '';
var documentGr = new GlideRecord(documentTable);
documentGr.addQuery('number', documentNumber);
documentGr.query();
if(documentGr.next()){
documentSysId = documentGr.getValue('sys_id');
}
return documentSysId;
},
getWorkItemSysId: function(documentTable, documentSysId) {
var workItemSysId = '';
var workItemGr = new GlideRecord('awa_work_item');
workItemGr.addQuery('document_table', documentTable);
workItemGr.addQuery('document_id', documentSysId);
workItemGr.query();
if (workItemGr.next()) {
workItemSysId = workItemGr.getValue('sys_id');
}
return workItemSysId;
},
getAgentCurrentCapacity: function(agent_sys_id) {
var count1 = 0,
count2 = 0,
final_capacity = 0;
var gr = new GlideRecord('awa_service_channel');
gr.addActiveQuery();
gr.query();
while (gr.next()) {
var utilization_condition = gr.getValue('utilization_condition');
var table = gr.getValue('workitem_table');
var default_size = gr.getValue('default_size');
var tableGr = new GlideRecord(table);
tableGr.addEncodedQuery('assigned_to=' + agent_sys_id + '^' + utilization_condition);
tableGr.query();
var allRecords = tableGr.getRowCount();
count1 += (allRecords * default_size);
}
var wGr = new GlideRecord('awa_work_item');
wGr.addQuery('state', 'pending_accept');
wGr.addQuery('assigned_to', agent_sys_id);
wGr.query();
while (wGr.next()) {
var sizeGr = new GlideRecord('awa_document_size');
sizeGr.addQuery('document_id', wGr.getValue('document_id'));
sizeGr.query();
count2 += sizeGr.getValue('size');
}
final_capacity = count1 + count2;
return final_capacity;
},
type: 'AWADiagnosticUtils'
};
Sys ID
79fd3ed7c3e70110d81b6e221f40dda4