Assign a Task to Every User in a lane/group (independently)

1
0
-1

Hello,

I'm looking to have a signoff-like task assigned to every member returned by a particular filter. It's a review/signoff task, so each person needs to complete it independently. I don't know the number of people in advance, could be just one or dozens. I've seen lots of questions about a pool of users being able to do a task, but in that case, only one user actually does the task. I need all of the users to do the task concurrently.

Thanks!

Josiah

2 answers

1
+1
-1

@josiah

here is some sample you want to do the create task and then assign to a user, I've coddled together a couple of pieces of code so it won't work just as is. You should be able to do this all in one connector.

I had to leave you something to do :)

regards
Seán

PS: As this reply offers an answer your question, and if you like it, please Mark UP and/or as Resolved.

  1. import java.util.logging.Logger;
  2.  
  3. import org.bonitasoft.engine.api.ProcessAPI;
  4. import org.bonitasoft.engine.bpm.flownode.HumanTaskInstance
  5. import org.bonitasoft.engine.bpm.flownode.HumanTaskInstanceSearchDescriptor
  6. import org.bonitasoft.engine.bpm.process.ProcessInstance
  7. import org.bonitasoft.engine.search.SearchOptions
  8. import org.bonitasoft.engine.search.SearchOptionsBuilder
  9. import org.bonitasoft.engine.search.SearchResult
  10.  
  11. Logger logger = Logger.getLogger("org.bonitasoft");
  12.  
  13. ProcessAPI processApi = apiAccessor.getProcessAPI();
  14.  
  15. long processDefinitionId = processApi.getProcessDefinitionId("TestNoContract", "1.0");
  16.  
  17. Map<String, Serializable> processData = new HashMap<String, Serializable>();
  18.  
  19. ProcessInstance processInstance = processApi.startProcess(processDefinitionId, processData);
  20.  
  21. logger.severe("Process started: " + processInstance.getId());
  22.  
  23. //NEW CODE TO do the assignment immediately
  24. //Search by Name
  25. for(int p=0; p<10; p++){
  26.  
  27.  
  28. SearchOptionsBuilder searchOptionsBuilderHTName = new SearchOptionsBuilder(0, 100);
  29. searchOptionsBuilderHTName.filter(HumanTaskInstanceSearchDescriptor.NAME, "Step1");
  30. SearchOptions searchOptionsHTName = searchOptionsBuilderHTName.done();
  31. SearchResult<HumanTaskInstance> searchHumanTaskInstancesName = processApi.searchHumanTaskInstances(searchOptionsHTName);
  32. logger.severe("Number of tasks found: " + searchHumanTaskInstancesName.getCount());
  33. //Search by id
  34. SearchOptionsBuilder searchOptionsBuilderHTId = new SearchOptionsBuilder(0, 100);
  35. searchOptionsBuilderHTId.filter(HumanTaskInstanceSearchDescriptor.PROCESS_INSTANCE_ID, processInstance.getId());
  36. SearchOptions searchOptionsHTId = searchOptionsBuilderHTId.done();
  37. SearchResult<HumanTaskInstance> searchHumanTasIknstancesId = processApi.searchHumanTaskInstances(searchOptionsHTId);
  38. logger.severe("Number of tasks found #2: " + searchHumanTaskInstancesId.getCount());
  39.  
  40. Thread.sleep(1000);
  41. }

The above code starts the process and then searchs for the humantask

You then need to search for the actual Humantask you need:

  1. for (HumanTaskInstance pendingTask : searchHumanTaskInstancesId.getResult()) {
  2.  
  3. if (pendingTask.getParentProcessInstanceId().toString().equals(processProcessId[1].toString())){
  4.  
  5. if (pendingTask.getId()>activityId){
  6. activityId = pendingTask.getId();
  7. }
  8. }
  9. }

And once you have the activityId, assign the user:

  1. String bonUser = username; // walter.bates for example
  2. bonUser = bonUser.replace(" ", ".");
  3. userid = identityAPI.getUserByUserName(bonUser.toLowerCase());
  4. try{
  5. processAPI.assignUserTask(activityId, userid.getId());
  6. //and change the due date if required
  7. processAPI.updateDueDateOfTask(activityId, dueDate); //otherwise c?
  8. }

