Announcing the Global SNUG Board of Directors. Learn more here

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Pending to Active state based on Due Date

scwillson
Tera Expert

I feel as though this should be a simple task but I am not proficient at scripting yet. I've not found anything quite spelling it out for me as to how to script it well.

Background

I have a workflow running on the Incident table who's purpose is to stop the SLA clock from running until the due date is met; at which point it clears the due date and sets the INC back to active.

Issue

The problem comes in when someone changes the 'Due Date'   value to something else. The workflow still waits for the original date to continue with the workflow.

Goal

I wanted put some script to look at the 'Due Date' with the OnChange condition. to fix the problem. Or possibly use the 'Wait for Condition' action instead of the regular timer, because "The workflow evaluates the wait for condition each time the current record is updated." which would make the Due Date field be checked to make sure it still has the same due date.


any help would be very much appreciated. let me know if you need more detail to understand the issue.

1 ACCEPTED SOLUTION

scwillson
Tera Expert

I've been able to piece together a solution, thanks to some code posted by Dan Patino here.


Hopefully someone else will find this helpful.



I setup a business rule to run on the Task table, on updates when the due_date changes.



The parts of this code to enter in your own data are on lines 3 and 35.


var PAtimer = retrieveTriggerRecord('NAME OF TIMER');  


NAME OF TIMER is literally just the name given to the timer action you want to be updated.



var newDT = new GlideDateTime(DATE FIELD);


DATE FIELD - I just put in the date field from the task table; current.due_date.getDisplayValue()



Here's the code in its entirety:



function onAfter(current, previous) {  


        //Reschedule Pending to Active timer  


        var PAtimer = retrieveTriggerRecord('NAME OF TIMER');  


        if(PAtimer != 'none')  


        rescheduleNextAction(PAtimer);



        function retrieveTriggerRecord(timer){  


        //Find the workflow context record


        var grContext = new GlideRecord("wf_context");


        grContext.addQuery('id',current.sys_id);


        grContext.query();


        if(!grContext.next())


                  return 'none';


   


        //Find the Workflow Executing record


        var grExecuting = new GlideRecord("wf_executing");


        grExecuting.addQuery("context", grContext.sys_id);


        grExecuting.addQuery("activity.name", timer);


        grExecuting.addQuery("activity.activity_definition.name", 'Timer');


        grExecuting.query();


        if (!grExecuting.next())


                  return 'none';


   


        //Find the sys_trigger record


        var grTrigger = new GlideRecord("sys_trigger");


        grTrigger.addQuery("name", 'WFTimer' + grExecuting.sys_id.toString());


        grTrigger.query();


        if (grTrigger.next())


                  return grTrigger;


        else


                  return 'none';


        }  



        function rescheduleNextAction(trigger){


        var newDT = new GlideDateTime(DATE FIELD);


        trigger.next_action = newDT.toString();


        trigger.update();


        }


}


View solution in original post

8 REPLIES 8

manikorada
ServiceNow Employee
ServiceNow Employee

Simon,



I will have my couple of suggestions here:



1. When there is a timer activity running for a workflow, there will a job running in sys_trigger table which will invoke the Workflow whenever the timer ends. The record in sys_trigger will have name some thing like :



WFTimer06c9501574d79100178ea0568d3fab9d



In the above line '06c9501574d79100178ea0568d3fab9d' is sys_id of the Timer Activity which is being executed/waiting at that time. Thats how is know which workflow/timer activity needs to invoked whenever timer ends.


In the sys_trigger job, there will be another field called 'Next Action' which tells us the date and time the sys_trigger job needs to be run.



In your case what you can do is whenever Due date is changing you can have a business rule which updates the above sys_trigger job's Next Action to what ever date you need. You can uniquely identify the job using the sys_id of the Workflow Timer activity which you can get by querying the workflow context and there by querying the Workflow Executing Activities table.


But the above option has a disadvantage, when your workflows grow eventually when you do a GlideRecord on that table because of huge number that might cause performance issues later on.



2. Another Solution is, if the First activity of the Workflow is timer and the workflow is waiting for that timer to be done. You can have business rule whenever due date is changing which will delete the workflow context previously attached to the RITM and invoke a new Workflow with your desired due date.



3. Another solution will be implementing something other than timer activity. Its like you will have a custom field on the Incident like a flag. The workflow will wait for the flag to be true to move forward and you can have have a business rule which will create a entry in the sys_trigger job with Next Action as your due date and the script in the sys_trigger will update that flag.


Something like:


var newTrigger = new GlideRecord("sys_trigger");


newTrigger.name = 'Incident Timer - ' + current.number + ' - ' + current.sys_id; // This is to uniquely identify the sys_trigger job to update later


newTrigger.next_action = current.due_date; // Set the Next Action to Due Date


newTrigger.document = 'incident';


newTrigger.document_key = current.sys_id;


newTrigger.script = "var inc = new GlideRecord('incident'); inc.addQuery('sys_id', '" + current.sys_id + "'); inc.query(); if (inc.next()) { inc.u_wait = true; inc.update();}"; // Field u_wait is the flag


newTrigger.job_id.setDisplayValue('RunScriptJob');


newTrigger.trigger_type = 0;


newTrigger.insert();



Now if the Due Date is changing you can have a business rule which can query the sys_trigger using the uniquely identified name and update the Next Action with what ever date you like.


Thanks Mani,



This is great information to know, regarding the sys_trigger table. I think I am going to implement the first suggestion, however I am not so good at scripting. I have started the business rule to run when the 'due date' field is changed, but I do not know how to write the code for:


You can uniquely identify the job using the sys_id of the Workflow Timer activity which you can get by querying the workflow context and there by querying the Workflow Executing Activities table.


For example, in a before update business rule, you want to check out any business rule that's script contains sys_trigger:



var nowdt = new GlideDateTime();


nowdt.setDisplayValue(current.due_date);



var gr = new GlideRecord("sys_trigger");


gr.name = current.number + " State Movement";


gr.next_action = nowdt;


gr.trigger_type = 0;// sys_trigger type Run Once

gr.job_context = "Auto created schedule job for moving the state based on due date of " + current.number;


gr.script = "current.state = <your state value>; current.update();";


gr.insert();


The business rule:   onBefore insert or update


Capture.PNG


The incident created:


Capture.PNG


The sys_trigger automatically created from the business rule:


Capture2.PNG