Fórumok

Complete current workflow task as timer action

thumbnail
Willem Vermeer, módosítva 10 év-val korábban

Complete current workflow task as timer action

Junior Member Bejegyzések: 32 Csatlakozás dátuma: 2012.03.30. Legújabb bejegyzések
Hi,

I'm investigating the new timer feature in workflows. It's possible to use the reassign feature to reassign the current task to another role or user when the timer fires. That's fine.

However I would like to complete the current open workflow task when the timer fires. Is this possible and would there be any side effects? The XML definition does not provde any clues in this direction.

One of the problems I see is that it's not easy to get to the current task, not even in the workflow handler, because the workflowcontext contains no reference to the current task. So I'm thinking along the following lines:
- use a script task to lookup the current workflow task (use WorkflowInstanceManagerUtil.getWorkflowInstances and WorkflowTaskManagerUtil.getWorkflowTasksByWorkflowInstance)
- invoke WorkflowTaskManagerUtil.completeWorkflowTask
but I'm afraid it will trip up the workflow management process if I try to complete a task for which we just received the timer completion event.

Any comments/hints/ideas?

Thanks
Willem
thumbnail
Beatriz Valdés Suárez, módosítva 10 év-val korábban

RE: Complete current workflow task as timer action

Junior Member Bejegyzések: 50 Csatlakozás dátuma: 2014.03.31. Legújabb bejegyzések
Hi Willem

i have the same problem. how did you solved it?
thumbnail
Willem Vermeer, módosítva 10 év-val korábban

RE: Complete current workflow task as timer action

Junior Member Bejegyzések: 32 Csatlakozás dátuma: 2012.03.30. Legújabb bejegyzések
Hi Beatriz,

I'm sorry to say we never solved it. The requirement was dropped and I didn't spend more time on it, nor did I receive any hints through the forum.

We've built a screen where we order the pending workflow tasks by create date, oldest tasks on top. On that screen the admin role can easily see which taks need attention because they have been open for too long. But of course that's a suboptimal situation, I'd much rather have received a notification directly from the workflow.

Maybe 6.2 will help us :-)

Good luck, regards,
Willem
thumbnail
Beatriz Valdés Suárez, módosítva 10 év-val korábban

RE: Complete current workflow task as timer action

Junior Member Bejegyzések: 50 Csatlakozás dátuma: 2014.03.31. Legújabb bejegyzések
Thanks Willem!
I'll have to find an alternative solution.

Best regards
Beatriz
Balázs Csönge, módosítva 9 év-val korábban

RE: Complete current workflow task as timer action

Regular Member Bejegyzések: 107 Csatlakozás dátuma: 2014.11.10. Legújabb bejegyzések
Hi,
I am brand new in Liferay and Kaleo topic. The solution what we have to develop needs a 2 step approval flow and the 2nd approval step has to be finished automatically after a specific time if task is ignored by the user. So I meet your problem, how can I finish a task automatically via a timer action.
Started searching the net for the solution, I found this topic too, but had no real, correct answer anywhere. I wanted write some rude thing here about the liferay "documentation", but I decided to skip it...emoticon
I saw I have to use WorkflowTaskManagerUtil.completeWorkflowTask method, and it had one magical parameter, the long workflowTaskId. I started examining the liferay database tables in ORACLE, in order to find out what collerate with what and where this task ID is hidding.

First brute force ide was to select it like this:
row = sql.firstRow("select max(T.KALEOTASKID) from kaleotask t where T.NAME='review2'")
long taskID = row[0]
WorkflowTaskManagerUtil.completeWorkflowTask(companyId, userId, taskID, "Approve", "Time has come", workflowContext)

But it not worked, I got the exception No KaleoTaskInstanceToken exists with the primary key 12846. Ok, I realized I have to find other ID not the node ID of the flow definition ,but the ID of the node instance of the running flow instance. I figured out how can I get the WorkflowInstanceId via the API, but starved how to find the needed ID using API too for that completeWorkflowTask method. I did a brute force select again:
sql = Sql.newInstance("jdbc:oracle:thin:@ipaddress:1521:dbname", "user",
"pwd", "oracle.jdbc.OracleDriver")
row = sql.firstRow("select MAX(K.KALEOINSTANCETOKENID) from KALEOINSTANCETOKEN k where K.KALEOINSTANCEID = ?:kiid and K.CURRENTKALEONODENAME='review2'",[kiid:wfiID])
long taskID = row[0]

Finally I get the right ID, and got another exception about I not allowed to complete a task which is not assigned to the single user.
Maybe liferay developers heared a voice at this point "Nuclear launch detected...".emoticon
At this point I saw I would have to use assignWorkflowTaskToUser method too, so must figure out the proper way using API for all steps, and forget direct SQL selects.
I did it (will be shown later), so made a timer and an action which getting the task, checking is it assigned to a single user or not, if not, it assigns the task for a user, then call the complete method.
Next punch came here. Task initiated the assign step, did it, but did not completed the task.

Just a tip, maybe engine leaving the script execution at the assigment point or something. No idea, no documentation, just a tip. So I decided I will make 2 timers. First will reassign the task to a single user (using only workflow xml tags, not coding anything), then a second timer after some second will do the complete step. And it worked fine. One remark, I thought timers will be initiated in order how they found in workflow xml, and second timer delay value is counting after the first timed task finish. But not, all corellated from the same starting time (when flow arrives to the task I think).

