Commit 5c2fcdce1554d1d6a9267bf308dbe8a289538e90

Authored by jason
1 parent 12108e73

仿钉钉流程设计- 会签按通过比率

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java
@@ -16,7 +16,7 @@ public enum BpmApproveMethodEnum { @@ -16,7 +16,7 @@ public enum BpmApproveMethodEnum {
16 16
17 SINGLE_PERSON_APPROVE(1, "单人审批"), 17 SINGLE_PERSON_APPROVE(1, "单人审批"),
18 ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签 18 ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签
19 - APPROVE_BY_RATIO(3, "多人会签(按比例投票)"), // 会签(按比例投票) 19 + APPROVE_BY_RATIO(3, "多人会签(按通过比例)"), // 会签(按通过比例)
20 ANY_APPROVE_ALL_REJECT(4, "多人会签(通过只需一人,拒绝需要全员)"), // 会签(通过只需一人,拒绝需要全员) 20 ANY_APPROVE_ALL_REJECT(4, "多人会签(通过只需一人,拒绝需要全员)"), // 会签(通过只需一人,拒绝需要全员)
21 ANY_APPROVE(5, "多人或签(一名审批人通过即可)"), // 或签(通过只需一人,拒绝只需一人) 21 ANY_APPROVE(5, "多人或签(一名审批人通过即可)"), // 或签(通过只需一人,拒绝只需一人)
22 SEQUENTIAL_APPROVE(6, "依次审批"); // 依次审批 22 SEQUENTIAL_APPROVE(6, "依次审批"); // 依次审批
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
@@ -56,6 +56,11 @@ public interface BpmnModelConstants { @@ -56,6 +56,11 @@ public interface BpmnModelConstants {
56 String USER_TASK_APPROVE_METHOD = "approveMethod"; 56 String USER_TASK_APPROVE_METHOD = "approveMethod";
57 57
58 /** 58 /**
  59 + * BPMN UserTask 的扩展属性,当审批方式为按通过比例时, 标记会签通过比例
  60 + */
  61 + String USER_TASK_APPROVE_RATIO = "approveRatio";
  62 +
  63 + /**
59 * BPMN ExtensionElement 的扩展属性,用于标记 服务任务附属的用户任务 Id 64 * BPMN ExtensionElement 的扩展属性,用于标记 服务任务附属的用户任务 Id
60 */ 65 */
61 String SERVICE_TASK_ATTACH_USER_TASK_ID = "attachUserTaskId"; 66 String SERVICE_TASK_ATTACH_USER_TASK_ID = "attachUserTaskId";
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/expression/CompleteByRejectCountExpression.java
@@ -16,7 +16,9 @@ import java.util.Objects; @@ -16,7 +16,9 @@ import java.util.Objects;
16 16
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
18 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT; 18 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT;
  19 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum.APPROVE_BY_RATIO;
19 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_METHOD; 20 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_METHOD;
  21 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_RATIO;
20 22
21 /** 23 /**
22 * 按拒绝人数计算会签的完成条件的流程表达式实现 24 * 按拒绝人数计算会签的完成条件的流程表达式实现
@@ -28,7 +30,7 @@ import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnMode @@ -28,7 +30,7 @@ import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnMode
28 public class CompleteByRejectCountExpression { 30 public class CompleteByRejectCountExpression {
29 31
30 /** 32 /**
31 - * 会签的完成条件 33 + * 会签的完成条件
32 */ 34 */
33 public boolean completionCondition(DelegateExecution execution) { 35 public boolean completionCondition(DelegateExecution execution) {
34 FlowElement flowElement = execution.getCurrentFlowElement(); 36 FlowElement flowElement = execution.getCurrentFlowElement();
@@ -53,13 +55,29 @@ public class CompleteByRejectCountExpression { @@ -53,13 +55,29 @@ public class CompleteByRejectCountExpression {
53 } else { 55 } else {
54 // 1.2 所有人都拒绝了。设置任务拒绝变量, 会签任务完成。 后续终止流程在 ServiceTask【MultiInstanceServiceTaskExpression】处理 56 // 1.2 所有人都拒绝了。设置任务拒绝变量, 会签任务完成。 后续终止流程在 ServiceTask【MultiInstanceServiceTaskExpression】处理
55 if (Objects.equals(nrOfInstances, rejectCount)) { 57 if (Objects.equals(nrOfInstances, rejectCount)) {
56 - execution.setVariable(String.format("%s_reject",flowElement.getId()), Boolean.TRUE); 58 + execution.setVariable(String.format("%s_reject", flowElement.getId()), Boolean.TRUE);
57 return true; 59 return true;
58 } 60 }
59 return false; 61 return false;
60 } 62 }
  63 + } else if (Objects.equals(APPROVE_BY_RATIO.getMethod(), approveMethod)) {
  64 + Integer approveRatio = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_APPROVE_RATIO));
  65 + Assert.notNull(approveRatio, "通过比例不能空");
  66 + double approvePct = approveRatio / (double) 100;
  67 + double realApprovePct = (double) agreeCount / nrOfInstances;
  68 + // 判断通过比例
  69 + if (realApprovePct >= approvePct) {
  70 + return true;
  71 + }
  72 + double rejectPct = (100 - approveRatio) / (double) 100;
  73 + double realRejectPct = (double) rejectCount / nrOfInstances;
  74 + // 判断拒绝比例
  75 + if (realRejectPct >= rejectPct) {
  76 + execution.setVariable(String.format("%s_reject", flowElement.getId()), Boolean.TRUE);
  77 + return true;
  78 + }
  79 + return false;
61 } 80 }
62 - // TODO 多人会签(按比例投票)  
63 log.error("[completionCondition] 按拒绝人数计算会签的完成条件的审批方式[{}],配置有误", approveMethod); 81 log.error("[completionCondition] 按拒绝人数计算会签的完成条件的审批方式[{}],配置有误", approveMethod);
64 throw exception(GlobalErrorCodeConstants.ERROR_CONFIGURATION); 82 throw exception(GlobalErrorCodeConstants.ERROR_CONFIGURATION);
65 } 83 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/simple/SimpleModelUserTaskConfig.java
1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple; 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple;
2 2
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
3 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType; 4 import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
4 import lombok.Data; 5 import lombok.Data;
5 6
@@ -30,11 +31,15 @@ public class SimpleModelUserTaskConfig { @@ -30,11 +31,15 @@ public class SimpleModelUserTaskConfig {
30 private List<Map<String,String>> fieldsPermission; 31 private List<Map<String,String>> fieldsPermission;
31 32
32 /** 33 /**
33 - * 审批方式 34 + * 审批方式 {@link BpmApproveMethodEnum }
34 */ 35 */
35 private Integer approveMethod; 36 private Integer approveMethod;
36 37
37 /** 38 /**
  39 + * 通过比例 当审批方式为 多人会签(按通过比例) 需设置
  40 + */
  41 + private Integer approveRatio;
  42 + /**
38 * 超时处理 43 * 超时处理
39 */ 44 */
40 private TimeoutHandler timeoutHandler; 45 private TimeoutHandler timeoutHandler;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -493,7 +493,7 @@ public class SimpleModelUtils { @@ -493,7 +493,7 @@ public class SimpleModelUtils {
493 // 添加表单字段权限属性元素 493 // 添加表单字段权限属性元素
494 addFormFieldsPermission(userTaskConfig.getFieldsPermission(), userTask); 494 addFormFieldsPermission(userTaskConfig.getFieldsPermission(), userTask);
495 // 处理多实例 495 // 处理多实例
496 - processMultiInstanceLoopCharacteristics(userTaskConfig.getApproveMethod(), userTask); 496 + processMultiInstanceLoopCharacteristics(userTaskConfig.getApproveMethod(), userTaskConfig.getApproveRatio(), userTask);
497 // 添加任务被拒绝的处理元素 497 // 添加任务被拒绝的处理元素
498 addTaskRejectElements(userTaskConfig.getRejectHandler(), userTask); 498 addTaskRejectElements(userTaskConfig.getRejectHandler(), userTask);
499 return userTask; 499 return userTask;
@@ -507,7 +507,7 @@ public class SimpleModelUtils { @@ -507,7 +507,7 @@ public class SimpleModelUtils {
507 addExtensionElement(userTask, USER_TASK_REJECT_RETURN_TASK_ID, rejectHandler.getReturnNodeId()); 507 addExtensionElement(userTask, USER_TASK_REJECT_RETURN_TASK_ID, rejectHandler.getReturnNodeId());
508 } 508 }
509 509
510 - private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, UserTask userTask) { 510 + private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
511 BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod); 511 BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
512 if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) { 512 if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) {
513 return; 513 return;
@@ -530,11 +530,16 @@ public class SimpleModelUtils { @@ -530,11 +530,16 @@ public class SimpleModelUtils {
530 multiInstanceCharacteristics.setSequential(true); 530 multiInstanceCharacteristics.setSequential(true);
531 multiInstanceCharacteristics.setLoopCardinality("1"); 531 multiInstanceCharacteristics.setLoopCardinality("1");
532 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 532 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
533 - } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT) { 533 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT ){
534 multiInstanceCharacteristics.setCompletionCondition(COMPLETE_BY_REJECT_COUNT_EXPRESSION); 534 multiInstanceCharacteristics.setCompletionCondition(COMPLETE_BY_REJECT_COUNT_EXPRESSION);
535 multiInstanceCharacteristics.setSequential(false); 535 multiInstanceCharacteristics.setSequential(false);
  536 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.APPROVE_BY_RATIO) {
  537 + multiInstanceCharacteristics.setCompletionCondition(COMPLETE_BY_REJECT_COUNT_EXPRESSION);
  538 + multiInstanceCharacteristics.setSequential(false);
  539 + Assert.notNull(approveRatio, "通过比例不能为空");
  540 + // 添加通过比例的扩展属性
  541 + addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_RATIO, approveRatio.toString());
536 } 542 }
537 - // TODO 会签(按比例投票 )  
538 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 543 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
539 } 544 }
540 545