Copy this script into ServiceNow under application x_786686_hr_leave (Australia). Table/API names already use the current scope.
Source: src/server/script_includes/HRLXProLeaveUtilsV2.js
/**
* Script Include: HRLXProLeaveUtilsV2
* Scope: x_786686_hr_leave
* Application: Custom · Scope: x_786686_hr_leave · sys_id: c84db0e8839f0b509f02b0d6feaad3c9
* Client callable: true (extends AbstractAjaxProcessor)
* Purpose: Leave calculations + helpers (business days, approver, balance, audit).
*
* Create in ServiceNow:
* Studio > Create Application File > Script Include
* Name: HRLXProLeaveUtilsV2
* Client callable: checked
*/
var HRLXProLeaveUtilsV2 = Class.create();
HRLXProLeaveUtilsV2.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
/**
* Count business days (Mon-Fri) inclusive between two date strings.
* @param {string} startDate - 'yyyy-MM-dd'
* @param {string} endDate - 'yyyy-MM-dd'
* @return {number}
*/
calculateBusinessDays: function (startDate, endDate) {
if (!startDate || !endDate) return 0;
var start = new GlideDateTime(startDate + ' 00:00:00');
var end = new GlideDateTime(endDate + ' 00:00:00');
if (end.before(start)) return 0;
var days = 0;
var cursor = new GlideDateTime(start);
while (!cursor.after(end)) {
var dow = cursor.getDayOfWeekLocalTime(); // 1=Mon ... 7=Sun
if (dow >= 1 && dow <= 5) days++;
cursor.addDaysLocalTime(1);
}
return days;
},
/**
* Resolve the approver (employee's manager) and set it on the record.
* @param {GlideRecord} currentRecord - leave request record
*/
setApproverFromEmployee: function (currentRecord) {
var empId = currentRecord.getValue('u_employee_ref');
if (!empId) return;
var emp = new GlideRecord('x_786686_hr_leave_employee_v2');
if (emp.get(empId) && emp.u_manager) {
currentRecord.u_approver_user = emp.getValue('u_manager');
}
},
/**
* Write an audit row when the state changes.
*/
auditStateChange: function (leaveSysId, oldState, newState, eventType) {
var a = new GlideRecord('x_786686_hr_leave_audit_v2');
a.initialize();
a.u_leave_ref = leaveSysId;
a.u_old_state = oldState || '';
a.u_new_state = newState || '';
a.u_event_type = eventType || 'state_change';
a.u_actor = gs.getUserID();
a.insert();
},
/**
* Recalculate remaining balance for an employee/year.
*/
recalculateBalance: function (employeeSysId, year) {
var used = this._sumApprovedDays(employeeSysId, year);
var bal = new GlideRecord('x_786686_hr_leave_bal_v2');
bal.addQuery('u_employee_ref', employeeSysId);
bal.addQuery('u_year', year);
bal.query();
if (bal.next()) {
bal.u_used = used;
bal.u_remaining = parseInt(bal.getValue('u_entitled') || 0, 10) - used;
bal.update();
}
},
_sumApprovedDays: function (employeeSysId, year) {
var total = 0;
var gr = new GlideAggregate('x_786686_hr_leave_req_v2');
gr.addQuery('u_employee_ref', employeeSysId);
gr.addQuery('u_state', 'approved');
gr.addQuery('u_start_date', '>=', year + '-01-01');
gr.addQuery('u_start_date', '<=', year + '-12-31');
gr.addAggregate('SUM', 'u_days_count');
gr.query();
if (gr.next()) total = parseInt(gr.getAggregate('SUM', 'u_days_count') || 0, 10);
return total;
},
/**
* GlideAjax entry point for client-side day calculation.
*/
ajaxGetBusinessDays: function () {
return this.calculateBusinessDays(
this.getParameter('sysparm_start'),
this.getParameter('sysparm_end')
);
},
type: 'HRLXProLeaveUtilsV2'
});