- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
6 hours ago
I am facing an issue with the following scheduled script execution code, where it runs fine for one case record but fails for other records. When I run the same script for the failing case record, it works fine. Failing means the script will move the cases that are in the 'Awaiting Info' state for more than 5 business days to the 'Resolved state'. Instead of moving after 5 days, it moved it within the 16 hours after the case was moved to 'Awaiting Info'.
It seems the following line does not work properly:
"var dueDate = schedule.add(sinceGdt, duration);"
Code:
=====
// =============================================================
// Auto-Resolve "Awaiting Info" Cases After 5 Business Days
// Using 9-hour business day logic and schedule-based time
// NO timezone override, runs daily at 00:00
// =============================================================
var LOG = '[AutoResolve Awaiting Info] ';
// ================================
// Load system properties (OOB pattern)
// ================================
var scheduleID = gs.getProperty('csm.schedule.auto.close');
var testerSupport = gs.getProperty('csm.tester.support.group');
var testerSupportCE = gs.getProperty('csm.tester.support.group.ce');
var testerSupportIP = gs.getProperty('csm.tester.support.group.in.person');
var envAdmins = gs.getProperty('csm.env.admin.group');
// Validate schedule ID before continuing
if (!scheduleID)
gs.error(LOG + 'System property csm.schedule.auto.close is not set. Job will continue but cannot resolve cases.');
// ================================
// Build list of the FOUR tester groups
// Only these groups are processed.
// ================================
var testerGroups = [];
if (testerSupport) testerGroups.push(testerSupport);
if (testerSupportCE) testerGroups.push(testerSupportCE);
if (testerSupportIP) testerGroups.push(testerSupportIP);
if (envAdmins) testerGroups.push(envAdmins);
// ================================
// Load schedule once (best practice)
// Do NOT set timezone in script.
// ================================
var schedule = new GlideSchedule();
schedule.load(scheduleID);
// ================================
// PRECOMPUTE DURATION (moved outside loop)
// 5 business days × 9 working hours → 45 working hours
// Converted to milliseconds → GlideDuration
// ================================
var days = 5;
var hours = 9;
var totalMs = days * hours * 60 * 60 * 1000;
var duration = new GlideDuration(totalMs);
// ================================
// Query cases in Awaiting Info (state=18)
// Only active cases with a timestamp
// ================================
var gr = new GlideRecord('sn_customerservice_case');
gr.addQuery('state', 18); // Awaiting Info
gr.addQuery('active', true);
gr.addNotNullQuery('u_awaiting_info_since'); // Must have tracking timestamp
gr.query();
var now = new GlideDateTime(); // Current UTC time
var processed = 0;
var resolvedCount = 0;
// ================================
// Resolution Notes Template
// "{name}" dynamically replaced with consumer display name
// ================================
/*var resolutionTemplate =
"Hello {name},\n\n" +
"We haven't heard back from you since our last reply, so we are now resolving this case due to inactivity.\n" +
"If you still require assistance, please simply reply to this email! Replying will automatically reopen the case, and we will be happy to resume helping you.\n\n";
"Thank you!\n" +
"uTest Support Team";*/
// ================================
// MAIN PROCESSING LOOP
// ================================
while (gr.next()) {
processed++;
var groupId = String(gr.assignment_group);
// Skip cases NOT belonging to the four tester groups
var isTesterGroup = testerGroups.indexOf(groupId) !== -1;
if (!isTesterGroup)
continue;
// Timestamp when case entered "Awaiting Info"
var sinceValue = gr.getValue('u_awaiting_info_since');
var sinceGdt = new GlideDateTime(sinceValue);
// Compute due date based on schedule (respects holidays & working hours)
var dueDate = schedule.add(sinceGdt, duration);
// If due date has passed (or equals now) → auto-resolve
if (dueDate.before(now) || dueDate.equals(now)) {
// Set Resolution Code (choice value "8")
gr.setValue('resolution_code', '8');
// Personalize message using consumer's display name
//var consumerName = gr.consumer ? gr.consumer.getDisplayValue() : "Tester";
//var notes = resolutionTemplate.replace("{name}", consumerName);
var notes = "We haven't heard back from you since our last reply, so we are now resolving this case due to inactivity.\n" +
"If you still require assistance, please simply reply to this email! Replying will automatically reopen the case, and we will be happy to resume helping you.\n\n";
gr.setValue('close_notes', notes);
// Move state to Resolved (6)
// OOB BR `mark_resolved` will update resolved_by and resolved_at
gr.setValue('state', 6);
// Add audit trail
//gr.work_notes = '[AutoResolve] Case auto-resolved after 5 business days of no response.';
gr.update();
resolvedCount++;
}
}
// Summary for system logs
gs.info(LOG + 'Execution complete. Processed=' + processed +
', Auto-resolved=' + resolvedCount);
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 hours ago
I was able to figure out the solution myself, and it was loading the schedule inside the while loop.
======
/ Load schedule once var schedule = new GlideSchedule(); schedule.load(scheduleID);
By loading the schedule once outside the loop, the GlideSchedule object’s internal cursor or state was likely being exhausted or locked after the first successful calculation, causing every subsequent call to schedule.add() to fail or return 0ms. Moving the instantiation inside the loop ensures a fresh, "clean" instance of the schedule engine for every single case calculation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
5 hours ago
try this
// =============================================================
// Auto-Resolve "Awaiting Info" Cases After 5 Business Days
// FIXED VERSION - Consistent schedule.add() handling
// Runs daily at 00:00 - 9-hour business day logic
// =============================================================
var LOG = '[AutoResolve Awaiting Info] ';
// ================================
// Load system properties
// ================================
var scheduleID = gs.getProperty('csm.schedule.auto.close');
var testerSupport = gs.getProperty('csm.tester.support.group');
var testerSupportCE = gs.getProperty('csm.tester.support.group.ce');
var testerSupportIP = gs.getProperty('csm.tester.support.group.in.person');
var envAdmins = gs.getProperty('csm.env.admin.group');
// Validate schedule
if (!scheduleID) {
gs.error(LOG + 'System property csm.schedule.auto.close is not set. Job stopped.');
return;
}
// Build tester groups list
var testerGroups = [];
if (testerSupport) testerGroups.push(testerSupport);
if (testerSupportCE) testerGroups.push(testerSupportCE);
if (testerSupportIP) testerGroups.push(testerSupportIP);
if (envAdmins) testerGroups.push(envAdmins);
// Load schedule once
var schedule = new GlideSchedule();
schedule.load(scheduleID);
// PRECOMPUTE DURATION: 5 business days × 9 hours = 45 working hours
var days = 5;
var hours = 9;
var totalMs = days * hours * 60 * 60 * 1000;
var duration = new GlideDuration(totalMs);
// Query cases: Awaiting Info (state=18), active, with timestamp
var gr = new GlideRecord('sn_customerservice_case');
gr.addQuery('state', 18); // Awaiting Info
gr.addQuery('active', true);
gr.addNotNullQuery('u_awaiting_info_since');
gr.query();
var now = new GlideDateTime();
var processed = 0;
var resolvedCount = 0;
// ================================
// MAIN PROCESSING LOOP - FIXED
// ================================
while (gr.next()) {
processed++;
var groupId = String(gr.assignment_group);
// Skip non-tester groups
if (testerGroups.indexOf(groupId) === -1)
continue;
// FIXED: Proper GlideDateTime normalization
var sinceValue = gr.getValue('u_awaiting_info_since');
var sinceGdt = new GlideDateTime();
sinceGdt.setValue(sinceValue); // Normalizes to instance UTC
// Calculate due date using schedule (respects holidays/working hours)
var dueDate = schedule.add(sinceGdt, duration);
// Check if due (handles edge case where dueDate equals now)
if (dueDate.before(now) || dueDate.equals(now)) {
// Set resolution details
gr.setValue('resolution_code', '8'); // Resolved choice value
gr.setValue('close_notes', "We haven't heard back from you since our last reply, so we are now resolving this case due to inactivity.\n" +
"If you still require assistance, please simply reply to this email! Replying will automatically reopen the case, and we will be happy to resume helping you.\n\nThank you!\nuTest Support Team");
gr.setValue('state', 6); // Resolved state
gr.update();
resolvedCount++;
gs.info(LOG + 'Auto-resolved: ' + gr.number + ' (since: ' + sinceGdt.getDisplayValue() + ', due: ' + dueDate.getDisplayValue() + ')');
}
}
// Final summary
gs.info(LOG + 'COMPLETE: Processed=' + processed + ', Auto-resolved=' + resolvedCount);
💡 If my response helped, please mark it as correct ✅ and close the thread 🔒— this helps future readers find the solution faster! 🙏
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
5 hours ago
@Ankur Bawiskar ,
Thanks for the update but still I see both the dates same. Please find below the logs.
[AutoResolve Awaiting Info] Auto-resolved: CS0080391 (since: 02/16/2026 02:04:14, due: 02/16/2026 02:04:14)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
5 hours ago
Go through this community post, Hope it will help you.
Solved: How to calculate business duration in days - ServiceNow Community
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 hours ago
I was able to figure out the solution myself, and it was loading the schedule inside the while loop.
======
/ Load schedule once var schedule = new GlideSchedule(); schedule.load(scheduleID);
By loading the schedule once outside the loop, the GlideSchedule object’s internal cursor or state was likely being exhausted or locked after the first successful calculation, causing every subsequent call to schedule.add() to fail or return 0ms. Moving the instantiation inside the loop ensures a fresh, "clean" instance of the schedule engine for every single case calculation.