Comments

Submitted by josiah.raiche on Wed, 05/03/2017 - 14:35

Thanks for that. Couple questions, if you don't mind. I'm going to call my process the signoff process, which all users in a list need to do.

  1. Does this require the signoff process to be in a separate process/pool from the main flow? Is that what the processAPI.startProcess() does?
  2. If tasks are created programmatically, how does control go back to the main pool once they are all complete?
  3. What does the for loop do? Do I need to check for changes every second for 10 seconds, or should I just wait 10 seconds at the beginning?
  4. Do I need to search by both task id and name, or is that a "pick one of these ways" thing?

Thanks so much! Josiah

Submitted by Sean McP on Wed, 05/03/2017 - 22:56

And now you hit the process design problem.

Do you really need a variable number of approvals before a final sign-off, which is what is indicated from your questions?

processAPI.startProcess() starts a brand new process, not connected to the originator process (apart from the startProcess).

so 1) Yes.

2) they don't, you'll need to design something to do this.

3) which for there are two:

for(int p=0; p<10; p++){ and
for (HumanTaskInstance pendingTask : searchHumanTaskInstancesId.getResult()) {

the former is not necessary, as I said you have to work out your own code...this is what we use for our reason.

the other for loop

has to read through ALL the human tasks to find the specific one you want.

4) this is old code and to be honest we're looking at it now as we're moving to 7 from 6. There are somethings that will change I'm sure. At the time it's what we researched, what we needed and what worked. If there's a better way we'll use that.

I've given you the building blocks, now you have to do your work for you, sorry, but I'm not being paid by your company...I'm not being paid by mine for that matter...

Submitted by Sean McP on Thu, 05/04/2017 - 07:03

I've been thinking about this most of the day and have thought of it from a manual point of view:

1) request is made to HR
2) HR send variable number of approval requests
3) HR receive approvals in dribs and drabs and check if all complete (imagine person x saying have i got them all - No, have i got them all - No, have i got them all - No, have i got them all - Yes)
4) when complete then send for final approval

So what you want to do is mimic this as follows:

1) request is made to System
2) System send variable number of approval requests (using startProcess()) and Creates a unique semaphore variable count = number of approval requests (saved as BDM?)
3) the Approval Request process does it's stuff (what happens when someone doesn't do the job - very important) and then starts a semaphore-count process (via startProcess()) (need to determine the correct fields/indexes/data to pass in the message)
4) the semaphore-count process receive approvals in dribs and drabs and reduces the outstanding count of approvals until zero when it then sends (via startProcess()) for final approval.

So you end up with

process 1 - the request which startProcess() variable number of approval requests
process 2 - the approval request startProcess() the semaphore-Count process
process 3 - the semaphore-Count process counts approvals until complete and then starts the final approval process
process 4 - the final approval does its stuff till end

You could timer the main process, stopping execution until approvals are in and then the semaphore-Count process could send a message the main process to restart...use signals and messaging as required.

regards
Seán

PS: Semaphores - very powerful constructs and the best way to deal with this type of activity - using them shows real software-engineering skills

PPS: a good reference on everything BPMN https://camunda.org/bpmn/reference/

PPPS: if you design the semaphore-Count process properly you'll be able to use it for many different processes

Submitted by josiah.raiche on Thu, 05/11/2017 - 14:12

@SeanMcP, thanks so much for all your help. It is surprising to me that this isn't a common business requirement. I'm attempting to help my organization choose a BPM tool by building out a project that is an IT request workflow. Essentially I'm trying to build a workflow to automate the process of requirements gathering, scoping, and financials. In this process, stakeholders and the product owner need to signoff on the requirements documentation prior to moving on to formal charter/scoping. Of course, the number of stakeholders can be literally anything - maybe 0 or maybe a couple dozen, depending on the project.

I would have thought this would be common business process that would be built into the underlying engine, but it seems to be rather complex.

