Name
global.ChangeRequestCalendarSNC
Description
ServiceNow logic for Change Request Calendar View
Script
var ChangeRequestCalendarSNC = Class.create();
ChangeRequestCalendarSNC.CHANGE = 'change_request';
ChangeRequestCalendarSNC.LOG_PROP = "com.snc.change_request.calendar_view.log";
ChangeRequestCalendarSNC.prototype = {
initialize: function(gr) {
this._gr = gr;
this._ciDataCache = {};
this._log = new global.GSLog(ChangeRequestCalendarSNC.LOG_PROP, this.type).setLog4J();
},
_addDateRangeQuery: function (gr, startDate, endDate) {
// Astute readers will notice that we leave out Change requests with null start &
// end dates if startDate & endDate are provided. In reality both of them are actually
// always provided.
//
// This is intentional. Change Calendar supports displaying events with null bounds,
// there it sets the null end way far far so that users don't navigate there, and the
// event texts show "unbounded" instead of actual date value.
//
// However, tests show the longer the event bar (even if we just show a 24hr length of it)
// slows down the dhtmlx calendar considerably. Also this might query many Change requests
// on customer instances; and for what purpose? Unbounded Change requests mean they are not
// yet scheduled and are not really useful when making a decision regarding scheduling current
// Change. So, because of no strong functional requirement and performance consideration, we
// leave out unbounded Change requests.
if (startDate)
gr.addQuery('end_date', '>', startDate);
if (endDate)
gr.addQuery('start_date', '<', endDate);
},
getRelatedSchedules: function (startDate, endDate) {
var conf = {
date_range: [startDate, endDate],
dry_run: true,
collect_window_data: true,
allow_partially_overlapping_windows: true,
show_timing_info: false
};
var conflictChecker = new global.ChangeCheckConflicts(this._gr, conf);
if (!conflictChecker.getWindowData) {
this._log.error("ChangeCheckConflicts does not have \"getWindowData\" defined. That is probably customized. Cannot continue.");
return {maintenance:[], blackout:[], is_invalid_conflict_checker_si: true};
}
conflictChecker.check();
return conflictChecker.getWindowData();
},
getChangesWithSameAssignedTo: function (startDate, endDate) {
if (!this._gr.getValue('assigned_to'))
return null;
var gr = new GlideRecordSecure(ChangeRequestCalendarSNC.CHANGE);
gr.addActiveQuery();
gr.addQuery('sys_id', '!=', this._gr.getUniqueValue());
this._addDateRangeQuery(gr, startDate, endDate);
var c = gr.addJoinQuery(ChangeRequestCalendarSNC.CHANGE, 'assigned_to', 'assigned_to');
c.addCondition('sys_id', this._gr.getUniqueValue());
return gr;
},
getChangesWithSameAssignmentGroup: function (startDate, endDate) {
if (!this._gr.getValue('assignment_group'))
return null;
var gr = new GlideRecordSecure(ChangeRequestCalendarSNC.CHANGE);
gr.addActiveQuery();
gr.addQuery('sys_id', '!=', this._gr.getUniqueValue());
this._addDateRangeQuery(gr, startDate, endDate);
var c = gr.addJoinQuery(ChangeRequestCalendarSNC.CHANGE, 'assignment_group', 'assignment_group');
c.addCondition('sys_id', this._gr.getUniqueValue());
return gr;
},
getChangesAffectingSamePrimaryCI: function (startDate, endDate) {
if (!this._gr.getValue('cmdb_ci'))
return null;
var gr = new GlideRecordSecure(ChangeRequestCalendarSNC.CHANGE);
gr.addActiveQuery();
gr.addQuery('sys_id', '!=', this._gr.getUniqueValue());
this._addDateRangeQuery(gr, startDate, endDate);
var c = gr.addJoinQuery(ChangeRequestCalendarSNC.CHANGE, 'cmdb_ci', 'cmdb_ci');
c.addCondition('sys_id', this._gr.getUniqueValue());
return gr;
},
getScheduleInformation: function (windowArr, startDate, endDate) {
var schedules = {};
for (var ci in windowArr) {
var wArr = windowArr[ci];
for (var i = 0; i < wArr.length; i++) {
var w = wArr[i];
var sh = schedules[w.scheduleId];
if (sh) {
this._addCiToRelated(sh.related_cis, ci, w);
continue;
}
sh = {
sys_id: w.scheduleId,
date_ranges: [],
related_cis: []
};
this._addCiToRelated(sh.related_cis, ci, w);
var sp = new GlideSchedule(w.scheduleId);
sh.title = sp.getName();
sh.time_zone = sp.getTimeZone();
var it = sp.fetchTimeMap(startDate, endDate, sh.time_zone , false);
while (it.hasNext()) {
var stp = it.next();
var startGDT = stp.getStart().getGlideDateTime();
var endGDT = stp.getEnd().getGlideDateTime();
var range = {
start: startGDT.getValue(),
startDisplay: startGDT.getDisplayValueInternal(),
end: endGDT.getValue(),
endDisplay: endGDT.getDisplayValueInternal()
};
var span = new GlideRecord('cmn_schedule_span');
if (span.get(stp.getOriginTimeSpan().getID())) {
range.origin_span = {
sys_id: span.getUniqueValue(),
name: span.getDisplayValue('name')
};
}
sh.date_ranges.push(range);
}
schedules[w.scheduleId] = sh;
}
}
var res = [];
for (var k in schedules) {
res.push(schedules[k]);
}
return res;
},
_addCiToRelated: function(arr, ci, w) {
// For maintenance/blackout schedules that apply to a Change Request the ci value will be null.
if (!ci || "null" === ci)
return;
if (w && w.relatedCiId)
this._addCiToRelated(arr, w.relatedCiId);
else if (arr.every(function (c) {
return c.sys_id !== ci;
})) {
var ciData = this._ciDataCache[ci];
if (!ciData) {
ciData = {};
var c = new GlideRecord('cmdb_ci');
if (c.get(ci)) {
ciData.name = c.getDisplayValue('name');
ciData.ci_class = c.getDisplayValue('sys_class_name');
}
this._ciDataCache[ci] = ciData;
}
arr.push({
sys_id: ci,
name: ciData.name,
ci_class: ciData.ci_class
});
}
},
type: 'ChangeRequestCalendarSNC'
};
Sys ID
6fa316240b2332005775aabcb4673af3