So the needed part of the flow is (I hope it will help anybody who had to do same thing):
        <task-timers>
            <task-timer>
                <name>FirstTimer</name>
                <delay>
		          <duration>1</duration>
		          <scale>minute</scale>
		         </delay>
		         <timer-actions>
		         	<timer-notification>
		         		<name>FirstTimerNoti</name>
		         		<template>Second level revision deadline has come. This task was reassigned to the default user (default@liferay.com) in order to automatically complete it.</template>
		         		<template-language>freemarker</template-language>
		         		<notification-type>email</notification-type>
						<recipients>
							<user />
						</recipients>
		         	</timer-notification>
		         	<reassignments>
		         		<user>
		         			<email-address>default@liferay.com</email-address>
		         		</user>
		         	</reassignments>
		         </timer-actions>
            </task-timer>
            <task-timer>
                <name>SecondTimer</name>
                <delay>
		          <duration>65</duration>
		          <scale>second</scale>
		         </delay>
		         <timer-actions>
				    <timer-action>
				    	<name>timedStatusChange1</name>
		                <script> <![CDATA[
import com.liferay.portal.kernel.concurrent.ThreadPoolExecutor.WorkerTask;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.util.GetterUtil
import com.liferay.portal.kernel.workflow.WorkflowConstants
import com.liferay.portal.service.CompanyLocalServiceUtil
import com.liferay.portal.service.GroupLocalServiceUtil
import com.liferay.portal.service.UserLocalServiceUtil
import com.liferay.portal.service.WorkflowInstanceLinkLocalServiceUtil
import com.liferay.portal.model.WorkflowInstanceLink
import com.liferay.portal.kernel.workflow.WorkflowInstanceManagerUtil
import com.liferay.portal.kernel.workflow.WorkflowTask;
import com.liferay.portal.kernel.workflow.WorkflowTaskManagerUtil

long companyId = GetterUtil.getLong((String)workflowContext.get(WorkflowConstants.CONTEXT_COMPANY_ID))
long userId = GetterUtil.getLong((String)workflowContext.get(WorkflowConstants.CONTEXT_USER_ID))
long groupId = GetterUtil.getLong((String)workflowContext.get(WorkflowConstants.CONTEXT_GROUP_ID))

String className = (String)workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_NAME);
long classPK = GetterUtil.getLong((String)workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));

WorkflowInstanceLink workflowInstanceLink = WorkflowInstanceLinkLocalServiceUtil.getWorkflowInstanceLink(companyId, groupId, className, classPK);
long wfilID = workflowInstanceLink.getWorkflowInstanceLinkId();
long wfiID = workflowInstanceLink.getWorkflowInstanceId();

WorkflowTask thisTask = null;

List<WorkflowTask> taskok = WorkflowTaskManagerUtil.getWorkflowTasksByWorkflowInstance(companyId, null, wfiID, true, QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
for (task in taskok) {
	if(task.getName().equalsIgnoreCase("review2")){
		thisTask = task;
		break;
	}
}
if (thisTask==null) {
	List<WorkflowTask> taskok2 = WorkflowTaskManagerUtil.getWorkflowTasksByWorkflowInstance(companyId, null, wfiID, false, QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
	for (task2 in taskok2) {
		if(task2.getName().equalsIgnoreCase("review2")){
			thisTask = task2;
			break;
		}
	}
}
long taskID = thisTask.getWorkflowTaskId();
println "taskID(KALEOINSTANCETOKENID): " + taskID;
println "isAssignedToSingleUse: " + thisTask.isAssignedToSingleUser();
println "completeWorkflowTask...";
WorkflowTaskManagerUtil.completeWorkflowTask(companyId, userId, taskID, "Approve", "2nd level revision deadline had come. Task had been closed automatically.", workflowContext);

					]]> </script>
				<script-language>groovy</script-language>
				    </timer-action>
				</timer-actions>
            </task-timer>
        </task-timers>
        <transitions>
            <transition>
                <name>Reject</name>
                <target>rejected</target>
            </transition>
            <transition>
                <name>Approve</name>
                <target>approved</target>
            </transition>
            <transition>
                <name>Modification request</name>
                <target>update</target>
            </transition>
        </transitions>
Balázs Csönge, módosítva 9 év-val korábban

RE: Complete current workflow task as timer action

Regular Member Bejegyzések: 107 Csatlakozás dátuma: 2014.11.10. Legújabb bejegyzések
One more remark.
I used a trial version of the developer studio, which functionality halfly made. For example, you can add a timer to a task, but you cannot specify any parameter of it. It adds a main tag into the xml with only the timer name, and right after it shows an error, because xml not valid via the xsd.
<task-timer>
<name>Something</name>
</task-timer>
So you must use only Source panel to make this xml section of the flow.
If your finish the edition and made a <timer-action>, then it will show an error about Execution type must be specified. It must be a bug, because xsd not let u define execution-type tag fo this action type. But don't afraid, independently this error, your xml can be uploaded into the liferay, and it can be run correctly.