D365: Workflow避免同一审核人多次审批
D365中当一个员工身居多职或者承担多个角色时,针对这样的场景,我们在配置审批流过程当中,难免会遇到,在配置的审批节点时,同一个人会出现在多个审批节点中,用户就会出现,同一张单需要进行多次审批,为了避免这种情况,需要通过对标准的审批流进行二次开发,涉及的开发主要需要扩展两个关键的类
1,SysWorkflowWorkItem
由于需要调用标准的SysWorkflowWorkItem的静态方法create来创建工作项,但是create方法又是private的,所以我们只能利用反射的机制来进行调用
using System.Reflection;
[ExtensionOf(classStr(SysWorkflowWorkItem))]
final class SysWorkflowWorkItemVya_Extension
{
public void callCreateWorkItems(Microsoft.Dynamics.AX.Framework.Workflow.Runtime.WorkItemActivityContext _workItemActivityContext,
WorkflowWorkItemClaimed _isClaimed,
Delimiter _workflowDelimiter = ',')
{
//int n;
//设置方法参数
System.Object[] parametersArray = new System.Object[3]();
parametersArray.SetValue(_workItemActivityContext, 0);
parametersArray.SetValue(_isClaimed, 1);
parametersArray.SetValue(_workflowDelimiter, 2);
var bindFlags = BindingFlags::NonPublic | BindingFlags::Static;
System.Type type = this.GetType();
var methodsInfo = type.GetMethods(bindFlags);
for (int n = 0; n < methodsInfo.get_Length(); n++)
{
System.Reflection.MethodInfo methodInfo = methodsInfo.getValue(n);
if (methodInfo.Name == staticMethodStr(SysWorkflowWorkItem, create))
{
System.Object[] parametersList = methodInfo.GetParameters();
if (parametersList.Length == 3)
{
methodInfo.Invoke(this, parametersArray);
break;
}
}
}
}
}
2,SysWorkflowWorkItemHelper
标准的审批流逻辑大部分代码,微软不允许我们进行扩展,但是给我们预留了一个框架类SysWorkflowWorkItemHelper,我们通过这个类里面的两个方法skipWorkItem,removeWorkItems来对审批节点创建的工作项进行skip和remove处理来达到上面的需求


扩展skipWorkItem,在方法体中,我们主要是需要做一个判断,如果当前的待审核人,在之前的审批节点中已经审批过此单,我们就不需要为此待审批人继续创建待审工作项
扩展removeWorkItem,由于审批流中可以设置不同的审批策略,可以设置审批节点,需要单个人审批,大多数人审批或者所有人审批。
针对不同的策略,我们需要在扩展的removeWorkItem方法中,分别进行处理
- 当审批策略设置为单个人审批时,并且审批流流转到当前的节点只有一个审核人,并且审核人,在前面的节点已经审批过,此是,我们应该将此节点自动审批,不需要审批人手工再次进行审批
- 当审批策略设置为单个人审批时,并且审批流流转到当前的节点存在多个审核人,并且其中的审核人,在前面的节点已经审批过,此是,我们应该skip掉已经审核过的审核人的工作项
- 当审核策略设置为大多数人审批或者所有人审批时,并且审批流流转到当前的节点存在多个审核人,并且其中的审核人,在前面的节点已经审批过,此是,我们应该将此节点将审核过的人的工作项自动审批,不需要审批人手工再次进行审批
using Microsoft.Dynamics.AX.Framework.Workflow.Runtime;
[ExtensionOf(classStr(SysWorkflowWorkItemHelper))]
final class SysWorkflowWorkItemHelperVya_Extension
{
public static boolean skipWorkItem(WorkItemActivityContext _workItemActivityContext)
{
SysWorkflowElement sysWorkflowElement;
WorkflowWorkItemTable workItemTable;
WorkflowElementEventArgs elementEventArgs;
WorkflowWorkItemsEventArgs workItemEventArgs;
UserId curUserId;
boolean skip = next skipWorkItem(_workItemActivityContext);
curUserId = _workItemActivityContext.User.UserId;
select firstonly workItemTable
where workItemTable.ConfigurationId == _workItemActivityContext.ConfigurationId
&& workItemTable.CorrelationId == _workItemActivityContext.WorkflowContext.WorkflowCorrelationId
&& workItemTable.RootCorrelationId == _workItemActivityContext.WorkflowContext.RootCorrelationId
&& workItemTable.UserId == _workItemActivityContext.User.UserId
&& workItemTable.Status == WorkflowWorkItemStatus::Completed;
if (workItemTable.RecId)
{
skip = true;
}
return skip;
}
public static void removeWorkItems(WorkItemActivityContextCollection _workItems)
{
Microsoft.Dynamics.AX.Framework.Workflow.Runtime.WorkItemActivityContext workItemActivityContext;
System.Collections.IEnumerator enumerator;
WorkflowWorkItemTable workItemTable;
WorkflowStepTable workflowStepTable;
int i;
Array array;
boolean skip;
next removeWorkItems(_workItems);
for (i = 0; i < _workItems.Count; i++)
{
workItemActivityContext = _workItems.get_ITEM(i);
skip = SysWorkflowWorkItemHelper::skipWorkItem(workItemActivityContext);
if (skip)
{
if (_workItems.Count == 1)
{
workItemTable = WorkflowWorkItemTable::findActivityInstanceId(workItemActivityContext.get_ActivityId());
if (workItemTable.RecId == 0)
{
new SysWorkflowWorkItem().callCreateWorkItems(workItemActivityContext, NoYes::Yes);
}
workItemTable = WorkflowWorkItemTable::findActivityInstanceId(workItemActivityContext.get_ActivityId());
if (workItemTable)
{
WorkflowWorkItemActionManager::dispatchWorkItemAction(
workItemTable,
"Auto Approve",
workItemTable.UserId,
WorkflowWorkItemActionType::Complete,
workItemTable.MenuItemName);
}
}
else
{
workflowStepTable = WorkflowStepTable::find(workItemActivityContext.StepActivityId);
if (workflowStepTable.CompletionPolicy == WorkflowStepCompletionPolicy::Single)
{
_workItems.Remove(workItemActivityContext);
}
else
{
workItemTable = WorkflowWorkItemTable::findActivityInstanceId(workItemActivityContext.get_ActivityId());
if (workItemTable.RecId == 0)
{
new SysWorkflowWorkItem().callCreateWorkItems(workItemActivityContext, NoYes::Yes);
}
workItemTable = WorkflowWorkItemTable::findActivityInstanceId(workItemActivityContext.get_ActivityId());
if (workItemTable)
{
WorkflowWorkItemActionManager::dispatchWorkItemAction(
workItemTable,
"Auto Approve",
workItemTable.UserId,
WorkflowWorkItemActionType::Complete,
workItemTable.MenuItemName);
}
}
}
}
}
}
}
难点:
- 找到扩展的对象
- 由于workflow大部分逻辑我们无法扩展且不能进行直接调用,需要利用反射的机制进行处理
- 遍历待审核工作项,集合不能用System.Collections.IEnumerator进行遍历,一定要用for循环,因为System.Collections.IEnumerator遍历不能修改集合的元素

浙公网安备 33010602011771号