Business Rules - Incident Autoclose based on Schedule not working as expected

Happy S
Tera Expert

Hi,

 

I am trying to write a code where resolved Incidents will have their state updated to Closed after 10 Business Days based on the Schedule: 8-5 weekdays excluding holidays.

 

I have referred to the ServiceNow Developer documentation below where its mentioned there is a need to query using whenNext(GlideDateTime time, String timeZone).

https://developer.servicenow.com/dev.do#!/reference/api/utah/server/c_GlideScheduleScopedAPI 

HappyS_0-1710870138896.png

 

 

 

testScript(); 
function testScript() { 
var now = new GlideDateTime(); //current date and time
var sched = new GlideSchedule("<sys_id>"); // Use a cmn_schedule sys_id 
if (sched.isInSchedule(now)){ 
gs.info('We are in an active schedule window so whenNext() is not helpful'); 
} else{  
gs.info('Not currently in schedule so call whenNext()'); 
var msUntilNext = sched.whenNext(new GlideDateTime(), 'US/Pacific'); 
gs.info('Next schedule starts in '+msUntilNext+' milliseconds'); 
} 
}
\\ Output [schedule inactive)]:
\\ *** Script: Not currently in schedule so call whenNext() 
\\ *** Script: Next schedule starts in -1 milliseconds

 

 

 

 

 

Below is the code that I have came up with and I need help as during testing some of the resolved tickets are getting closed earlier although they have yet to pass/hit 10 Business Days based on the schedule 8-5 weekdays excluding holidays.

 

 

 

var ps = gs.getProperty('glide.ui.autoclose.time');
var pn = parseInt(ps);

// Check if autoclose time is enabled
if (pn > 0) {
    // Query for the schedule record
    var schedRec = new GlideRecord('cmn_schedule');
    schedRec.get('name', '8-5 weekdays excluding holidays');

    // Check if the schedule record exists and the GlideSchedule object is defined
    if (schedRec.isValid() && typeof GlideSchedule != 'undefined') {
        var sched = new GlideSchedule(schedRec.sys_id);
        var now = new GlideDateTime(); 
       
        // Debugging: Log the current date and time
        gs.info('Current date and time: ' + now.getDisplayValue());

        // Query for the incidents
        var gr = new GlideRecord('incident');
        gr.addQuery('incident_state', 6); 
        gr.query();

        // Check if the incident record exists
        if (gr.hasNext()) {
           gs.info('Number of resolved incidents: ' + gr.getRowCount());

            // Check if we are currently within the schedule window
            if (sched.whenNext(now, 'GMT') <= 0) {
                gs.info('We are in an active schedule window. Closing incidents...');
                while (gr.next()) {
                    var resolvedDate = new GlideDateTime(gr.resolved_at);

                    //Log the resolved date of the incident
                    gs.info('Resolved date for incident ' + gr.number + ': ' + resolvedDate.getDisplayValue());

                    // Calculate the due date based on resolved date and schedule
                    var dueDate = sched.add(resolvedDate, 10, '');

                    //Log the due date for the incident
                    gs.info('Due date for incident ' + gr.number + ': ' + dueDate.getDisplayValue());

                    Log the schedule end date for the incident
                    gs.info('Schedule end date for incident ' + gr.number + ': ' + getScheduleEndDate(resolvedDate, 7).getDisplayValue());

                    // Check if the due date falls within the schedule
                    if (sched.isInSchedule(dueDate)) {
                        // Close the incident
                        gr.state = 7; 
                        gr.active = false;
                        gr.update();
                        gs.info('Incident ' + gr.number + ' closed on ' + now.getDisplayValue());
                    } else {
                        gs.info('Incident ' + gr.number + ' due to be closed outside of schedule window.');
                    }
                }
            } else {
                var msUntilNext = sched.whenNext(now, 'GMT');
                gs.info('Not currently in schedule window. Next schedule starts in ' + msUntilNext + ' milliseconds.');

                  }
               }
        }
     }
 }

 

 

 

 

Thank you.. 😀

4 REPLIES 4

Tony Chatfield1
Kilo Patron

Hi, I would take a slightly different approach and simplify the solution by adding a new date/time field to your Incident or task table and use this to set a set a close date using a before BR based on your state field.
Your scheduled job then becomes a simple check for tasks that have a close date of yesterday - I assume the schedule will run daily just after midnight. I would think this was more efficient and also provides clear visibility to everyone involved as to when a specific task is expected to close.

Untested but something like

var startDate = new GlideDateTime();
var days = 10;
var busHours = 8.5;
var myDuration = new GlideDuration(60 * 60 * busHours * 1000 * days);
gs.info(myDuration);
var schedule = new GlideSchedule('090eecae0a0a0b260077e1dfa71da828');
var closeDate = schedule.add(startDate, myDuration);
gs.info('closeDate ' + closeDate);

