Name
global.OnCallGapsConflictsReportSNC
Description
No description available
Script
var OnCallGapsConflictsReportSNC = Class.create();
OnCallGapsConflictsReportSNC.prototype = {
initialize: function() {
this.log = new GSLog("com.snc.on_call_rotation.log.level", this.type);
this.ocsNG = new OnCallSecurityNG();
},
V_ON_CALL_REPORT_CACHE: 'v_on_call_report_cache',
ATTR_REPORT_ID: 'report_id',
ATTR_GROUP: 'group',
ATTR_DATA: 'data',
NO_OF_DAYS: 30,
sendReports: function () {
var that = this;
var userGroupReports = [];
/*
SAMPLE:
this.userGroupReports = [{
userIds: [],
groupIds: []
}]
*/
var reportId = gs.generateGUID();
var onCallGroups = new GlideAggregate('cmn_rota');
onCallGroups.addActiveQuery();
onCallGroups.groupBy('group');
onCallGroups.query();
var allOnCallGroups = [];
var directGroupManagerMap = {};
while (onCallGroups.next()) {
var groupId = onCallGroups.getValue('group');
if (groupId) {
this._buildGroupReportData(reportId, groupId, true);
allOnCallGroups.push(groupId);
if (onCallGroups.group.manager.toString()) {
if (!directGroupManagerMap[onCallGroups.group.manager.toString()])
directGroupManagerMap[onCallGroups.group.manager.toString()] = [];
directGroupManagerMap[onCallGroups.group.manager.toString()].push(groupId);
}
}
}
var ocsNG = new OnCallSecurityNG();
/*
* Admins and Rota admins full reports
*/
var adminUserMap = ocsNG.getOnCallAdminList(true);
var userSysIds = Object.keys(adminUserMap);
if (userSysIds.length) {
var userGroupReport = { userIds:[]};
userGroupReport.groupIds = allOnCallGroups;
userGroupReport.userIds = userSysIds;
userGroupReports.push(userGroupReport); // admin report
}
/*
* Direct group managers
*/
Object.keys(directGroupManagerMap).forEach(function (userId) {
if (!adminUserMap[userId])
that._addUserGroupReportByUserId(userGroupReports, userId, directGroupManagerMap[userId]);
});
/*
* Shift managers through preferences
*/
var groupManagersByPreference = ocsNG.getShiftManagersByPreferences();
groupManagersByPreference.forEach(function (groupMap) {
groupMap.userIds.forEach(function (userId) {
if (!adminUserMap[userId])
that._addUserGroupReportByUserId(userGroupReports, userId, groupMap.groupId);
});
});
/*
* Managers through delegation
*/
var groupManagersByDelegation = ocsNG.getShiftManagersByDelegation();
groupManagersByDelegation.forEach(function (groupMap) {
groupMap.userIds.forEach(function (userId) {
if (!adminUserMap[userId])
that._addUserGroupReportByUserId(userGroupReports, userId, groupMap.groupId);
});
});
this._generateEmailsAndDispatch(reportId, userGroupReports);
this._cacheDeleteReports(reportId);
},
_addUserGroupReportByUserId: function (userGroupReports, userId, groupId) {
var userGroupReport = userGroupReports.find(function (userGroupReport) {
return userGroupReport.userId == userId;
});
if (userGroupReport) {
userGroupReport.groupIds.push(groupId);
} else {
userGroupReports.push({
userId: userId,
userIds: [userId],
groupIds: [groupId]
})
}
},
_buildUserReportData: function(reportId, userSysId, isRotaAdmin) {
var that = this;
var onCallCommon = new OnCallCommon();
var userGroupReport = {};
userGroupReport.userIds = [userSysId];
userGroupReport.groupIds = [];
var groupId;
// Directly managed groups
var managerGroupGr = new GlideRecord("sys_user_group");
onCallCommon.addManagedGroupsQuery(managerGroupGr, userSysId, isRotaAdmin);
managerGroupGr.query();
while (managerGroupGr.next()) {
groupId = managerGroupGr.sys_id + "";
this._buildGroupReportData(reportId, groupId);
userGroupReport.groupIds.push(groupId);
}
if (!isRotaAdmin) {
// Managed groups through delegation
var gaHasRole = this.ocsNG.getDelegatedGroups(userSysId);
while (gaHasRole.next()) {
groupId = gaHasRole.getValue('granted_by');
this._buildGroupReportData(reportId, groupId);
userGroupReport.groupIds.push(groupId);
}
// Managed through group preferences
var groupIds = this.ocsNG.getManagedGroupsByPreferences(userSysId);
groupIds.forEach(function(groupId) {
that._buildGroupReportData(reportId, groupId);
userGroupReport.groupIds.push(groupId);
});
}
return userGroupReport;
},
/*
* @output: Group Report Id, temp record store in
*/
_buildGroupReportData: function (reportId, groupId) {
var groupReport = {};
var todayGd = new GlideDate();
var from = todayGd.getDisplayValueInternal();
todayGd.addDays(30);
var to = todayGd.getDisplayValueInternal();
var gapsConflictsSpans = this._getGapsConflictsSpans(groupId, from, to, this.NO_OF_DAYS);
if (gapsConflictsSpans) {
this._populateGaps(groupReport, groupId, from, to, gapsConflictsSpans);
this._populateConflicts(groupReport, groupId, from, to, gapsConflictsSpans);
}
this._populateRotaInfo(groupReport);
this._cacheSaveReports(reportId, groupId, groupReport);
},
_populateGaps: function(report, groupId, from, to, gapsConflictsSpans) {
report.gaps = {};
var gapTypes = ["user_inactive", "user_left", "user_timeoff_no_coverage"];
var gapsObj = new OCOddityChecker().getGaps(from, to, groupId, this.NO_OF_DAYS, gapsConflictsSpans);
gapTypes.forEach(function(gapType) {
if (gapsObj[gapType] && gapsObj[gapType].length) {
gapsObj[gapType].forEach(function(userId) {
gapsObj[userId].forEach(function(gap) {
if (!report.gaps[gap.rota_id]) {
rotaGap = {};
rotaGap.count = 0;
report.gaps[gap.rota_id] = rotaGap;
}
report.gaps[gap.rota_id].count++;
});
});
}
});
},
_populateConflicts: function(report, groupId, from, to, gapsConflictsSpans) {
report.conflicts = {};
var conflicts = new OCOddityChecker().getConflictsInGroup(from, to, groupId, this.NO_OF_DAYS, gapsConflictsSpans);
conflicts.forEach(function(conflict) {
if (!report.conflicts[conflict.rota_id]) {
rotaConflit = {};
rotaConflit.count = 0;
report.conflicts[conflict.rota_id] = rotaConflit;
}
report.conflicts[conflict.rota_id].count++;
});
},
_populateRotaInfo: function(report) {
var rotaGr = new GlideRecord("cmn_rota");
Object.keys(report).forEach(function(key) {
Object.keys(report[key]).forEach(function(rotaId) {
if (rotaGr.get(rotaId)) {
report[key][rotaId].scheduleName = rotaGr.schedule.name + "";
report[key][rotaId].groupId = rotaGr.group + "";
report[key][rotaId].groupName = rotaGr.group.name + "";
report[key][rotaId].managerName = (rotaGr.group.manager + "") ? (rotaGr.group.manager.name + "") : "";
}
});
});
},
_getGapsConflictsSpans: function(groupId, startDate, endDate, maxOddityDuration) {
var oddityDateDiff = gs.dateDiff(startDate, endDate, true);
if (JSUtil.nil(oddityDateDiff) || oddityDateDiff < 0) {
this.log.logErr("[_getGapsConflictsSpans] : Invalid start and end time provided");
return;
}
var providedOddityDuration = parseInt(oddityDateDiff / (24 * 60 * 60));
if (providedOddityDuration > maxOddityDuration) {
this.log.logErr("[_getGapsConflictsSpans] : Gaps and conflicts can not be found for more than {0} days", maxOddityDuration);
return;
}
var formatterClass = OCFormatterMapping.formatters["dhtmlx"];
var formatter = new formatterClass();
var ocrRotaV2 = new OCRotationV2(null, formatter);
return ocrRotaV2
.setStartDate(startDate)
.setEndDate(endDate)
.setGroupIds(groupId)
.getSpans();
},
_generateEmailsAndDispatch: function(reportId, userGroupReports) {
var that = this;
if (userGroupReports.length) {
userGroupReports.forEach(function(userGroupReport) {
if (userGroupReport.userIds.length) {
var htmlReport = that.generateEmailHtml(reportId, userGroupReport.groupIds);
if (htmlReport)
userGroupReport.userIds.forEach(function(userId) {
gs.eventQueue("rota.on_call.report", null, userId, htmlReport);
});
}
});
}
},
/*
* @output: returns html report. if there are no gaps and conflicts in consolidated report, then returns 'undefined'.
*/
generateEmailHtml: function(reportId, groupIds) {
var that = this;
var consolidatedReport = {};
groupIds.forEach(function(groupId) {
var report = that._cacheGetReport(reportId, groupId);
if (report)
that._consolidateReport(consolidatedReport, report);
});
var html = this.getStyle();
html += '<div><div id="schedule-report">';
html += '<p>' + gs.getMessage('Please review pending actions for your On-Call group(s).') + '</p><table>';
var gapKeys = Object.keys(consolidatedReport.gaps);
var conflictKeys = Object.keys(consolidatedReport.conflicts);
if(!gapKeys.length && !conflictKeys.length)
return;
if (gapKeys.length) {
html += this.getHeader(gs.getMessage("On-Call Coverage Gaps"));
gapKeys.forEach(function(key) {
html += that.getRowHtml(consolidatedReport.gaps[key]);
});
}
if (conflictKeys.length) {
html += this.getHeader(gs.getMessage("On-Call Conflicts"));
conflictKeys.forEach(function(key) {
html += that.getRowHtml(consolidatedReport.conflicts[key]);
});
}
html += '</table></div>';
html += '</div>';
return html;
},
getHeader: function(subHeading) {
return "<tr> <th>" + subHeading +
"</th> <th>" + gs.getMessage("Group Name") +
"</th> <th>" + gs.getMessage("Manager Name") +
"</th> <th>" + gs.getMessage("Schedule Name") +
"</th> <th>" + gs.getMessage("Occurrences") +
"</th> <th>" + gs.getMessage("Take Action") +
"</th> </tr>";
},
getRowHtml: function(item) {
var link = gs.getProperty('glide.servlet.uri') + "$oc_workbench.do?sysparm_group_id=" + item.groupId;
return "<tr> <td></td> <td>" + item.groupName +
"</td> <td>" + item.managerName +
"</td> <td>" + item.scheduleName +
"</td> <td>" + item.count +
"</td> <td> <a href='" + link + "' target='_blank'>" + "View Workbench</a>" +
"</td> </tr>";
},
getStyle: function() {
return '<style> #schedule-report table, #schedule-report th, #schedule-report td { border-collapse: collapse; border: 1px solid black; text-align: center; padding: 5px; font-size: 10pt; font-family: SourceSansPro, "Helvetica Neue", Arial; } #schedule-report th, #schedule-report tr > td:first-child { background-color: #767676; color: white; } </style>';
},
_consolidateReport: function(consolidatedReport, report) {
["gaps", "conflicts"].forEach(function(key) {
if (!consolidatedReport[key])
consolidatedReport[key] = {};
for (var attrName in report[key]) consolidatedReport[key][attrName] = report[key][attrName];
});
},
_cacheHasReport: function(reportId, groupId) {
var vocrGr = new GlideRecord(this.V_ON_CALL_REPORT_CACHE);
vocrGr.addQuery(this.ATTR_REPORT_ID, reportId);
vocrGr.addQuery(this.ATTR_GROUP, groupId);
vocrGr.query();
return vocrGr.hasNext();
},
_cacheGetReport: function(reportId, groupId) {
var vocrGr = new GlideRecord(this.V_ON_CALL_REPORT_CACHE);
vocrGr.addQuery(this.ATTR_REPORT_ID, reportId);
vocrGr.addQuery(this.ATTR_GROUP, groupId);
vocrGr.query();
if (vocrGr.next()) {
var reportData = vocrGr.getValue(this.ATTR_DATA);
if (reportData) {
return JSON.parse(reportData);
}
}
},
_cacheSaveReports: function(reportId, groupId, reportData) {
var vocrGr = new GlideRecord(this.V_ON_CALL_REPORT_CACHE);
vocrGr.initialize();
vocrGr.setValue(this.ATTR_REPORT_ID, reportId);
vocrGr.setValue(this.ATTR_GROUP, groupId);
vocrGr.setValue(this.ATTR_DATA, JSON.stringify(reportData));
vocrGr.insert();
},
_cacheDeleteReports: function(reportId) {
var vocrGr = new GlideRecord(this.V_ON_CALL_REPORT_CACHE);
vocrGr.addQuery(this.ATTR_REPORT_ID, reportId);
vocrGr.deleteMultiple();
},
type: 'OnCallGapsConflictsReportSNC'
};
Sys ID
a913e4db731c2300cbb654eb7df6a7be