HR Leave · Australia

Scripts & Functions — Deep Dive (Interview Reference)

ServiceNow Australia · Custom app · Arabic + English readable · scripts copy/paste ready

App typeCustom
Scopex_786686_hr_leave
sys_idc84db0e8839f0b509f02b0d6feaad3c9
Replace{BASE} = your instance
Instance URLs Studio Business Rules Client Scripts Script Includes

Scripts & Functions — Deep Dive (Interview Reference)

شرح كل الدوال في تطبيقنا + أهم APIs في ServiceNow للمقابلة.
الأسلوب: عربية + إنجليزية تكمّلان بعضهما — بدون ترجمة حرفية لأسماء الشاشات.


Part 1 — Our Script Includes (line-by-line purpose)

HRLXProLeaveUtilsV2

File: src/server/script_includes/HRLXProLeaveUtilsV2.js

Function Parameters Returns Purpose
calculateBusinessDays startDate, endDate (yyyy-MM-dd) number Counts Mon–Fri inclusive
setApproverFromEmployee currentRecord (GlideRecord) void Sets u_approver_user from employee.u_manager
auditStateChange leaveSysId, oldState, newState, eventType void Inserts audit row
recalculateBalance employeeSysId, year void Updates u_used, u_remaining on balance
_sumApprovedDays employeeSysId, year number Private — SUM u_days_count via GlideAggregate
ajaxGetBusinessDays (from GlideAjax params) string Client-callable wrapper

Interview: Why GlideAggregate for _sumApprovedDays? — أفضل أداء من loop على GlideRecord — يجمع على الخادم.


HRLXProSecurityUtilsV2

File: src/server/script_includes/HRLXProSecurityUtilsV2.js

Function Purpose
isHrAdmin gs.hasRole(‘x_786686_hr_leave.hr_admin’)
canReadLeave Owner, manager, or HR admin
canWriteLeave draft only for owner; HR admin always
_isManagerOfEmployee Checks employee.u_manager == current user

Used in: ACL scripts (src/security/acls.md).


HRLXProIntegrationUtilsV2

File: src/server/script_includes/HRLXProIntegrationUtilsV2.js

Function Purpose
inboundCreateLeave Parse JSON → find employee → insert leave req
outboundPushDecision POST approve/reject to ERP via RESTMessageV2
_findEmployeeByExternalId Lookup by u_employee_id
_findUserByEmployee Map employee → sys_user

Part 2 — Our Business Rules

BR When Trigger logic
BR1 before insert/update Days + approver
BR2 after insert/update if state→submitted: gs.eventQueue
BR3 after update if state changed: audit + recalculateBalance

BR2 event example:

gs.eventQueue('x_786686_hr_leave.leave_v2.submitted', current,
 current.getValue('u_approver_user'), current.getValue('u_number'));

Interview: Why after for BR2 not before? — لأننا نريد التأكد أن السجل حُفظ بحالة submitted قبل إطلاق الإشعار.


Part 3 — Server-Side API (gs.*) — Interview Must-Know

API Purpose Example
gs.getUserID() Current user sys_id audit actor
gs.getUserName() Username logging
gs.hasRole(‘role’) Role check security
gs.info() / gs.error() Logs debugging
gs.addErrorMessage() Block + message BR abort
gs.eventQueue() Fire event notifications
gs.getProperty() System property config
gs.nil() Null/empty check validation
current.setAbortAction(true) Stop BR save validation fail

Part 4 — GlideRecord patterns

var gr = new GlideRecord('table');
gr.addQuery('field', 'value');
gr.addActiveQuery(); // active=true
gr.orderByDesc('sys_created_on');
gr.setLimit(1);
gr.query();
if (gr.next()) {
 gr.field = 'newValue';
 gr.update();
}

// Insert
gr.initialize();
gr.field = ‘x’;
var sysId = gr.insert();

// Secure (respects ACL)
var grs = new GlideRecordSecure(‘table’);

Interview: When use GlideRecordSecure? — Service Portal، multi-tenant، أي سياق المستخدم النهائي.


Part 5 — GlideAggregate

var ga = new GlideAggregate('x_786686_hr_leave_req_v2');
ga.addQuery('u_state', 'approved');
ga.addAggregate('SUM', 'u_days_count');
ga.query();
if (ga.next()) {
 var sum = ga.getAggregate('SUM', 'u_days_count');
}

Part 6 — Client-Side API (g_form.*)

API Purpose
g_form.getValue(‘field’) Read field
g_form.setValue(‘field’, val) Write field
g_form.setMandatory(‘field’, true) Mandatory UI
g_form.setVisible(‘field’, false) Hide
g_form.setReadOnly(‘field’, true) Read only
g_form.addErrorMessage(‘msg’) Show error
g_form.clearValue(‘field’) Clear

onSubmit:

function onSubmit() {
 if (invalid) {
 g_form.addErrorMessage('Fix dates');
 return false; // blocks save
 }
}

Part 7 — GlideAjax (client → server)

var ga = new GlideAjax('ScriptIncludeName');
ga.addParam('sysparm_name', 'methodName');
ga.addParam('sysparm_custom', value);
ga.getXMLAnswer(function(response) {
 // response is string return value
});

Requirements: Script Include must be Client callable + extend AbstractAjaxProcessor (or have sysparm_name handler).


Part 8 — REST (inbound/outbound)

Inbound (Scripted REST):

(function process(request, response) {
 var body = request.body.data;
 response.setStatus(201);
 response.setBody({ sys_id: '...' });
})(request, response);

Outbound (RESTMessageV2):

var rm = new sn_ws.RESTMessageV2('REST Message Name', 'POST method');
rm.setRequestBody(JSON.stringify(payload));
var res = rm.execute();
var status = res.getStatusCode();

Part 9 — Portal Widget server.js pattern

(function() {
 data.items = [];
 var gr = new GlideRecordSecure('x_786686_hr_leave_req_v2');
 gr.addQuery('u_requested_for_user', gs.getUserID());
 gr.query();
 while (gr.next()) {
 data.items.push({
 number: gr.getDisplayValue('u_number'),
 state: gr.getDisplayValue('u_state')
 });
 }
})();

Part 10 — Common interview “write this script” scenarios

1. Set assignment group by category:

if (current.category == 'network')
 current.assignment_group.setDisplayValue('Network');

2. Prevent save if field empty:

if (!current.u_reason) {
 gs.addErrorMessage('Reason required');
 current.setAbortAction(true);
}

3. Copy manager to approver:

Same as setApproverFromEmployee in our app.

4. Query related records:

var child = new GlideRecord('child_table');
child.addQuery('parent', current.sys_id);
child.query();

Part 11 — Where each script type lives (navigation)

Type Navigate
Script Include Studio or sys_script_include.list
Business Rule Studio or sys_script.list
Client Script Studio or sys_script_client.list
UI Policy All > System UI > UI Policies · Open direct
Flow $flow-designer.do
Scripted REST All > System Web Services > Scripted REST APIs · Open direct

File: ../01_DEVELOPMENT.md — every artifact explained with options.

File: 00_MASTER_DEV_ADMIN_INTERVIEW.md — platform + admin tour.