current.yourAutoCloseDateField = closeDate;

 

var incCheck = new GlideRecord('incident');
incCheck.addEncodedQuery('yourAutoCloseDateFieldONYesterday@javascript&colon;gs.beginningOfYesterday()@javascript&colon;gs.endOfYesterday()');
incCheck.query();

while(incCheck.next()) {
incCheck.state = 7; 
incCheck.active = false;
incCheck.comments = 'Auto closed incident';
incCheck.update();
}

 

Sohail Khilji
Kilo Patron
Kilo Patron

Try this :

 

autoclose();

function autoclose() {	
    var gr = new GlideRecord('your_case_table');
    gr.addEncodedQuery('Your_query_means_resolved_case');
	gr.query();
    while (gr.next()) {
        var firstDT = gr.resolved_at;
        var scheduleID = gs.getProperty('24*5_Schedule');//You can change this with a sys_id of 24*5 schedule
        var cdate = gs.nowDateTime();
        var dc = new DurationCalculator();
        dc.setSchedule(scheduleID);
        var diff = dc.calcScheduleDuration(firstDT, cdate);
        //gs.info("amu:"+diff+gr.number);
        if(diff > 864000) //10 days==864000 seconds 
		{
            
            gr.state = 3;//You can check your close value
            gr.active = false;
            gr.comments = 'Case automatically closed after 10 business days in the Resolved state';
            gr.update();
        }
    }
}

☑️ Please mark responses as HELPFUL or ACCEPT SOLUTION to assist future users in finding the right solution....

LinkedIn - Lets Connect

ok, I did tested this out but do I need to change the default value for the below properties which is 7?

glide.ui.autoclose.time

 

Happy S
Tera Expert

Hi,
Just an update..

I tested out with the code below and somehow it is not working as expected where the incidents are still getting closed based on the value of the system properties - glide.ui.autoclose.time which is 10 calendar days..

 

Anything else that I missed out?

 

// This script automatically closes incidents that are resolved
// and haven't been updated in the specified number of days.
// This number is a property in System Properties.
// To place a comment in the incident, uncomment the "gr.comments" line.

autoCloseIncidents();

function autoCloseIncidents() {
    var ps = gs.getProperty('glide.ui.autoclose.time');
    var pn = parseInt(ps);
    var queryTime = new GlideDateTime();
    queryTime.addDaysUTC(-pn);
   	var i = 0;
	
    if (pn > 0) {
        var sched = new GlideSchedule('090eecae0a0a0b260077e1dfa71da828');

        var d = new GlideDateTime();
        var daycount = 1;
        var countday = 1;
        
        d.setDisplayValue(gs.daysAgoStart(countday).toString());

        do {
            if (sched.isInSchedule(d)) {
                gs.log(d.toString() + ' is in Schedule');
                countday++;
                daycount++;
            } else {
                gs.log(d.toString() + ' is not in Schedule');
                countday++;
            }

            d.setDisplayValue(gs.daysAgoStart(countday).toString());
        } while (!sched.isInSchedule(d) || daycount != pn);
        gs.log('Number of calendar days since Incident ticket resolution: ' + countday);
        gs.log('Date of resolved Incident tickets: ' + gs.daysAgoStart(countday));

        var gr = new GlideRecord('incident');
        gr.addQuery('state', '6');
		gr.addQuery('resolved_at', '<', d);
		
        if (gs.getProperty('com.snc.incident.autoclose.basedon.resolved_at', 'false') === 'true') {
            gr.addQuery('resolved_at', '<', queryTime);
        } else {
            gr.addQuery('sys_updated_on', '<', queryTime);
        }
        if (pm.isActive('com.snc.incident.mim')) {
            var mim = gr.addNullQuery('major_incident_state');
            mim.addOrCondition('major_incident_state', '!=', new 
            sn_major_inc_mgmt.MajorIncidentTriggerRulesSNC().MAJOR_INCIDENT_STATE.ACCEPTED);
        }
        if (pm.isActive('com.sn_ot_inc_mgmt')) {
            gr.addEncodedQuery('sys_class_nameNOT IN' + new TableUtils('sn_ot_incident').getAllExtensions().toArray().join());
        }

        gr.query();
        while (gr.next()) {
            i++;
            gs.info('Incident closed: ' + gr.number);
            gr.incident_state = IncidentState.CLOSED;
            gr.state = IncidentState.CLOSED;
            //gr.comments = 'Incident automatically closed after ' + pn + ' days in the Resolved state.';

            gr.active = false;
            gr.closed_by = gr.resolved_by;
	    gr.setWorkflow(false);
	    gr.update();

        }
           gs.log('Number of Incidents Closed:' + i);

	}
}