Parallel flow -> multiple Approval Activity skipping

bryanjurgensmey
Kilo Contributor

Here's my use case:

When a new record is added to pc_software_cat_item run an Approval Activity for each Company using our instance.   If approved the item is added to their employee user criteria so that it becomes available in Portal.   Each company can choose to approve or deny and they're independent of each other.

The issue:

I can create ~20 stand-alone workflows (1 per company) and it works, however, ideally this would be dynamic and just need 1 workflow that accepts param's for the approval group and user criteria record.  

This seemed like a good use case for Parallel Flow so I created a workflow (New Catalog Item Approval - Parent) that runs a Parallel Flow Launcher for my approval workflow (New Catalog Item Approval).   I'm triggering this with an on-after business rule and passing an input with the array containing an approval group and the user criteria record from the parent workflow to the approval workflow.   This works and the inputs are correctly passed, however, only 1 instance of the approval activity will hold 'executing' and the rest just skip (attached).   The skipped workflows are receiving correct inputs.

I added the timer, which does seem to occasionally allow more than 1 flow to stay executing but I have no idea why that helps.

Any idea's why this is failing?

19 REPLIES 19

shawna
Tera Guru

I am having the same issue. Did you ever manage to get it resolved?


davidnovak
Tera Contributor

Hello all,


i am in process of implementing entirely same functionality as you describe and getting exactly same result.



Did anybody manage to solve this somehow?


dennismagnuson
Kilo Expert

Sooo, yes. I had the same problem and was finally able to get around it.

Unfortunately and undocumented, the Approvals in a Sublfow react the same as Tasks. See the docs for Subflows and Create Task Activity.

In our scenario, the user can request multiple roles with each role having it's own approval and fulfillment task for audit purposes. As the Request has a one to many to Requested Items, we did this as one Requested Item to many (Approvals and Tasks) with the subflow.

 

I was lucky enough to use the Parallel Flow with a Sub that was just executing Tasks. Using the suggestion of creatiing the Task using the Run Script activity I was able to achieve what I wanted. When I ran into the issue with a Subflow that had both an Approval and a Task, with the Approvals only generating one, I assumed the Approval record had to be created using the Run Script too.

And yes, that solved the issue. When the Approval record gets updated, it "nudges" the workflow which causes the next step, a Wait for Condition, to check if it needs to continue. The Wait for is scripted to check for associated approvals, store the state to the scratchpad for later checking and then mark any other approval as no longer required, just for that particular flow.

Maybe the pictures and code will help tell the story better.

find_real_file.png

 

The Run Script to create the Approval records, where the parent Requested Item record is passed to the Input u_request_item and after you save the necessary approvers to the role_approvers array is this:

workflow.scratchpad.approvals = [];

for(var i=0; i<role_approvers.length; i++){
	var new_app = setApproval(role_approvers[i]);
	workflow.scratchpad.approvals.push(new_app +'');
}

function setApproval(app_id){
	var app_rec = new GlideRecord('sysapproval_approver');
	app_rec.initialize();
	app_rec.sysapproval = workflow.inputs.u_request_item;
	app_rec.document_id = workflow.inputs.u_request_item;
	app_rec.source_table = 'sc_req_item';
	app_rec.approver = app_id;
	app_rec.approval_column = 'approval';
	app_rec.approval_journal_column = 'approval_history';
	app_rec.state = 'requested';
	return app_rec.insert();	
}

From there, the Wait for Condition it's scripted as such:

// Set the variable 'answer' to true or false to indicate if the condition has been met or not.
var app_recs = workflow.scratchpad.approvals;
var app_state = 'requested';
var check;

for(var i=0; i<app_recs.length; i++){
   check = getAppState(app_recs[i]);
	if(check == 'approved' || check == 'rejected'){
		app_state = check;

		//Store approval state for later check in workflow
		workflow.scratchpad.app_state = app_state;
	}
}

if(app_state != 'requested' && app_recs.length > 1){
	for(varj=0; j<app_recs.length; j++){
		updAppState(app_recs[j]);
	}
}

function getAppState(id){
	var gr = new GlideRecord('sysapproval_approver');
	gr.get(id);
	return gr.state;
}

function updAppState(id){
	var ga = new GlideRecord('sysapproval_approver');
	ga.get(id);
	if(ga.state == 'requested'){
		ga.state = 'not_required';
		ga.update();
	}
}

if(app_state != 'requested'){
	answer = true;
}
else{
	answer = false;
}

And no, a rejection of one separate approval won't set the overall Requested Item as rejected. Actually, I don't have anything setup to mark the Requested Item as Rejected if all individual approvals are rejected. Maybe save that for future enhancement.

Hopefully this helps and if you have any other questions, feel free to ask.

Dennis

 

Thanks dennismagnuson!

This is a very helpful solution to approvals in parallel flows. I ended up expanding this solution to be able to handle if it was given a group and found a small bug in the Wait for script. It was just missing a space in the variable declaration of 'j' in the section to update the other related approvals. I also am working on adding the approve/reject paths to the wait for. If someone asks I may post that part of my solution as well.

Modified the Run Script to include processing for the groups:

workflow.scratchpad.approvals = [];

for(var i=0; i<role_approver.length; i++){
	var grp = new GlideRecord('sys_user_grmember');
	grp.addQuery('group',role_approver[i]);
	grp.query();
	if (grp.hasNext()){
		while (grp.next()){
			var new_app = setApproval(grp.user);
			workflow.scratchpad.approvals.push(new_app +'');
		}
	} else {
		var new_app = setApproval(role_approver[i]);
		workflow.scratchpad.approvals.push(new_app +'');
	}
}
function setApproval(app_id){
...
}