I think that the semaphore is the way to go. I believe the method would be to assign the signoff task a uuid. Fork the subprocesses. Then create a record in a bonita-semaphore table with the uuid and the number of processes required. For each person who signs off yes or no, insert a record into another bonita-signoff table. From the main script, check on a schedule until the COUNT(signoffs) hits the target or someone declines to signoff (COUNT(signoff_failures) > 0) or a threshold % decline it (COUNT(signoff_failures) > COUNT(signoffs)/10) . Once that condition occurs, set a bonita process variable with the number of people who didn't sign off, and continue as normal using conditions to control where the process goes next.

Unfortunately, I think this would require a fairly detailed understanding of the bonita engine to get it to work. I'm also not fluent in Java yet (I'm mostly a front end web developer). So I'll have to revisit this at a later date.

Thanks for all your help!

Josiah

Submitted by Sean McP on Thu, 05/11/2017 - 22:11

@josiah, pleasure to help someone who has a real recognition of the issues...

BPM though is a funny beast - the BPM standard says BPM processes should be clearly defined to work properly.

The sending of an email is clearly defined, and not an issue - but sending an email to a variable number of people and expecting a variable number of returns (at the gateway) before continuing breaks this clear definition rule.

Yes it is a common business process but what people find is it is easier to redesign the process rather than implement a process that's already in place. And isn't that the point of doing a BPM (re-)engineering exercise? To make things simpler...

We had six RFP streams with anywhere between 5 and 15 sign-offs including the Board of Directors. and because they were also value based we ended up with something like 1,300 different rules on where, what, when and how...ridiculous.

So we redesigned the whole process, with management, and in the end implemented a simple sequential model with stricter management controls on building the early stages (RFP, ROI model etc.). It took a while and management guts but we cut the 1,300 different rule down to 7 (I think). We gave people responsibility and accountability and the process worked, there were always exceptions but these were handled by exception rules we built in to the process.

One thing to remember and maybe you can discuss this with management when discussing the redesign of the process is:

There can be many people RESPONSIBLE for delivering a piece (or pieces) of work, but there can only be one that is ACCOUNTABLE for delivering the work, and it is the person that is Accountable that should be one the chain... search for RACI if you've not come across the term and use this to build your process.

That being said I'm using semaphore on a project I'm working on, but it is a different kind of project...

you could use a UUID we just use the process name along with the case number...much easier to read when needing to look things up :)

Regarding your comment:

Unfortunately, I think this would require a fairly detailed understanding of the bonita engine to get it to work

Not true, it's only the process you need to think about, not the engine, it will take care of itself. And thinking about it this would make a great How-To...a weekends work.

And as for Java - I only knew it was a language when I started Bonitasoft, still only use 5% of the language and don't need more than a basic skill of understanding of how to program.

regards
Seán

1
+1
-1

You need an instance of the task created per user - which you can do with iteration.
Then either assign the tasks to the relevant users explicitly and/or provide a custom user filter.

I think I would do this with a service task that populates a process array variable with the list of users, then an iterated call task to spawn the multiple instances you need; one for each entry in the array.

Comments

Submitted by josiah.raiche on Wed, 04/19/2017 - 19:59

That sounds promising. I'll give it a try.

Submitted by Sean McP on Wed, 04/19/2017 - 21:06

Chris describes exactly the way we do it as well, or did I give him the idea before :)

  1. get the list of names
  2. multi-Instantiate the Start Process
  3. Start and Assign the process to each user
  4. Send an email to each user asking for them to complete their task

Don't forget to add a boundary timer for those approval tasks that do not get completed in an appropriate amount of time, managers go on holiday too so I'm told.

regards

Submitted by josiah.raiche on Tue, 05/02/2017 - 18:13

@Sean and/or Chris, can you give or point me to a bit more detail on how to accomplish this? I've got the list of names, and I can multi instantiate the task (parallel instantiation) but I'm not sure how to assign an actor to the task programmatically, either in the UI or via a groovy script. Can you give some more guidance? Thanks!

Submitted by josiah.raiche on Tue, 05/02/2017 - 18:13

@Sean and/or Chris, can you give or point me to a bit more detail on how to accomplish this? I've got the list of names, and I can multi instantiate the task (parallel instantiation) but I'm not sure how to assign an actor to the task programmatically, either in the UI or via a groovy script. Can you give some more guidance? Thanks!

Testing
Notifications