Timers - how to force a timer to go through before the end

brandong
Kilo Contributor

Hello everyone,

  I currently have a workflow the leverages 1 day timers which after 1 day, it checks to see if a field is populated, then creates a task if it is. Let's say that field is populated within the first 3 hours of that timer, how can we force the timer to end without having to wait another 21 hours?  Thank you for the help.

1 ACCEPTED SOLUTION

you have to create 1

UI Action

Name: Skip Timer

Table: Requested Item

Client: False

/*
* 1. In order for this script to work, the UI action must be on the Requested Item table.
* 2. on the sys_trigger table, there is a field "Upgrade Safe"   which is a true/false field.   It's "writable" only by the role of "maint"   which is a ServiceNow Employee role.
You need to edit the security of that role and allow whatever role needed to write to that field.

* 3. With this being a restricted field, it's probably not best practice to edit it, and after an upgrade it may be affected where the UI Action doesn't work anymore.
*/


ReclaimAllDevices();


function ReclaimAllDevices() {
	//how much time do you want to add to the timer from now.   Expiration will be right now + newSeconds.
	var newSeconds = 30;

	var ID = current.sys_id;
	//get the workflow context id for the current request item.
	//i'm using this for a very specific timer, so i only want 1 result.   if you want more, change the if to a while
	var context = new GlideRecord("wf_context");
	context.addQuery("id", ID);
	context.query();
	if(context.next()){

		// find the specific executing activity from the context above.
		var time = new GlideRecord("wf_executing");
		time.addQuery('context', context.sys_id);
		time.addQuery('stage', 'loan');
		time.query();
		if(time.next()){

			//set the name for the workflow timer
			var WFTimer = "WFTimer" + time.sys_id;

			//search the sys_trigger table for the current timer
			var schedule = new GlideRecord("sys_trigger");
			schedule.addQuery("name", WFTimer);
			schedule.query();
			if(schedule.next()){
				var curTime = schedule.next_action.getDisplayValue();

				var gdt = new GlideDateTime();
				gdt.addSeconds(newSeconds);
				schedule.next_action = gdt;

				var schedDisp = schedule.next_action.getDisplayValue();
				schedule.update();

				gs.addInfoMessage("<br><br><br><br><center><font size = 5>You have chosen to end the timer NOW<br>Timer will now expire at: </font><font size= 5 color='ff0000'>" + schedDisp + "</font><font size=5><br><br> which is " + newSeconds + " seconds from now.</font></center><br><br><br><br>");

				current.work_notes = "Time has been expired early.\nTimer will now be expired at: '" + schedDisp + "'   instead of '" + curTime + "'.";
				current.update();
			}
		}
	}
	action.setRedirectURL(current);
}

View solution in original post

8 REPLIES 8

sure, that works great. Is that button already there and I just missed it due to lack of knowledge or is this something that will need to be added to the RITM form?

you have to create 1

UI Action

Name: Skip Timer

Table: Requested Item

Client: False

/*
* 1. In order for this script to work, the UI action must be on the Requested Item table.
* 2. on the sys_trigger table, there is a field "Upgrade Safe"   which is a true/false field.   It's "writable" only by the role of "maint"   which is a ServiceNow Employee role.
You need to edit the security of that role and allow whatever role needed to write to that field.

* 3. With this being a restricted field, it's probably not best practice to edit it, and after an upgrade it may be affected where the UI Action doesn't work anymore.
*/


ReclaimAllDevices();


function ReclaimAllDevices() {
	//how much time do you want to add to the timer from now.   Expiration will be right now + newSeconds.
	var newSeconds = 30;

	var ID = current.sys_id;
	//get the workflow context id for the current request item.
	//i'm using this for a very specific timer, so i only want 1 result.   if you want more, change the if to a while
	var context = new GlideRecord("wf_context");
	context.addQuery("id", ID);
	context.query();
	if(context.next()){

		// find the specific executing activity from the context above.
		var time = new GlideRecord("wf_executing");
		time.addQuery('context', context.sys_id);
		time.addQuery('stage', 'loan');
		time.query();
		if(time.next()){

			//set the name for the workflow timer
			var WFTimer = "WFTimer" + time.sys_id;

			//search the sys_trigger table for the current timer
			var schedule = new GlideRecord("sys_trigger");
			schedule.addQuery("name", WFTimer);
			schedule.query();
			if(schedule.next()){
				var curTime = schedule.next_action.getDisplayValue();

				var gdt = new GlideDateTime();
				gdt.addSeconds(newSeconds);
				schedule.next_action = gdt;

				var schedDisp = schedule.next_action.getDisplayValue();
				schedule.update();

				gs.addInfoMessage("<br><br><br><br><center><font size = 5>You have chosen to end the timer NOW<br>Timer will now expire at: </font><font size= 5 color='ff0000'>" + schedDisp + "</font><font size=5><br><br> which is " + newSeconds + " seconds from now.</font></center><br><br><br><br>");

				current.work_notes = "Time has been expired early.\nTimer will now be expired at: '" + schedDisp + "'   instead of '" + curTime + "'.";
				current.update();
			}
		}
	}
	action.setRedirectURL(current);
}

Thank you. Unfortunately i am a delegated admin and my ability to script is severely limited. However, I should be able to present this to our development team to have them implement. Thank you very much.

hunter_phillips
Tera Contributor

It sounds like your workflow could use a 'Wait for Condition' activity

So it would use a 'branch' to do 2 things in parallel:

1. Wait For the field to be populated > once populated, continue through workflow

2. use a 1 day timer to wait and check if 'field still not populated' > do stuff


If 1 is triggered before 2, the workflow continues on as normal and #2 never happens (bc the check fails). Else the 2nd branch continues along until the field is populated.