Name
sn_comm_management.CommunicationManagementDefaultHandlerSNC
Description
Default handler for Communication Management common tasks. This handler will be used if there is no specific script include shipped in comm_task_handler table. A handler can extend this definition.
Script
var context = this;
var CommunicationManagementDefaultHandlerSNC = Class.create();
CommunicationManagementDefaultHandlerSNC.prototype = {
initialize: function() {
this.arrayUtil = new global.ArrayUtil();
this.communicationManagementUtil = new CommunicationManagementUtil();
this.contactManagementUtilsSNC = new global.ContactManagementUtilSNC();
this.incidentUtilsSNC = new global.IncidentUtilsSNC();
this.initializeChannelMap();
var startPage = '';
var endPage = '';
if (typeof global.NotifyConferenceUtils != 'function') {
startPage = 'sn_comm_management_conference_call_participants_comm_task';
endPage = 'sn_comm_management_conference_call_end_comm_task';
} else {
startPage = 'notify_conference_dialog';
endPage = 'notify_end_conference_dialog';
}
this.CONFERENCE_PAGES.MANAGE = startPage;
this.CONFERENCE_PAGES.END = endPage;
},
TABLES: {
COMM_CHANNEL: CommunicationManagementUtil.prototype.TABLES.COMM_CHANNEL,
COMM_CHANNEL_CONFERENCE: CommunicationManagementUtil.prototype.TABLES.COMM_CHANNEL_CONFERENCE,
COMM_PLAN_DEFINITION: CommunicationManagementUtil.prototype.TABLES.COMM_PLAN_DEFINITION,
COMM_TASK_DEFINITION: CommunicationManagementUtil.prototype.TABLES.COMM_TASK_DEFINITION,
COMM_CHANNEL_DEFINITION: CommunicationManagementUtil.prototype.TABLES.COMM_CHANNEL_DEFINITION,
COMM_CONTACT_DEFINITION: 'comm_contact_definition',
COMM_TASK_HANDLER: CommunicationManagementUtil.prototype.TABLES.COMM_TASK_HANDLER,
COMM_PLAN: CommunicationManagementUtil.prototype.TABLES.COMM_PLAN,
COMM_TASK: CommunicationManagementUtil.prototype.TABLES.COMM_TASK,
CONTACT: CommunicationManagementUtil.prototype.TABLES.CONTACT
},
COLUMNS: {
COMM_PLAN_DEFINITION: 'comm_plan_definition',
COMM_TASK_DEFINITION: 'comm_task_definition',
COMM_TASK_TABLE: 'comm_task_table',
SYS_CLASS_NAME: 'sys_class_name',
SOURCE: 'source',
SYS_ID: 'sys_id',
CONDITION: 'condition',
CONDITION_BASED: 'condition_based',
TABLE: 'table',
TYPE: 'type',
DOCUMENT: 'document',
ORDER: 'order',
COMMUNICATION_FREQUENCY: 'communication_frequency',
COMM_PLAN: 'comm_plan',
STATE: 'state',
HANDLER_SI: 'handler_si',
COMM_TASK: CommunicationManagementUtil.prototype.COLUMNS.COMM_TASK,
COMM_CHANNEL_CLASSIFICATION: CommunicationManagementUtil.prototype.COLUMNS.COMM_CHANNEL_CLASSIFICATION
},
CHANNEL_CLASSIFICATIONS: CommunicationManagementUtil.prototype.CHANNEL_CLASSIFICATIONS,
CONTACT_TYPE: {
USER: 'sys_user',
GROUP: 'sys_user_group',
CONSUMER: 'csm_consumer',
RECIPIENT: 'sn_publications_recipients_list'
},
PROPERTIES: {
NOTIFY_NUMBER: 'com.snc.tcm.notify_number',
ENABLE_NOTIFY: 'com.snc.tcm.enable_notify',
ESCALATION_LEVEL: 'com.snc.tcm.on_call_escalation_level',
MAX_CONTACT_LIMIT_EMAIL: 'sn_comm_management.com.snc.tcm.max_contact_limit_email',
MAX_CONTACT_LIMIT_SMS: 'sn_comm_management.com.snc.tcm.max_contact_limit_sms',
CONFERENCE_CALL_ESCALATION_WORKFLOW: 'sn_comm_management.com.snc.tcm.conference_call_escalation_workflow',
ESCALATE_CONFERENCE: 'sn_comm_management.com.snc.tcm.conference_call_follow_on_call_escalation',
ADD_ALL_MEMBERS_ON_NO_ROTA_DEFINED: 'sn_comm_management.add_all_members_on_no_rota_defined'
},
COMMUNICATION_FREQUENCY_TYPE: {
RECURRING: 'recurring',
ONE_TIME: 'one_time'
},
COMM_TASK_STATES: {
PENDING: -5,
OPEN: 1,
WIP: 2,
COMPLETED: 3,
CANCELED: 4,
SKIPPED: 7
},
COMM_PLAN_STATES: {
NEW: 'new',
WIP: 'work_in_progress',
CLOSED: 'closed',
CANCELLED: 'cancelled'
},
COMM_TASK_ACTIONS: {
SKIP: 'skip',
SNOOZE: 'snooze',
CLOSE: 'close',
START: 'start'
},
CONFERENCE_PAGES: typeof global.NotifyConferenceUtils == 'function' ?
{
MANAGE: 'notify_conference_dialog',
END: 'notify_end_conference_dialog'
}:
{
MANAGE: 'add_to_conference',
END: 'sn_comm_management_conference_call_end_comm_task'
},
DEFAULT_TEMPLATES: {
EMAIL: '5925caa5875013000e3dd61e36cb0b43',
SMS: '064a4265871013000e3dd61e36cb0b85'
},
/*Used to initialize channel related meta data*/
initializeChannelMap: function() {
//This call is not going to populate 'channel.available' information as it is dependent on source table. Call explicitly with sourceTable if that info is needed.
this.channelMap = this.communicationManagementUtil.getChannelMap();
},
getCommTaskVariables: function(tableName) {
var commTaskVariables = {};
commTaskVariables.default_email_client_template = this.DEFAULT_TEMPLATES.EMAIL;
commTaskVariables.default_sms_template = this.DEFAULT_TEMPLATES.SMS;
commTaskVariables.default_recipient_field = this.communicationManagementUtil.getDefaultEmailRecipientField(tableName);
return commTaskVariables;
},
/*Override to set instance table of comm_plan for a Task record*/
getCommPlanInstanceForTask: function() {
return this.TABLES.COMM_PLAN;
},
/*Override to set instance table of comm_task for a Task record*/
getCommTaskInstanceForTask: function() {
return this.TABLES.COMM_TASK;
},
attachPlans: function(sourceRecordGr) {
var planDefsAlreadyAttached = [];
var planInstanceTable = this.getCommPlanInstanceForTask();
var cpmw = new global.CommunicationPlanMutexWrapper(sourceRecordGr.sys_id);
if (cpmw.getLock()) {
try {
//Piggy back on incidentUtils to use addDomainQuery
var planInstanceCheckGr = this.incidentUtilsSNC.getPlanInstanceGr(planInstanceTable, sourceRecordGr);
while (planInstanceCheckGr.next()) {
if (planDefsAlreadyAttached.indexOf(planInstanceCheckGr.getValue(this.COLUMNS.COMM_PLAN_DEFINITION)) == -1)
planDefsAlreadyAttached.push(planInstanceCheckGr.getValue(this.COLUMNS.COMM_PLAN_DEFINITION));
}
//Piggy back on incidentUtils to use addDomainQuery
var planDefGr = this.incidentUtilsSNC.getPlanDefinitionGr(sourceRecordGr, planDefsAlreadyAttached);
var planInstanceGr;
while(planDefGr.next()) {
var conditions = planDefGr.getValue(this.COLUMNS.CONDITION);
if (gs.nil(conditions) || GlideFilter.checkRecord(sourceRecordGr, conditions)) {
planInstanceGr = new GlideRecord(planInstanceTable);
planInstanceGr.newRecord();
this.peparePlanInstanceGr(planDefGr, planInstanceGr, sourceRecordGr);
this.updatePlanDetails(planDefGr, planInstanceGr, sourceRecordGr);
}
}
} finally {
cpmw.releaseLock();
}
}
else
gs.error("cannot get hold of the TCM lock for task" + sourceRecordGr.sys_id);
},
/*Override to set specific extension fields*/
peparePlanInstanceGr: function(planDefGr, planInstanceGr, sourceRecordGr) {
planInstanceGr.source = sourceRecordGr.getUniqueValue();
planInstanceGr.comm_plan_definition = planDefGr.getUniqueValue();
},
updatePlanDetails: function(planDefGr, planInstanceGr, sourceRecordGr) {
var isDirty = false;
if (planInstanceGr.sys_domain != sourceRecordGr.sys_domain) {
planInstanceGr.sys_domain = sourceRecordGr.sys_domain;
isDirty = true;
}
if (gs.nil(planInstanceGr.short_description) && !gs.nil(planDefGr.name)) {
planInstanceGr.short_description = planDefGr.name;
isDirty = true;
}
if (gs.nil(planInstanceGr.description) && !gs.nil(planDefGr.description)) {
planInstanceGr.description = planDefGr.description;
if (!isDirty)
isDirty = true;
}
if (gs.nil(planInstanceGr.comm_plan_type) && !gs.nil(planDefGr.comm_plan_type)) {
planInstanceGr.comm_plan_type = planDefGr.comm_plan_type;
if (!isDirty)
isDirty = true;
}
if (gs.nil(planInstanceGr.order) && !gs.nil(planDefGr.order)) {
planInstanceGr.order = planDefGr.order;
if (!isDirty)
isDirty = true;
}
if (planInstanceGr.isNewRecord())
planInstanceGr.insert();
else if (isDirty)
planInstanceGr.update();
},
createCommunicationTasks: function(sourceRecordGr, planInstanceGr) {
//Piggy back on incidentUtils to use addDomainQuery
var planTaskDefGr = this.incidentUtilsSNC.getTaskDefinitionGr(planInstanceGr);
while (planTaskDefGr.next())
this.createCommTaskAndChannels(planTaskDefGr, planInstanceGr, sourceRecordGr);
},
prepareFieldForCommunicationTask: function(commTaskGr) {
var requiredFields = ['number', 'sys_class_name', 'state', 'last_communication', 'order', 'short_description', 'sys_created_on', 'due_date', 'description', 'sys_id', 'reminder_frequency', 'periodicity', 'closed_at', 'active', 'communication_frequency', 'comm_count', 'assigned_to', 'due_in', 'sys_updated_on'];
return this.communicationManagementUtil.toJS(commTaskGr, requiredFields);
},
prepareFieldForCommunicationChannel: function(commChannelGr) {
var configGr = commChannelGr.comm_channel_config.getRefRecord();
var typeValue = configGr.type + '';
var channelApi = this.channelMap[typeValue].api_name;
var channelApiInstance = this.communicationManagementUtil.getScriptInstanceFromApiName(context, channelApi);
var jsonOb = channelApiInstance.getCommunicationChannelDetails(commChannelGr, configGr);
return jsonOb;
},
prepareFieldForCommunicationPlan: function(commPlanGr) {
var requiredFields = ['sys_id', 'short_description', 'number', 'sys_class_name', 'order', 'sys_created_on', 'comm_plan_type'];
return this.communicationManagementUtil.toJS(commPlanGr, requiredFields);
},
getCommunicationDetails: function(sysId, filterCriteria) {
var respData = {
comm_plan: [],
contact_types: [],
permissions: {}
};
var hasValidPhoneNumber = false;
if(GlidePluginManager.isActive('com.snc.notify')) {
var notifyUtils = null;
if(typeof global.NotifyUtil != 'undefined')
notifyUtils = new global.NotifyUtil();
else
notifyUtils = new global.NotifyUtils();
var numbers = notifyUtils.getUniquePhoneNumbersForUsersAndGroups([], [gs.getUserID()], [], notifyUtils.numberType.voice);
hasValidPhoneNumber = numbers.length > 0;
}
var commPlanGr = new GlideRecord(this.getCommPlanInstanceForTask());
commPlanGr.addQuery("source", sysId);
if(filterCriteria.sysparm_query)
commPlanGr.addEncodedQuery(filterCriteria.sysparm_query);
if(filterCriteria && filterCriteria.orderBy){
if(filterCriteria.orderType == "desc"){
commPlanGr.orderByDesc(filterCriteria.orderBy);
} else
commPlanGr.orderBy(filterCriteria.orderBy);
}
if(filterCriteria && filterCriteria.maxRows)
commPlanGr.setLimit(filterCriteria.maxRows);
commPlanGr.query();
while (commPlanGr.next()) {
var jsCommPlan = this.prepareFieldForCommunicationPlan(commPlanGr);
if (jsCommPlan) {
jsCommPlan.comm_tasks = this.getCommunicationTaskForPlan(commPlanGr, hasValidPhoneNumber);
jsCommPlan.chatRecipient = this.communicationManagementUtil.getContactsForChat(commPlanGr.sys_id, commPlanGr.getRecordClassName());
respData.comm_plan.push(jsCommPlan);
jsCommPlan.recipients = [];
var recipientsGr = this.communicationManagementUtil.getCommPlanRecipients(commPlanGr);
while(recipientsGr.next()) {
if (recipientsGr.canRead()) {
var recipientJs = this.communicationManagementUtil.toJS(recipientsGr);
recipientJs.can_manage = this.contactManagementUtilsSNC.canManageRecipient(recipientsGr);
jsCommPlan.recipients.push(recipientJs);
}
}
}
}
respData.labels = {
comm_task: this.communicationManagementUtil.getTableFieldsMap(this.getCommTaskInstanceForTask())
};
respData.states = {
comm_task: this.communicationManagementUtil.getStates(this.getCommTaskInstanceForTask(), 'state')
};
respData.contact_types = this.communicationManagementUtil.getContactTypes();
respData.permissions.manage_recipients = this.contactManagementUtilsSNC.canManageRecipients();
var canCreateTask = this.incidentUtilsSNC.canCreateRecord(this.getCommTaskInstanceForTask());
respData.permissions.add_adhoc_communication = canCreateTask && this.incidentUtilsSNC.canCreateRecord(this.getCommPlanInstanceForTask());
respData.permissions.add_adhoc_task = canCreateTask;
// conference details
respData.activeCalls = this.getConferenceOrChatData(respData);
if(GlidePluginManager.isActive('com.snc.notify')) {
var notifyInfo = {
number: gs.getProperty(this.PROPERTIES.NOTIFY_NUMBER, ''),
enabled: gs.getProperty(this.PROPERTIES.ENABLE_NOTIFY, 'false'),
capabilities: {
speaking: false
},
serviceProviderDetails: {}
};
if (typeof global.NotifyConferenceUtils == 'function') {
var confUtils = new global.NotifyConferenceUtils();
notifyInfo.serviceProviderDetails = confUtils.getServiceProviderDetails();
notifyInfo.selfJoinStatusMap = confUtils.getSelfJoinStatusMap();
}
try {
notifyInfo.capabilities.speaking = new sn_notify.NotifyScoped().hasCapability(gs.getProperty(this.PROPERTIES.NOTIFY_NUMBER, ''), 'show_speakers');
} catch (e) {
}
respData.notifyInfo = notifyInfo;
respData.userInfo = {
userID: gs.getUserID()
};
respData.conf_pages = {};
respData.conf_pages.manage = this.getConferenceManagementPageName();
respData.conf_pages.end = this.getConferenceEndPageName();
respData.automation_urls = this.getAutomationUrls();
}
return respData;
},
getAutomationUrls: function() {
if(GlidePluginManager.isActive('sn_tcm_collab_hook') && GlidePluginManager.isActive('sn_now_teams')) {
var teamsConfigProvider = new sn_tcm_collab_hook.MSTeamsChatConfigProvider();
var teamsUrl = teamsConfigProvider.getTeamsUrl();
var teamsAppUrl = teamsConfigProvider.getTeamsAppUrl();
var azureLoginUrl = teamsConfigProvider.getAzureLoginUrl();
var msGraphUrl = teamsConfigProvider.getMSGraphUrl();
return {
"teamsUrl": teamsUrl,
"teamsAppUrl": teamsAppUrl,
"azureLoginUrl": azureLoginUrl,
"msGraphUrl": msGraphUrl
};
}
return {};
},
getConferenceCallJS: function(notifyGr) {
var jsFields = ['active', 'source', 'number', 'code', 'duration', 'sys_created_on', 'sys_updated_on', 'notify_number', 'service_provider', 'state', 'service_provider_data', 'conference_title'];
result = this.communicationManagementUtil.toJS(notifyGr, jsFields);
if(result.notify_number.display_value == '')
result = this.communicationManagementUtil.getDialInNumber(notifyGr, result);
return result;
},
getConferenceCallParticipantJS: function(notifyParticipantGr) {
var jsFields = ['notify_conference_call', 'active', 'user', 'group', 'muted', 'sys_created_on', 'sys_updated_on', 'phone_number', 'speaking', 'email', 'initiator', 'service_provider_user_name', 'service_provider_data'];
return this.communicationManagementUtil.toJS(notifyParticipantGr, jsFields);
},
addRecordingUrl: function(confCallSysId) {
var obj = {};
var notifyGr = new GlideRecord('notify_recording');
notifyGr.addQuery('notify_conference_call', confCallSysId);
notifyGr.setLimit(1);
notifyGr.query();
if (notifyGr.next()) {
obj.display_value = "Recording";
obj.value = notifyGr.url + '';
}
return obj;
},
appendChatData: function(commTaskGr, channelTable) {
var data = {};
var teamsChatGr = new GlideRecord(channelTable.table);
teamsChatGr.addQuery(channelTable.source_table, commTaskGr.sys_class_name.value);
teamsChatGr.addQuery(channelTable.source, commTaskGr.sys_id.value);
teamsChatGr.setLimit(1);
teamsChatGr.query();
if (teamsChatGr.next()) {
var userGr = new GlideRecord('sys_user');
userGr.addActiveQuery();
if (userGr.get(teamsChatGr.getValue(channelTable.initiated_by))) {
data.display_value = userGr.getDisplayValue();
data.value = userGr.email.getDisplayValue();
data.sysId = userGr.getUniqueValue();
data.is_private = teamsChatGr.getValue('is_private');
}
}
return data;
},
getConferenceOrChatData: function(data) {
var confSysIds = [];
for (var i = 0; i < data.comm_plan.length; i++) {
for (var j = 0; j < data.comm_plan[i].comm_tasks.length; j++) {
var channels = data.comm_plan[i].comm_tasks[j].channels;
if(channels.length != 1)
continue;
if(channels[0].channelType.value != 'conference') {
if (channels[0].is_collaboration_chat)
channels[0].chatInitiatedBy = this.appendChatData(data.comm_plan[i].comm_tasks[j], channels[0].channelTable);
continue;
}
if(GlidePluginManager.isActive('com.snc.notify')) {
if(!channels[0].notify_conference_call.value)
continue;
channels[0].notify_recording_url = this.addRecordingUrl(channels[0].notify_conference_call.value);
confSysIds.push(channels[0].notify_conference_call.value);
}
}
}
if(GlidePluginManager.isActive('com.snc.notify')) {
var notifyGr = new GlideRecord('notify_conference_call');
notifyGr.addQuery('sys_id', 'IN', confSysIds);
notifyGr.orderByDesc('sys_created_on');
notifyGr.query();
var activeCallsInfo = {
};
var activeCallSysIds = [];
while (notifyGr.next()) {
var sysId = notifyGr.sys_id + '';
activeCallsInfo[sysId] = this.getConferenceCallJS(notifyGr);
activeCallSysIds.push(sysId);
}
var notifyParticipantGr = new GlideRecord('notify_participant');
notifyParticipantGr.addQuery('notify_conference_call', 'IN', activeCallSysIds);
notifyParticipantGr.addQuery('notify_conference_call.active', 'true');
notifyParticipantGr.query();
while (notifyParticipantGr.next()) {
var participantInfo = this.getConferenceCallParticipantJS(notifyParticipantGr);
var callInfo = activeCallsInfo[participantInfo.notify_conference_call.value];
callInfo.participants = callInfo.participants || {};
callInfo.participants[participantInfo.sys_id.value] = participantInfo;
}
return activeCallsInfo;
}
},
doConferenceMutingAction: function (confId, muteAction) {
var muted;
if (muteAction + '' == 'multiMute')
muted = false;
else if (muteAction + '' == 'multiUnmute')
muted = true;
var confParticipantGr = new GlideRecord('notify_participant');
confParticipantGr.addActiveQuery();
confParticipantGr.addQuery('notify_conference_call', confId);
confParticipantGr.addQuery('muted', muted);
confParticipantGr.query();
while (confParticipantGr.next()) {
if (confParticipantGr.user + '' == gs.getUserID())
continue;
if (muteAction + '' == 'multiMute') {
new sn_notify.NotifyScoped().mute(confParticipantGr);
} else if (muteAction + '' == 'multiUnmute') {
new sn_notify.NotifyScoped().unmute(confParticipantGr);
}
}
},
doNotifyParticipantAction: function (action, actionInfo) {
var nutils = new global.NotifyUtils();
if (action === 'self_join' || action === 'anonymous_join' || action === 'join') {
var confGr = new GlideRecord('notify_conference_call');
if (!confGr.get(actionInfo.confId))
return false;
if (actionInfo.phNum && nutils.isParticipantSessionActiveForPhoneNumber(actionInfo.phNum, confGr.getUniqueValue()))
return false;
if (actionInfo.userId && nutils.isParticipantSessionActive(actionInfo.userId, confGr.getUniqueValue()))
return false;
var taskNotify = new sn_comm_management.CommTaskNotifyAjax();
taskNotify.call(actionInfo.userId || actionInfo.phNum, confGr);
return true;
}
if (!actionInfo.sysId)
return;
var gr = new GlideRecord('notify_participant');
if (!gr.get(actionInfo.sysId))
return new sn_ws_err.BadRequestError("Notify record not found");
var isLeader = false;
var sourceTask = gr.notify_conference_call.source;
if (gr.notify_conference_call.table == this.getCommTaskInstanceForTask()) {
var commTaskGr = new GlideRecord(this.getCommTaskInstanceForTask());
if (sourceTask && commTaskGr.get(sourceTask)) {
isLeader = new sn_comm_management.CommTaskNotifyUtils().isConferenceLeader(commTaskGr);
}
}
if (!isLeader)
return new sn_ws_err.BadRequestError("User doesn't have role to do this action");
if (action == 'kick') {
if (!gr.active) {
return {
action: 'change',
changes: ['active'],
record: {
active: {
value: 'false',
display_value: 'false'
}
}
};
}
new sn_notify.NotifyScoped().kick(gr);
} else if (action == 'mute') {
if (!!gr.muted) {
//return new sn_ws_err.BadRequestError("User is already in mute state");
return {
action: 'change',
changes: ['muted'],
record: {
muted: {
value: 'true',
display_value: 'true'
}
}
};
}
new sn_notify.NotifyScoped().mute(gr);
} else if (action == 'unmute') {
if (gr.muted + '' == 'false') {
return {
action: 'change',
changes: ['muted'],
record: {
muted: {
value: 'false',
display_value: 'false'
}
}
};
}
new sn_notify.NotifyScoped().unmute(gr);
} else if (action == 'join') {
if (!!gr.active) {
return {
action: 'change',
changes: ['active'],
record: {
active: {
value: 'true',
display_value: 'true'
}
}
};
}
if (!new global.NotifyUtils().isParticipantSessionActive(gr.user + '', actionInfo.confId)) {
var taskNotify = new sn_comm_management.CommTaskNotifyAjax();
taskNotify.call(gr.user + '', gr.notify_conference_call.getRefRecord());
}
}
return {
action: action,
actionInfo: actionInfo
};
},
getCommunicationTaskForPlan: function(commPlanGr, hasValidPhoneNumber) {
var comm_task = [];
var commTaskGr = new GlideRecord(this.getCommTaskInstanceForTask());
commTaskGr.addQuery("comm_plan", commPlanGr.getUniqueValue());
commTaskGr.orderBy("order");
commTaskGr.orderByDesc('sys_created_on');
commTaskGr.query();
while (commTaskGr.next()){
var jsCommTask = this.prepareFieldForCommunicationTask(commTaskGr);
jsCommTask.channels = this.getChannelsForTask(commTaskGr);
jsCommTask.canSendUpdates = this.canSendUpdates(commTaskGr);
jsCommTask.canStart = this.canStart(commTaskGr);
jsCommTask.canSnooze = this.canSnooze(commTaskGr);
jsCommTask.canClose = this.canClose(commTaskGr);
if (GlidePluginManager.isActive('com.snc.tcm_collab_hook') && this.isVersionSupported())
jsCommTask.isCollabLeader = this.isCollaborateLeader(commTaskGr);
if (GlidePluginManager.isActive('com.snc.notify')) {
jsCommTask.isLeader = new sn_comm_management.CommTaskNotifyUtils().isConferenceLeader(commTaskGr);
jsCommTask.hasValidPhoneNumber = hasValidPhoneNumber;
}
jsCommTask.canViewCollaborationActions = this.canViewCollaborationActions();
comm_task.push(jsCommTask);
}
return comm_task;
},
isVersionSupported: function() {
if (sn_tcm_collab_hook.CollaborationUtils) {
if (new sn_tcm_collab_hook.CollaborationUtils().getVersion() >= 2)
return true;
}
return false;
},
isCollaborateLeader: function(gr) {
var userId = gs.getUserID();
var gUser = new global.IncidentUtils().getUserByIdObj(userId);
if (gr.getRecordClassName() == 'incident_alert_task') {
if (gr.active && gUser.hasRole('itil,sn_incident_write') && (gr.assigned_to == userId || gr.incident_alert.assigned_to == userId))
return true;
}
return !!(gr.active && (gUser.hasRole('sn_comm_management.comm_plan_manager') || gUser.hasRole('sn_comm_management.comm_plan_admin')));
},
canViewCollaborationActions: function() {
if (gs.getUser().hasRole('sn_comm_management.comm_plan_manager'))
return true;
return false;
},
canSendUpdates: function(commTaskGR) {
var channelGR = new GlideRecord(this.TABLES.COMM_CHANNEL);
channelGR.addQuery(this.COLUMNS.COMM_TASK, commTaskGR.sys_id);
channelGR.addQuery(this.COLUMNS.COMM_CHANNEL_CLASSIFICATION, this.CHANNEL_CLASSIFICATIONS.UPDATE);
channelGR.query();
return (channelGR.hasNext() && commTaskGR.active == true && commTaskGR.state.canWrite());
},
canStart: function(commTaskGr) {
return commTaskGr.state == this.COMM_TASK_STATES.PENDING && commTaskGr.state.canWrite();
},
canSnooze: function(commTaskGr) {
return commTaskGr.state != this.COMM_TASK_STATES.PENDING && commTaskGr.communication_frequency == this.COMMUNICATION_FREQUENCY_TYPE.RECURRING && commTaskGr.state.canWrite();
},
canClose: function(commTaskGr) {
return commTaskGr.state != this.COMM_TASK_STATES.PENDING && commTaskGr.state.canWrite();
},
getCommTaskStates: function() {
return this.COMM_TASK_STATES;
},
getChannelsForTask: function(commTaskGr) {
var channels = [];
var channelMap = this.channelMap;
for (var channel in channelMap) {
var table = channelMap[channel].inst_table;
var commChannelGr = new GlideRecord(table);
commChannelGr.addQuery(this.COLUMNS.COMM_TASK, commTaskGr.getUniqueValue());
commChannelGr.query();
while(commChannelGr.next()){
channels.push(this.prepareFieldForCommunicationChannel(commChannelGr));
}
}
return channels;
},
getChannels: function(planTaskDef, planTaskGr, sourceRecordGr) {
if (!planTaskDef)
return;
var defChannels = [];
var channelMap = this.channelMap;
for (var channel in channelMap) {
var channelDefGr = this.incidentUtilsSNC.getChannelDefintionGr(channelMap[channel].def_table, planTaskDef, planTaskGr, channel);
if (!channelDefGr)
continue;
while (channelDefGr.next())
defChannels.push({channelMetaObj: channelMap[channel], channelDefGr: channelDefGr});
}
return defChannels;
},
updateTaskStateWBActions: function(commTaskSysId, action) {
/*Override to implement task state management from WorkBench - See CommunicationManagementIncidentHandlerSNC for implementation for Major Incident Management WB*/
},
createCommTaskAndChannels: function(planTaskDefGr, planInstanceGr, sourceRecordGr) {
var planTaskGr = new GlideRecord(this.getCommTaskInstanceForTask());
planTaskGr.newRecord();
this.prepareTaskInstanceGr(planTaskGr, planTaskDefGr, planInstanceGr);
planTaskGr.insert();
var taskChannels = this.getChannels(planTaskDefGr.getUniqueValue(), planTaskGr, sourceRecordGr);
for (var j = 0; j < taskChannels.length; j++) {
this.createChannelInstance(taskChannels[j].channelMetaObj, planTaskGr, taskChannels[j].channelDefGr);
}
},
/*Override to set specific extension fields*/
prepareTaskInstanceGr: function(planTaskGr, planTaskDefGr, planInstanceGr) {
planTaskGr.comm_task_definition = planTaskDefGr.getUniqueValue();
planTaskGr.comm_plan = planInstanceGr.getUniqueValue();
planTaskGr.sys_domain = planInstanceGr.sys_domain;
planTaskGr.order = planTaskDefGr.order;
planTaskGr.short_description = planTaskDefGr.name;
planTaskGr.description = planTaskDefGr.description;
planTaskGr.comm_task_type = planTaskDefGr.comm_task_type;
planTaskGr.communication_frequency = planTaskDefGr.communication_frequency;
planTaskGr.due_in = planTaskDefGr.due_in;
},
createChannelInstance: function(channelObj, planTaskGr, channelDefGr) {
var channelInstance = new GlideRecord(channelObj.inst_table);
if (!channelInstance.isValid())
return;
channelInstance.initialize();
channelInstance.comm_task = planTaskGr.getUniqueValue();
channelInstance.sys_domain = planTaskGr.sys_domain;
channelInstance.comm_channel_definition = channelDefGr.getUniqueValue();
channelInstance.notify_group_selector = channelDefGr.notify_group_selector + '';
var channelApi = channelObj.api_name;
var channelApiInstance = this.communicationManagementUtil.getScriptInstanceFromApiName(context, channelApi);
var commTaskVariables = this.getCommTaskVariables(planTaskGr.comm_plan.source.getRefRecord().getRecordClassName());
channelApiInstance.updateChannelFromDef(channelInstance, channelDefGr, planTaskGr, commTaskVariables);
channelInstance.insert();
},
createContactsFromContactDefinition: function(planGr) {
if (planGr.comm_plan_definition) {
var existingContact = this.contactManagementUtilsSNC.getExistingContacts(planGr);
//Piggy back on incidentUtils to use addDomainQuery
var contactDef = this.incidentUtilsSNC.getContactDefinitionGr(planGr);
while (contactDef.next()) {
var contacts = new GlideRecord(this.TABLES.CONTACT);
contacts.initialize();
contacts.table = planGr.getRecordClassName();
contacts.document = planGr.sys_id;
contacts.responsibility = contactDef.contact_responsibility;
contacts.type = contactDef.type;
contacts.sys_domain = planGr.sys_domain;
contacts.classification = this.TABLES.COMM_CONTACT_DEFINITION;
var options = contacts.type + '';
switch (options) {
case this.CONTACT_TYPE.USER:
if (!this.arrayUtil.contains(existingContact, contactDef.sys_user)) {
contacts.user = contactDef.sys_user;
contacts.insert();
}
break;
case this.CONTACT_TYPE.GROUP:
if (!this.arrayUtil.contains(existingContact, contactDef.sys_user_group)) {
contacts.group = contactDef.sys_user_group;
contacts.insert();
}
break;
case this.CONTACT_TYPE.CONSUMER:
if (!this.arrayUtil.contains(existingContact, contactDef.csm_consumer)) {
contacts.consumer = contactDef.csm_consumer;
contacts.insert();
}
break;
case this.CONTACT_TYPE.RECIPIENT:
if (!this.arrayUtil.contains(existingContact, contactDef.recipients_list)) {
contacts.recipient_list = contactDef.recipients_list;
contacts.insert();
}
break;
default:
gs.log("Not a valid contact Type");
}
}
}
},
//Defines rules of when a add channel action can show up on commTask
allowAddChannelOnCommTask: function(commTaskGr, ignoreACL, instanceTable) {
if(ignoreACL)
return commTaskGr.active;
else if(instanceTable) {
var commChannelGr = new GlideRecord(instanceTable);
commChannelGr.newRecord();
commChannelGr.setValue(this.COLUMNS.COMM_TASK, commTaskGr.getUniqueValue());
return commChannelGr.canCreate() && commTaskGr.active;
}
return false;
},
/* By default all channel types are supported. If a product wishes to limit the availability of channels
they must add entry here.*/
getDeniedChannelTypes: function() {
return [];
},
/* By default all provider types are supported for collaboration. If a product wishes to limit the availability of providers
they must add entry here.*/
getDeniedCollaborationProviderTypes: function() {
return [];
},
isNotifyNumberSet: function() {
return !gs.nil(gs.getProperty(this.PROPERTIES.NOTIFY_NUMBER, ''));
},
isNotifyEnabled: function() {
return (gs.getProperty(this.PROPERTIES.ENABLE_NOTIFY, '') === 'true');
},
onConferenceParticipantChange: function(commTaskGr, participants) {
},
/*override to use a product specific or custom conference page*/
getConferenceManagementPageName: function() {
return this.CONFERENCE_PAGES.MANAGE;
},
/*override to use a product specific or custom conference page*/
getConferenceEndPageName: function() {
return this.CONFERENCE_PAGES.END;
},
createAdhocCommTask: function(commTaskBody, channels, recipients, templateMap) {
if(!this.incidentUtilsSNC.canCreateRecord(this.getCommTaskInstanceForTask()))
return new sn_ws_err.BadRequestError("User doesn't have permissions");
var commPlanGr = new GlideRecord(this.getCommPlanInstanceForTask());
if (commPlanGr.get(commTaskBody.comm_plan)) {
var commTaskGr = new GlideRecord(this.getCommTaskInstanceForTask());
this.prepareAdhocCommTaskGr(commTaskGr, commPlanGr, commTaskBody);
commTaskGr.insert();
if (channels) {
for (var i = 0; i < channels.length; i++) {
var channel = channels[i];
var channelTable = '';
channelTable = this.channelMap[channel].inst_table;
if (channelTable) {
var channelGr = new GlideRecord(channelTable);
channelGr.newRecord();
channelGr.comm_task = commTaskGr.getUniqueValue();
var channelApi = this.channelMap[channel].api_name;
var commTaskVariables = this.getCommTaskVariables(commTaskGr.comm_plan.source.getRefRecord().getRecordClassName() + '');
commTaskVariables.templateMap = templateMap;
var channelApiInstance = this.communicationManagementUtil.getScriptInstanceFromApiName(context, channelApi);
channelApiInstance.updateChannelAdHoc(channelGr, commPlanGr, commTaskGr, commTaskVariables);
channelGr.insert();
}
}
}
if (recipients)
this.contactManagementUtilsSNC.addRecipients(this.getCommPlanInstanceForTask(), commPlanGr.getUniqueValue(), recipients);
return commTaskGr.sys_id + '';
}
},
createAdhocCommPlan: function(commPlanBody, commTaskBody, channels, sourceGr, recipients, templateMap) {
var canCreateTask = this.incidentUtilsSNC.canCreateRecord(this.getCommTaskInstanceForTask());
var canCreatePlan = canCreateTask && this.incidentUtilsSNC.canCreateRecord(this.getCommPlanInstanceForTask());
if(!canCreatePlan)
return new sn_ws_err.BadRequestError("User doesn't have permissions");
var commPlanGr = new GlideRecord(this.getCommPlanInstanceForTask());
this.prepareAdhocCommPlanGr(commPlanGr, commPlanBody, sourceGr);
commPlanGr.insert();
commTaskBody.comm_plan = commPlanGr.getUniqueValue();
var commTaskSysId = this.createAdhocCommTask(commTaskBody, channels, recipients, templateMap);
return commTaskSysId;
},
prepareAdhocCommPlanGr: function(commPlanGr, commPlanBody, sourceGr) {
commPlanGr.short_description = commPlanBody.short_description;
commPlanGr.comm_plan_type = commPlanBody.comm_plan_type;
commPlanGr.source = sourceGr.getUniqueValue();
},
prepareAdhocCommTaskGr: function(commTaskGr, commPlanGr, commTaskBody) {
commTaskGr.comm_plan = commTaskBody.comm_plan;
commTaskGr.comm_task_type = commTaskBody.comm_task_type;
commTaskGr.communication_frequency = commTaskBody.communication_frequency;
if (commTaskBody.due_in) {
// In tests found GlidDuration to support 2^62 + some X, so setting it to 2^62. Lesser that Java max limit for long
if ((commTaskBody.due_in * 6000) <= (Math.pow(2, 62)))
commTaskGr.due_in = new GlideDuration(commTaskBody.due_in * 60000);
else
gs.addErrorMessage(gs.getMessage('Duration provided is too long'));
}
commTaskGr.short_description = commTaskBody.short_description + '';
},
prepareTaskUpdatesPerChannelCommunication: function(commTaskGr, channelUpdates, currentTime) {
if (channelUpdates && channelUpdates.update_last_communication) {
commTaskGr.last_communication = currentTime;
var countTillNow = 0;
if (!gs.nil(commTaskGr.comm_count))
countTillNow = commTaskGr.comm_count * 1;
commTaskGr.comm_count = countTillNow + 1;
if (commTaskGr.communication_frequency == this.COMMUNICATION_FREQUENCY_TYPE.RECURRING && commTaskGr.due_in) {
var dueIn = new GlideDateTime(commTaskGr.due_in).getNumericValue() / 1000;
var nextDue = new GlideDateTime(commTaskGr.last_communication);
nextDue.addSeconds(dueIn);
commTaskGr.due_date = nextDue.getDisplayValue();
}
}
},
updateTaskPerChannelCommunication: function(commTaskGr, channelUpdates, currentTime) {
this.prepareTaskUpdatesPerChannelCommunication(commTaskGr, channelUpdates, currentTime);
commTaskGr.update();
},
addRecipients: function(commPlanSysId, recipients) {
if (!commPlanSysId || !recipients)
return;
return this.contactManagementUtilsSNC.addRecipients(this.getCommPlanInstanceForTask(), commPlanSysId, recipients);
},
prepareGroupsInvolved: function(sysId) {
//NoOp - Default implementation. See CommunicationManagementIncidentHandlerSNC for implementation for incident
},
/*Called from Calculate Next Due - Before BR on comm_task
* WARNING - Hence don't use current.update()
*/
calculateNextDue: function(current, previous) {
var openState = this.COMM_TASK_STATES.OPEN;
var pendingState = this.COMM_TASK_STATES.PENDING;
var secondsToAdd;
var nextDue;
if (current.state.changesTo(openState) && current.state.changesFrom(pendingState) && current.due_in) {
secondsToAdd = new GlideDateTime(current.due_in).getNumericValue() / 1000;
nextDue = new GlideDateTime();
nextDue.addSeconds(secondsToAdd);
current.due_date = nextDue.getDisplayValue();
} else if (current.state.changesTo(pendingState)) {
//May be user moved to open by mistake. So, allow moving to pending but clear due_date
current.due_date = null;
} else if (current.due_in && current.due_in.changes() && current.state != pendingState) {
if (gs.nil(previous.due_in))
secondsToAdd = new GlideDateTime(current.due_in).getNumericValue() / 1000;
else
secondsToAdd = (new GlideDateTime(current.due_in).getNumericValue() - new GlideDateTime(previous.due_in).getNumericValue()) / 1000;
if (gs.nil(current.due_date))
nextDue = new GlideDateTime();
else
nextDue = new GlideDateTime(current.due_date);
nextDue.addSeconds(secondsToAdd);
current.due_date = nextDue.getDisplayValue();
} else if (!current.active) {
current.due_date = null;
}
},
/*Called from State Management - On Task Completion BR on comm_task. This is a after BR*/
onCommTaskCompletion: function(current, previous) {
//NoOp - Default implementation. See CommunicationManagementIncidentHandlerSNC for implementation for incident_alert_task
},
/*Called from State Management-Decide state per order BR on comm_task.
* WARNING - Hence don't use current.update()
*/
decideStatePerOrder: function(current, previous) {
//NoOp - Default implementation. See CommunicationManagementIncidentHandlerSNC for implementation for incident_alert_task
},
/*returns sys_id of workflow to be attached while escalating conference call*/
getConferenceCallEscalationWorkflow: function(groupSysId) {
var workflowSysId = gs.getProperty(this.PROPERTIES.CONFERENCE_CALL_ESCALATION_WORKFLOW);
if (!groupSysId || !this.conferenceEscalationGroupWorkflowMap)
return workflowSysId;
if (this.conferenceEscalationGroupWorkflowMap[groupSysId])
return this.conferenceEscalationGroupWorkflowMap[groupSysId];
return workflowSysId;
},
getClassNameForConferenceEscalation: function(conferenceCallGr) {
return conferenceCallGr.table;
},
getSysIdForWorkflow: function(conferenceCallGr) {
return conferenceCallGr.source + '';
},
getConferenceDefaultTitle: function(data) {
var gr = new GlideRecord(data.table);
if (gr.get(data.sysId))
return gr.number + ' - ' + gr.short_description;
return '';
},
getCommunicateExcludeList: function() {
return [];
},
type: 'CommunicationManagementDefaultHandlerSNC'
};
Sys ID
09b5281f533b030009170ef5d5dc344c