public enum NodeTypeEnum {
/**
* 审批节点
*/
APPROVAL("审批节点"),
/**
* 条件节点
*/
CONDITION("条件节点"),
/**
* 系统节点
*/
SYSTEM("系统节点");
private final String name;
NodeTypeEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public enum HandlerTypeEnum {
/**
* 审批人
*/
APPROVER,
/**
* 抄送人
*/
CCPERSON
}
public enum ApprovalFlowNodeEnum {
/**
* 填写Site基本信息
*/
FILL_SITE_INFO("填写Site基本信息", "Input Site Basic Information"),
/**
* 维护银行函信息
*/
MAIN_BANK_LETTER_INFO("维护银行函信息", "Maintain Bank Letter Information"),
/**
* 填写OU信息
*/
FILL_OU_INFO("填写OU信息", "Input OU Information"),
/**
* 修改OU信息
*/
MODIFY_OU_INFO("修改OU信息", "Change OU Information"),
/**
* 供应商Owner审批
*/
SUPPLIER_OWNER_APPROVAL("供应商Owner审核", "Supplier Owner Review"),
/**
* 供应商填写
*/
SUPPLIER_FILL("供应商填写", "Supplier Input"),
/**
* AP审核
*/
AP_APPROVAL("AP审核", "AP Review"),
/**
* 金融合规审核
*/
COMPLIANCE_APPROVAL("金融合规审核", "Financial Compliance Review"),
/**
* 采购复核
*/
PROCUREMENT_REAPPROVAL("采购复核", "Procurement Information Review"),
/**
* CEG Leader 审核
*/
CEG_LEADER_APPROVAL("CEG Leader 审批", "CEG Leader Approval"),
/**
* EBS集成
*/
EBS_INTE("EBS集成", "EBS Integration"),
/**
* 已邀请
*/
INVITED("已邀请", "Invited"),
/**
* 变更site信息
*/
MODIFY_SITE_INFO("变更Site基本信息", "Change Site Basic Information"),
/**
* 变更银行函信息
*/
MODIFY_BANK_LETTER_INFO("变更银行函信息", "Change Bank Letter Information");
private final String nameCn;
private final String nameEn;
ApprovalFlowNodeEnum(String nameCn, String nameEn) {
this.nameCn = nameCn;
this.nameEn = nameEn;
}
private String nameEn() {
return this.nameEn;
}
/**
* 根据中文获取英文
*
* @param nameCn nameCn
* @return String String
*/
public static String getNameEn(String nameCn) {
ApprovalFlowNodeEnum[] approvalNodeEnEnums = values();
for (ApprovalFlowNodeEnum approvalNodeEnEnum : approvalNodeEnEnums) {
if (approvalNodeEnEnum.nameCn.equals(nameCn)) {
return approvalNodeEnEnum.nameEn();
}
}
return nameCn;
}
}
public enum ApprovalErrorEnum {
/**
* 没有权限撤回
*/
NO_AUTH_REVOKE(5001, "No Auth Revoke"),
/**
* 非法的实例状态
*/
ILLEGAL_INSTANCE_STATUS(5002, "Illegal Instance Status"),
/**
* 该审批人已经在使用中
*/
APPROVER_REALLY_USE(5003, "approver really use"),
/**
* 没有权限作废(只允许责任人作废)
*/
NO_AUTH_ABORT(5004, "No Auth Abort"),
/**
* 没有找到实例
*/
NOT_FIND_INSTANCE(5005, "Not Find Instance"),
/**
* 没有权限
*/
NO_AUTH(5006, "No Auth"),
/**
* 流程不在当前节点,无法审批
*/
CURRENT_NODE_ERROR(5007, "The process is not in the current node and cannot be approved"),
/**
* 没有权限审批
*/
NO_AUTH_APPROVE(5008, "No Auth Approve"),
/**
* 不能转审给自己
*/
NOT_REFERRAL_TO_SELF(5009, "Can't refer to myself");
private final Integer code;
private final String msg;
ApprovalErrorEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
public enum ApprovalEnum {
/**
* 提交
*/
SUBMIT("提交"),
/**
* 同意
*/
AGREE("同意"),
/**
* 驳回
*/
REJECT("驳回"),
/**
* 重新启动
*/
RESTART("重新启动"),
/**
* 重新提交
*/
RESUBMIT("重新提交"),
/**
* 撤回
*/
REVOKE("撤回"),
/**
* 转审
*/
REFERRAL("转审"),
/**
* 修改owner
*/
MODIFY_OWNER("修改owner"),
/**
* 作废
*/
ABORT("作废"),
/**
* 删除
*/
DELETE("删除"),
/**
* 未处理
*/
UNHANDLED("未处理"),
/**
* 进行中
*/
RUNNING("进行中"),
/**
* 已完成
*/
FINISHED("已完成"),
/**
* 取消
*/
CANCEL("取消");
private final String name;
ApprovalEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class ApprovalConstants {
/**
* tip for flowInstanceId is required
*/
public static final String FLOW_INSTANCE_ID_NULL_ERROR_MSG = "flowInstanceId is required";
/**
* tip for flowInstanceId is required
*/
public static final String FLOW_ID_NULL_ERROR_MSG = "flowId is required";
/**
* tip for flowNodeId is required
*/
public static final String FLOW_NODE_ID_NULL_ERROR_MSG = "flowNodeId is required";
/**
* tip for flowNodeVersion is required
*/
public static final String VERSION_NULL_ERROR_MSG = "flowNodeVersion is required";
/**
* RULE_STATIC
*/
public static final String RULE_STATIC = "static:";
/**
* RULE_VAR
*/
public static final String RULE_VAR = "var:";
/**
* RULE_SPEL
*/
public static final String SPEL_VAR = "spel:";
/**
* RULE_BEAN
*/
public static final String RULE_BEAN = "bean:";
/**
* COMMA
*/
public static final String COMMA = ",";
/**
* NEGATIVE_ONE
*/
public static final int NEGATIVE_ONE = -1;
/**
* YES
*/
public static final String YES = "Y";
/**
* NO
*/
public static final String NO = "N";
/**
* AGREE
*/
public static final String AGREE = "AGREE";
/**
* DISAGREE
*/
public static final String DISAGREE = "DISAGREE";
/**
* SORT_NUM_1
*/
public static final Integer SORT_NUM_1 = 1;
/**
* SORT_NUM_2
*/
public static final Integer SORT_NUM_2 = 2;
private ApprovalConstants() {
}
}
@Component
public class ApprovalAgreeUtil {
@Autowired
private ProApprovalFlowInstanceDomainService instanceService;
@Autowired
private ProApprovalFlowTodoDomainService toDoService;
@Autowired
private ProApprovalFlowLogDomainService logService;
/**
* 权限校验
*
* @param bizType bizType
* @param bizDataId bizDataId
* @return ResultDto
*/
public ResultDto checkAuth(String bizType, String bizDataId) {
UserVO user = CommonUtil.getCurrentUser();
ProApprovalFlowInstanceDto instance = instanceService.loadByBizTypeBizDataId(bizType, bizDataId);
if (instance.getFlowInstanceId() == null) {
return ResultDto.fail(ApprovalErrorEnum.NOT_FIND_INSTANCE);
}
if (!instance.getStatus().equals(ApprovalEnum.RUNNING.name())) {
return ResultDto.fail(ApprovalErrorEnum.ILLEGAL_INSTANCE_STATUS);
}
Optional<ProApprovalFlowTodoDto> todoOpt =
toDoService.loadByHandler(instance.getFlowInstanceId(), instance.getCurrentNode(), user.getUserAccount());
if (!todoOpt.isPresent()) {
return ResultDto.fail(ApprovalErrorEnum.NO_AUTH_APPROVE);
}
ResultDto resultDto = new ResultDto(todoOpt.get());
resultDto.setResult(instance);
return resultDto;
}
/**
* 转审权限校验
*
* @param approvalDto approvalDto
* @return ResultDto
*/
public ResultDto checkAuthReferral(ApprovalDto approvalDto) {
String bizType = approvalDto.getBizType();
String bizDataId = approvalDto.getBizDataId();
UserVO user = CommonUtil.getCurrentUser();
// 不能自己转自己
if (user.getUserAccount().equals(approvalDto.getForwardUser())) {
return ResultDto.fail(ApprovalErrorEnum.NOT_REFERRAL_TO_SELF);
}
ProApprovalFlowInstanceDto instance = instanceService.loadByBizTypeBizDataId(bizType, bizDataId);
if (instance.getFlowInstanceId() == null) {
return ResultDto.fail(ApprovalErrorEnum.NOT_FIND_INSTANCE);
}
Optional<ProApprovalFlowTodoDto> todoOpt =
toDoService.loadByHandler(instance.getFlowInstanceId(), instance.getCurrentNode(), user.getUserAccount());
if (!todoOpt.isPresent() && !user.getUserAccount().equals(instance.getOwner())) {
return ResultDto.fail(ApprovalErrorEnum.NO_AUTH_APPROVE);
}
ResultDto resultDto = new ResultDto();
if (todoOpt.isPresent()) {
resultDto.setData(todoOpt.get());
} else {
List<ProApprovalFlowTodoDto> todoDtoList =
toDoService.loadByCurNode(instance.getFlowInstanceId(), instance.getCurrentNode());
resultDto.setData(todoDtoList.stream()
.filter(item -> ApprovalEnum.UNHANDLED.name().equals(item.getResult()))
.findFirst()
.get());
}
resultDto.setResult(instance);
return resultDto;
}
/**
* 节点是否完成
*
* @param instance instance
* @param curNode curNode
* @return 节点是否完成
*/
public boolean isFinished(ProApprovalFlowInstanceDto instance, ProApprovalFlowNodeDto curNode) {
boolean isFinishedFlag = false;
// 如果通过比例为空则默认全部通过才通过,否则计算比例
List<ProApprovalFlowTodoDto> todoList =
toDoService.loadByCurNode(instance.getFlowInstanceId(), curNode.getFlowNodeId());
todoList = todoList.stream()
.filter(item -> !item.getResult().equals(ApprovalEnum.REFERRAL.name()))
.collect(Collectors.toList());
if (ObjectUtils.isEmpty(curNode.getPassRatio())) {
isFinishedFlag = true;
} else {
BigDecimal shouldPassNum =
curNode.getPassRatio().multiply(new BigDecimal(todoList.size())).setScale(0, RoundingMode.CEILING);
long realPassNum =
todoList.stream().filter(item -> item.getResult().equals(ApprovalEnum.AGREE.name())).count();
if (new BigDecimal(realPassNum).compareTo(shouldPassNum) > NEGATIVE_ONE) {
isFinishedFlag = true;
}
}
return isFinishedFlag;
}
}
@Component
public class ApprovalRejectUtil {
@Autowired
private ProApprovalFlowInstanceDomainService instanceService;
@Autowired
private ProApprovalFlowTodoDomainService toDoService;
@Autowired
private TodoWeLinkService todoWelinkService;
/**
* 节点是否驳回
*
* @param instance instance
* @param curNode curNode
* @return 节点是否驳回
*/
public boolean isReject(ProApprovalFlowInstanceDto instance, ProApprovalFlowNodeDto curNode) {
boolean isRejectFlag = false;
if (ObjectUtils.isEmpty(curNode.getRejectRatio())) {
return true;
}
List<ProApprovalFlowTodoDto> todoList =
toDoService.loadByCurNode(instance.getFlowInstanceId(), curNode.getFlowNodeId());
todoList = todoList.stream()
.filter(item -> !item.getResult().equals(ApprovalEnum.REFERRAL.name()))
.collect(Collectors.toList());
BigDecimal shouldRejectNum =
curNode.getRejectRatio().multiply(new BigDecimal(todoList.size())).setScale(0, RoundingMode.CEILING);
long realRejectNum =
todoList.stream().filter(item -> item.getResult().equals(ApprovalEnum.REJECT.name())).count();
if (new BigDecimal(realRejectNum).compareTo(shouldRejectNum) > NEGATIVE_ONE) {
isRejectFlag = true;
}
return isRejectFlag;
}
/**
* 完成当前实例的所有待办,待办结果置为取消
*
* @param flowInstanceId 流程实例ID
*/
public void cancelOtherTodo(Long flowInstanceId) {
List<ProApprovalFlowTodoDto> todoList = toDoService.loadByInstance(flowInstanceId);
for (ProApprovalFlowTodoDto todo : todoList) {
if (todo.getResult().equals(ApprovalEnum.UNHANDLED.name())) {
todoWelinkService.completeToDoAsync(new TodoCompleteDto(todo.getAppTaskId(), todo.getHandler()));
todo.setResult(ApprovalEnum.CANCEL.name());
}
}
toDoService.invalid(todoList);
}
/**
* 获取驳回节点
*
* @param bizData 业务数据
* @param rule 驳回节点规则
* @return RejectNode
*/
public Long getRejectNode(String bizData, String rule) {
if (rule.startsWith(RULE_STATIC)) {
return Long.valueOf(rule.substring(RULE_STATIC.length()));
}
if (rule.startsWith(SPEL_VAR)) {
String spelExpression = rule.substring(SPEL_VAR.length());
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable("map", JSON.parseObject(bizData));
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(spelExpression);
return exp.getValue(evaluationContext, Long.class);
}
throw new IllegalArgumentException("RejectNodeRule is Illegal");
}
/**
* 获取是否重新提交到自己
*
* @param bizData 业务数据
* @param rule 驳回节点规则
* @return RejectNode
*/
public boolean getResubmitToSelf(String bizData, String rule) {
if (StringUtils.isBlank(rule)) {
return false;
}
if (YES.equals(rule)) {
return true;
}
if (rule.startsWith(SPEL_VAR)) {
String spelExpression = rule.substring(SPEL_VAR.length());
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable("map", JSON.parseObject(bizData));
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(spelExpression);
return exp.getValue(evaluationContext, Boolean.class);
}
throw new IllegalArgumentException("ResubmitToSelf Rule is Illegal");
}
}
@Component
@Slf4j
public class ApprovalSubmitUtil {
private static final String VAR_MAP = "map";
@Autowired
private ProApprovalFlowInstanceDomainService instanceService;
@Autowired
private ProApprovalFlowNodeDomainService nodeService;
@Autowired
private ProApprovalFlowNodeHandlerDomainService nodeHandlerService;
@Autowired
private ProApprovalFlowDomainService flowService;
@Autowired
private ProApprovalFlowTodoDomainService toDoService;
@Autowired
private ApplicationContext context;
@Autowired
private TodoWeLinkService todoWelinkService;
@Autowired
private ApprovalEventPublisher eventPublisher;
@Autowired
private ProApprovalFlowLogDomainService logService;
/**
* 保存流程实例
*
* @param submitDto 提交参数
* @param oldInstance 旧流程实例
* @return ProApprovalFlowInstanceDto
*/
public ProApprovalFlowInstanceDto saveInstance(SubmitDto submitDto, ProApprovalFlowInstanceDto oldInstance) {
Long flowId = submitDto.getFlowId();
if (flowId == null) {
throw new IllegalArgumentException("flowId is required");
}
Long flowInstanceId = oldInstance.getFlowInstanceId();
boolean isAdd = flowInstanceId == null;
ProApprovalFlowInstanceEntity instance = new ProApprovalFlowInstanceEntity();
instance.setFlowInstanceId(flowInstanceId);
BeanUtils.copyProperties(submitDto, instance);
CommonUtil.setUser(instance, isAdd);
if (ObjectUtils.isEmpty(submitDto.getOwner())) {
UserVO user = CommonUtil.getCurrentUser();
submitDto.setOwner(user.getUserAccount());
submitDto.setOwnerName(user.getUserCN());
}
instance.setOwner(submitDto.getOwner());
instance.setOwnerName(submitDto.getOwnerName());
instance.setStatus(ApprovalEnum.RUNNING.name());
Object bizData = submitDto.getBizData();
if (!ObjectUtils.isEmpty(bizData)) {
instance.setBizData(JSON.toJSONString(bizData));
}
if (isAdd) {
instance.setFlowNodeVersion(nodeService.queryLastVersion(flowId));
instanceService.save(instance);
} else {
instance.setFlowNodeVersion(oldInstance.getFlowNodeVersion());
instanceService.modify(instance);
}
return ProApprovalAssembler.instanceToDto(instance);
}
/**
* 保存节点处理人
*
* @param instance 流程实例
* @param submitDto 提交参数
*/
public void saveNodeHandler(ProApprovalFlowInstanceDto instance, SubmitDto submitDto) {
Long flowId = submitDto.getFlowId();
Long flowInstanceId = instance.getFlowInstanceId();
String flowNodeVersion = instance.getFlowNodeVersion();
List<ProApprovalFlowNodeDto> nodeList = nodeService.loadByFlowIdAndVersion(flowId, flowNodeVersion);
List<ProApprovalFlowNodeDto> hasHandlerList =
nodeList.stream().filter(item -> StringUtils.hasText(item.getApproverRule())).collect(Collectors.toList());
for (ProApprovalFlowNodeDto node : hasHandlerList) {
// 审批人
processNodeHandlerRule(flowInstanceId, node, submitDto, false);
// 抄送人
processNodeHandlerRule(flowInstanceId, node, submitDto, true);
}
}
/**
* 处理节点处理人规则
*
* @param flowInstanceId 实例ID
* @param node 节点
* @param submitDto 提交参数
* @param isCc 是否抄送
*/
private void processNodeHandlerRule(Long flowInstanceId, ProApprovalFlowNodeDto node, SubmitDto submitDto,
boolean isCc) {
Long flowNodeId = node.getFlowNodeId();
String rule = isCc ? node.getCcUserRule() : node.getApproverRule();
if (!StringUtils.hasText(rule)) {
return;
}
Map data = JSON.parseObject(JSON.toJSONString(submitDto.getApprover()));
NodeHandlerDto owner = new NodeHandlerDto(submitDto.getOwner(), submitDto.getOwnerName());
data.put("owner", Collections.singletonList(owner));
String handlerStr = "";
if (rule.startsWith(RULE_STATIC)) {
// static:[{"account":"lw0043690","name":"luoyunyong W0043690"}]
handlerStr = rule.substring(RULE_STATIC.length());
}
if (rule.startsWith(RULE_VAR)) {
// var:approver
String handlerKey = rule.substring(RULE_VAR.length());
Object handler = data.get(handlerKey);
if (handler != null) {
handlerStr = JSON.toJSONString(handler);
}
}
if (rule.startsWith(RULE_BEAN)) {
// bean:node_handler_bean:blacklist
String beanName = rule.substring(RULE_BEAN.length());
NodeHandlerFactory handlerFactory = context.getBean(beanName, NodeHandlerFactory.class);
handlerStr = handlerFactory.get(submitDto);
}
if (!StringUtils.hasText(handlerStr)) {
return;
}
List<NodeHandlerDto> handlerList = JSON.parseArray(handlerStr, NodeHandlerDto.class);
String handlerType = isCc ? HandlerTypeEnum.CCPERSON.name() : HandlerTypeEnum.APPROVER.name();
for (NodeHandlerDto handler : handlerList) {
ProApprovalFlowNodeHandlerEntity handlerEntity = new ProApprovalFlowNodeHandlerEntity();
handlerEntity.setFlowInstanceId(flowInstanceId);
handlerEntity.setFlowNodeId(flowNodeId);
handlerEntity.setHandler(handler.getAccount());
handlerEntity.setHandlerName(handler.getName());
handlerEntity.setHandlerType(handlerType);
CommonUtil.setUser(handlerEntity);
nodeHandlerService.save(handlerEntity);
}
}
/**
* 激活节点
*
* @param instance 实例DTO
* @param curNode 当前节点
* @param isPass 是否通过
* @return BaseEvent
*/
public BaseEvent activateNode(ProApprovalFlowInstanceDto instance, ProApprovalFlowNodeDto curNode, boolean isPass) {
TimerUtil timerAll = new TimerUtil();
BaseEvent event = null;
// 条件节点
if (NodeTypeEnum.CONDITION.name().equals(curNode.getNodeType())) {
ProApprovalFlowNodeDto nextNode = evalCondition(curNode.getConditionExpression(), instance.getBizData());
event = activateNode(instance, nextNode, isPass);
}
// 系统节点
if (NodeTypeEnum.SYSTEM.name().equals(curNode.getNodeType())) {
SystemActivity systemActivityService = context.getBean(curNode.getSystemActivity(), SystemActivity.class);
boolean isAgree = systemActivityService.run(instance, curNode);
if (isAgree) {
// 激活下一个节点
ProApprovalFlowNodeDto nextNode = nodeService.loadByFlowIdAndVersion(instance.getFlowId(),
instance.getFlowNodeVersion(), curNode.getSortNum() + 1);
if (NodeTypeEnum.CONDITION.name().equals(nextNode.getNodeType())) {
nextNode = evalCondition(nextNode.getConditionExpression(), instance.getBizData());
}
activate(instance, nextNode, true);
// 发布节点完成事件
ProApprovalFlowInstanceDto flowInfo = new ProApprovalFlowInstanceDto();
BeanUtils.copyProperties(instance, flowInfo);
flowInfo.setPreNodeId(curNode.getFlowNodeId());
flowInfo.setPreNodeCode(curNode.getFlowNodeCode());
flowInfo.setPreNodeName(curNode.getFlowNodeName());
event = new NodeFinishedEvent(flowInfo);
} else {
activate(instance, curNode, true);
eventPublisher.publishEvent(new PendingEvent(instance));
}
}
// 审批节点
if (NodeTypeEnum.APPROVAL.name().equals(curNode.getNodeType())) {
activate(instance, curNode, isPass);
}
timerAll.print("activateNode total");
return event;
}
private ProApprovalFlowNodeDto evalCondition(String conditionExpression, String bizData) {
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(conditionExpression);
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable(VAR_MAP, JSON.parseObject(bizData));
Long nextNodeId = expression.getValue(evaluationContext, Long.class);
return nodeService.load(nextNodeId);
}
/**
* 激活
*
* @param instance 实例DTO
* @param curNode 当前节点
* @param isPass 是否通过
*/
public void activate(ProApprovalFlowInstanceDto instance, ProApprovalFlowNodeDto curNode, boolean isPass) {
log.info("activate start instance : {}, curNode: {}", instance.getFlowInstanceId(), curNode.getFlowNodeCode());
TimerUtil timerAll = new TimerUtil();
Long flowInstanceId = instance.getFlowInstanceId();
Long originNodeId = instance.getCurrentNode();
ProApprovalFlowNodeDto originNode = nodeService.load(originNodeId);
instance.setPreNodeId(originNodeId);
instance.setPreNodeCode(originNode.getFlowNodeCode());
instance.setPreNodeName(originNode.getFlowNodeName());
// 激活
TimerUtil timer = new TimerUtil();
instanceService.updateCurNode(flowInstanceId, curNode.getFlowNodeId());
instance.setCurrentNode(curNode.getFlowNodeId());
instance.setCurrentNodeCode(curNode.getFlowNodeCode());
instance.setCurrentNodeName(curNode.getFlowNodeName());
instance.setBizStatus(curNode.getBizStatus());
timer.print("=====updateCurNode");
// 给审批人发送待办和WeLink通知
timer = new TimerUtil();
String todoRule = isPass ? curNode.getActiveTodoRule() : originNode.getRejectTodoRule();
TodoDto todo = getTodo(instance.getBizData(), todoRule);
List<ProApprovalFlowNodeHandlerDto> nodeHandlerList =
nodeHandlerService.loadByInstanceAndNodeId(flowInstanceId, curNode.getFlowNodeId());
if (ObjectUtils.isEmpty(nodeHandlerList)) {
return;
}
List<ProApprovalFlowNodeHandlerDto> approverList = nodeHandlerList.stream()
.filter(item -> item.getHandlerType().equals(HandlerTypeEnum.APPROVER.name()))
.collect(Collectors.toList());
if (!ObjectUtils.isEmpty(approverList)) {
for (ProApprovalFlowNodeHandlerDto handlerDto : approverList) {
approvalSendTodo(instance, handlerDto, todo, new ApprovalDto());
}
timer.print("=====SendTodo approverList");
}
// 给抄送人发送WeLink通知
timer = new TimerUtil();
List<ProApprovalFlowNodeHandlerDto> ccUserList = nodeHandlerList.stream()
.filter(item -> item.getHandlerType().equals(HandlerTypeEnum.CCPERSON.name()))
.collect(Collectors.toList());
if (!ObjectUtils.isEmpty(ccUserList)) {
for (ProApprovalFlowNodeHandlerDto ccUser : ccUserList) {
sendWeLinkNotice(todo.getTitle(), todo.getDesc(), ccUser.getHandler(), todo.getUrl());
}
timer.print("=====sendWeLinkNotice ccUserList");
}
timerAll.print("activate total");
}
/**
* 获取待办
*
* @param bizData 业务数据
* @param todoRule 待办
* @return TodoDto
*/
public static TodoDto getTodo(String bizData, String todoRule) {
if (!StringUtils.hasText(todoRule)) {
return new TodoDto();
}
String todoJson = "";
if (todoRule.startsWith(RULE_STATIC)) {
// static:{"title":"新增Site- AP审核-待审核(单据号:${documentNo})","desc":"新增Site-
// AP审核-待审核","url":"${todoHost}/#/group/procurement/site-create?id=${siteMainId}"}
todoJson = todoRule.substring(RULE_STATIC.length());
}
if (todoRule.startsWith(SPEL_VAR)) {
// spel:#map['isSupMain']?'{\"title\":\"新增Site- AP审核-待审核(单据号:${documentNo})\",\"desc\":\"新增Site-
// AP审核-待审核\",\"url\":\"${todoHost}/#/group/procurement/site-create?id=${siteMainId}\"}':7
String spelExpression = todoRule.substring(SPEL_VAR.length());
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable(VAR_MAP, JSON.parseObject(bizData));
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(spelExpression);
todoJson = exp.getValue(evaluationContext, String.class);
}
TodoDto todoDto = JSON.parseObject(todoJson, TodoDto.class);
varReplace(bizData, todoDto);
return todoDto;
}
@SneakyThrows
private static void varReplace(String bizData, Object obj) {
if (!StringUtils.hasText(bizData)) {
return;
}
Class clazz = obj.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
Object val = field.get(obj);
if (ObjectUtils.isEmpty(val)) {
continue;
}
String valStr = val.toString();
Map<String, Object> map = JSON.parseObject(bizData).getInnerMap();
for (String key : map.keySet()) {
String replaceKey = "${" + key + "}";
String value = map.get(key) == null ? "" : map.get(key).toString();
valStr = valStr.replace(replaceKey, value);
field.set(obj, valStr);
}
}
}
/**
* 审批流发送待办
*
* @param instance 流程信息
* @param handlerDto 处理人
* @param todoDto 待办
* @param approvalDto 审批参数
*/
public void approvalSendTodo(ProApprovalFlowInstanceDto instance, ProApprovalFlowNodeHandlerDto handlerDto,
TodoDto todoDto, ApprovalDto approvalDto) {
String title = todoDto.getTitle();
String desc = todoDto.getDesc();
String url = todoDto.getUrl();
Assert.hasText(title, "Todo title is null");
Assert.hasText(title, "Todo desc is null");
Assert.hasText(title, "Todo url is null");
Assert.hasText(handlerDto.getHandler(), "Todo Handler is null");
// 发送待办
UserVO user = CommonUtil.getCurrentUser();
TodoSaveDto toDoDto = new TodoSaveDto();
toDoDto.setAppTaskId("APPROVAL_" + IdUtil.getSnowflake().nextIdStr());
toDoDto.setType("COUNTERSIGN");
toDoDto.setTitle(title);
toDoDto.setDescription(desc);
toDoDto.setApplicantAccount(user.getUserAccount());
toDoDto.setHandlersAccount(Collections.singletonList(handlerDto.getHandler()));
toDoDto.setUrl(url);
toDoDto.setWpMsg(true);
toDoDto.setWelinkMsg(true);
toDoDto.setShowApplicantName(false);
todoWelinkService.newToDoAsync(toDoDto);
// 保存待办
ProApprovalFlowTodoEntity todoEntity = new ProApprovalFlowTodoEntity();
todoEntity.setAppTaskId(toDoDto.getAppTaskId());
todoEntity.setFlowInstanceId(instance.getFlowInstanceId());
todoEntity.setFlowNodeId(instance.getCurrentNode());
todoEntity.setHandler(handlerDto.getHandler());
todoEntity.setHandlerName(handlerDto.getHandlerName());
todoEntity.setForwardUser(approvalDto.getForwardUser());
todoEntity.setForwardUserName(approvalDto.getForwardUserName());
todoEntity.setResult(ApprovalEnum.UNHANDLED.name());
todoEntity.setActiveFlag(YES);
CommonUtil.setUser(todoEntity);
toDoService.save(todoEntity);
// 发送WeLink通知
sendWeLinkNotice(title, desc, handlerDto.getHandler(), url);
}
/**
* 发送WeLink通知
*
* @param title 标题
* @param desc 描述
* @param handler 处理人
* @param url 链接
*/
public void sendWeLinkNotice(String title, String desc, String handler, String url) {
WelinkSendDto sendDto = new WelinkSendDto();
sendDto.setTitle(title);
sendDto.setContent(desc);
sendDto.setAccounts(handler);
sendDto.setUrl(url);
todoWelinkService.sendWeLinkNoticeAsync(sendDto);
}
/**
* 获取节点
*
* @param curNode 当前节点
* @param instance instanceInfo
* @param nodeList nodeList
* @param nodeMap nodeMap
*/
public void getNode(ProApprovalFlowNodeDto curNode, ProApprovalFlowInstanceDto instance,
List<ProApprovalFlowNodeDto> nodeList, Map<Integer, ProApprovalFlowNodeDto> nodeMap) {
// 条件节点
if (NodeTypeEnum.CONDITION.name().equals(curNode.getNodeType())) {
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(curNode.getConditionExpression());
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable(VAR_MAP, JSON.parseObject(instance.getBizData()));
Long nextNodeId = expression.getValue(evaluationContext, Long.class);
Optional<ProApprovalFlowNodeDto> nextOpt =
nodeMap.values().stream().filter(item -> item.getFlowNodeId().equals(nextNodeId)).findFirst();
getNode(nextOpt.get(), instance, nodeList, nodeMap);
}
// 系统节点和审批节点
if (NodeTypeEnum.SYSTEM.name().equals(curNode.getNodeType())
|| NodeTypeEnum.APPROVAL.name().equals(curNode.getNodeType())) {
nodeList.add(curNode);
if (YES.equals(curNode.getLastFlag())) {
return;
}
getNode(nodeMap.get(curNode.getSortNum() + 1), instance, nodeList, nodeMap);
}
}
}
public class ProApprovalAssembler {
private ProApprovalAssembler() {
}
/**
* 实例entity转DTO
*
* @param entity ProApprovalFlowInstanceEntity
* @return ProApprovalFlowInstanceDto
*/
public static ProApprovalFlowInstanceDto instanceToDto(ProApprovalFlowInstanceEntity entity) {
ProApprovalFlowInstanceDto flowInfoDto = new ProApprovalFlowInstanceDto();
if (entity == null) {
return flowInfoDto;
}
BeanUtils.copyProperties(entity, flowInfoDto);
return flowInfoDto;
}
/**
* 节点entity转DTO
*
* @param entity ProApprovalFlowNodeEntity
* @return ProApprovalFlowInfoDto
*/
public static ProApprovalFlowNodeDto nodeToDto(ProApprovalFlowNodeEntity entity) {
ProApprovalFlowNodeDto nodeDto = new ProApprovalFlowNodeDto();
if (entity == null) {
return nodeDto;
}
BeanUtils.copyProperties(entity, nodeDto);
return nodeDto;
}
/**
* 流程entity转DTO
*
* @param entity ProApprovalFlowEntity
* @return ProApprovalFlowDto
*/
public static ProApprovalFlowDto flowToDto(ProApprovalFlowEntity entity) {
ProApprovalFlowDto flowDto = new ProApprovalFlowDto();
if (entity == null) {
return flowDto;
}
BeanUtils.copyProperties(entity, flowDto);
return flowDto;
}
/**
* 处理人entity转DTO
*
* @param entity ProApprovalFlowNodeHandlerEntity
* @return ProApprovalFlowNodeHandlerDto
*/
public static ProApprovalFlowNodeHandlerDto nodeHandlerToDto(ProApprovalFlowNodeHandlerEntity entity) {
ProApprovalFlowNodeHandlerDto nodeHandlerDto = new ProApprovalFlowNodeHandlerDto();
if (entity == null) {
return nodeHandlerDto;
}
BeanUtils.copyProperties(entity, nodeHandlerDto);
return nodeHandlerDto;
}
}