Skip to content

Commit 1d566da

Browse files
authored
Create next_business_window.js
1 parent 4972f94 commit 1d566da

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
var NextBusinessWindow = Class.create();
2+
NextBusinessWindow.prototype = (function () {
3+
// Configuration
4+
var DEFAULT_SCHEDULE_SYS_ID = ''; // optional fallback schedule sys_id (cmn_schedule)
5+
var DEFAULT_TZ = 'Europe/London';
6+
var MAX_SEGMENTS = 1000; // safety guard
7+
8+
// Helpers
9+
function _toGdt(input) {
10+
if (input instanceof GlideDateTime) return input;
11+
var g = new GlideDateTime();
12+
if (input) g.setDisplayValue(input);
13+
return g;
14+
}
15+
function _getSchedule(scheduleSysId) {
16+
var sch = new GlideSchedule();
17+
if (scheduleSysId) sch.load(scheduleSysId);
18+
else if (DEFAULT_SCHEDULE_SYS_ID) sch.load(DEFAULT_SCHEDULE_SYS_ID);
19+
else throw new Error('No schedule sys_id supplied and no default configured.');
20+
return sch;
21+
}
22+
function _setTz(gdt, tz) { if (tz) gdt.setTZ(tz); return gdt; }
23+
24+
return {
25+
initialize: function () {},
26+
27+
/**
28+
* Add working minutes across a GlideSchedule.
29+
* @param {String|GlideDateTime} start
30+
* @param {Number} minutes
31+
* @param {String} scheduleSysId
32+
* @param {String} [timeZone] IANA name, e.g. "Europe/London"
33+
* @returns {{endGdt: GlideDateTime, consumedMinutes: number, segments: Array}}
34+
*/
35+
addWorkingMinutes: function (start, minutes, scheduleSysId, timeZone) {
36+
if (!minutes || minutes < 0) throw new Error('Minutes must be a positive integer.');
37+
var tz = timeZone || DEFAULT_TZ;
38+
var sch = _getSchedule(scheduleSysId);
39+
40+
var cursor = _toGdt(start);
41+
_setTz(cursor, tz);
42+
43+
// If not in schedule, jump to the next working start
44+
if (!sch.isInSchedule(cursor)) {
45+
var nextStart = sch.getNextStartTime(cursor);
46+
if (!nextStart) throw new Error('No next working period found from start time.');
47+
cursor = nextStart;
48+
}
49+
50+
var remaining = parseInt(minutes, 10);
51+
var segments = [];
52+
var guard = 0;
53+
54+
while (remaining > 0) {
55+
if (guard++ > MAX_SEGMENTS) throw new Error('Exceeded max segments; check schedule/inputs.');
56+
57+
var segEnd = sch.getNextEndTime(cursor);
58+
if (!segEnd) throw new Error('Schedule has no next end time; check configuration.');
59+
60+
var available = Math.ceil((segEnd.getNumericValue() - cursor.getNumericValue()) / (60 * 1000)); // minutes
61+
62+
if (remaining <= available) {
63+
var end = new GlideDateTime(cursor);
64+
end.addSeconds(remaining * 60);
65+
segments.push({ segmentStart: new GlideDateTime(cursor), segmentEnd: new GlideDateTime(end), consumed: remaining });
66+
return { endGdt: end, consumedMinutes: minutes, segments: segments };
67+
}
68+
69+
// consume full segment
70+
segments.push({ segmentStart: new GlideDateTime(cursor), segmentEnd: new GlideDateTime(segEnd), consumed: available });
71+
remaining -= available;
72+
73+
var nextStart = sch.getNextStartTime(segEnd);
74+
if (!nextStart) throw new Error('No subsequent working segment found.');
75+
cursor = nextStart;
76+
}
77+
78+
return { endGdt: new GlideDateTime(cursor), consumedMinutes: minutes, segments: segments };
79+
}
80+
};
81+
})();

0 commit comments

Comments
 (0)