| | |
| | | package com.ruoyi.approve.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.approve.mapper.ApproveLogMapper; |
| | | import com.ruoyi.approve.mapper.ApproveNodeMapper; |
| | | import com.ruoyi.approve.mapper.ApproveProcessMapper; |
| | | import com.ruoyi.approve.pojo.ApproveLog; |
| | | import com.ruoyi.approve.pojo.ApproveNode; |
| | | import com.ruoyi.approve.pojo.ApproveProcess; |
| | | import com.ruoyi.approve.service.IApproveNodeService; |
| | | import com.ruoyi.approve.service.IApproveProcessService; |
| | | import com.ruoyi.approve.vo.ApproveNodeVO; |
| | | import com.ruoyi.common.enums.FileNameType; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import lombok.AllArgsConstructor; |
| | | import com.ruoyi.other.service.impl.TempFileServiceImpl; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import com.ruoyi.sales.mapper.CommonFileMapper; |
| | | import com.ruoyi.sales.pojo.CommonFile; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class ApproveNodeServiceImpl extends ServiceImpl<ApproveNodeMapper, ApproveNode> implements IApproveNodeService { |
| | | private final ApproveNodeMapper approveNodeMapper; |
| | | private final ApproveProcessMapper approveProcessMapper; |
| | | private final ApproveLogMapper approveLogMapper; |
| | | private final SysUserMapper sysUserMapper; |
| | | private final TempFileServiceImpl tempFileService; |
| | | private final CommonFileMapper fileMapper; |
| | | |
| | | @Autowired |
| | | private ApproveNodeMapper approveNodeMapper; |
| | | @Autowired |
| | | private IApproveProcessService approveProcessService; |
| | | |
| | | private ApproveProcess getApproveById(String code) { |
| | | ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>() |
| | | .eq(ApproveProcess::getApproveId, code) |
| | | .eq(ApproveProcess::getApproveDelete, 0) |
| | | .eq(ApproveProcess::getTenantId, tenantId()) |
| | | .last("limit 1")); |
| | | if (process == null) throw new RuntimeException("审批不存在"); |
| | | return process; |
| | | } |
| | | |
| | | @Override |
| | | public void initApproveNodes(String id) { |
| | | //租户id |
| | | Long tenantId = SecurityUtils.getLoginUser().getTenantId(); |
| | | |
| | | ApproveProcess approve = approveProcessService.getApproveById(id); |
| | | String[] names = approve.getApproveUserNames().split(","); |
| | | Long approveId = approve.getId(); |
| | | for (int i = 0; i < names.length; i++) { |
| | | ApproveNode approveNode = new ApproveNode(); |
| | | approveNode.setApproveProcessId(approveId); |
| | | approveNode.setApproveNodeOrder(i +1); |
| | | approveNode.setApproveNodeUser(names[i]); |
| | | approveNode.setApproveNodeTime(new Date()); |
| | | approveNode.setApproveNodeStatus(0); |
| | | approveNode.setTenantId(tenantId); |
| | | approveNode.setDeleteFlag(0); |
| | | approveNodeMapper.insert(approveNode); |
| | | public void initApproveNodes(String approveUserIds, String approveID, Long tenantId) { |
| | | if (!StringUtils.hasText(approveUserIds)) throw new RuntimeException("请选择审批人"); |
| | | List<ApproveNodeVO> nodes = new ArrayList<>(); |
| | | for (String id : approveUserIds.split(",")) { |
| | | ApproveNodeVO node = new ApproveNodeVO(); |
| | | node.setUserId(Long.parseLong(id.trim())); |
| | | node.setConditionOperator("ALWAYS"); |
| | | nodes.add(node); |
| | | } |
| | | initApproveNodes(nodes, approveID, tenantId); |
| | | } |
| | | |
| | | @Override |
| | | public void initApproveNodes(List<ApproveNodeVO> nodes, String approveID, Long ignoredTenantId) { |
| | | if (CollectionUtils.isEmpty(nodes)) throw new RuntimeException("审批流程至少包含一个节点"); |
| | | Long tenantId = tenantId(); |
| | | Long currentUserId = SecurityUtils.getUserId(); |
| | | ApproveProcess process = getApproveById(approveID); |
| | | int order = 1; |
| | | ApproveNode first = null; |
| | | Long previousUserId = null; |
| | | for (ApproveNodeVO request : nodes) { |
| | | if (request.getUserId() == null) throw new RuntimeException("审批人不能为空"); |
| | | if (request.getUserId().equals(previousUserId)) throw new RuntimeException("相邻审批节点不能选择同一审批人"); |
| | | previousUserId = request.getUserId(); |
| | | if (!matchesCondition(process.getAmount(), request)) continue; |
| | | SysUser user = sysUserMapper.selectUserById(request.getUserId()); |
| | | if (user == null || !tenantId.equals(user.getTenantId())) throw new RuntimeException("审批人不存在或不属于当前租户"); |
| | | ApproveNode node = new ApproveNode(); |
| | | node.setApproveProcessId(process.getApproveId()); |
| | | node.setApproveNodeOrder(order++); |
| | | node.setApproveNodeName(StringUtils.hasText(request.getNodeName()) ? request.getNodeName() : "审批"); |
| | | node.setApproveNodeUser(user.getNickName()); |
| | | node.setApproveNodeUserId(user.getUserId()); |
| | | node.setApproveNodeStatus(0); |
| | | node.setConditionField(request.getConditionField()); |
| | | node.setConditionOperator(StringUtils.hasText(request.getConditionOperator()) ? request.getConditionOperator() : "ALWAYS"); |
| | | node.setConditionValue(request.getConditionValue()); |
| | | node.setIsCurrent(first == null ? 1 : 0); |
| | | node.setTenantId(tenantId); |
| | | node.setDeleteFlag(0); |
| | | node.setCreateUser(currentUserId); |
| | | node.setUpdateUser(currentUserId); |
| | | node.setCreateTime(LocalDateTime.now()); |
| | | node.setUpdateTime(LocalDateTime.now()); |
| | | approveNodeMapper.insert(node); |
| | | if (first == null) first = node; |
| | | } |
| | | if (first == null) throw new RuntimeException("没有满足条件的审批节点"); |
| | | process.setApproveUserCurrentId(first.getApproveNodeUserId()); |
| | | process.setApproveUserCurrentName(first.getApproveNodeUser()); |
| | | process.setUpdateTime(LocalDateTime.now()); |
| | | approveProcessMapper.updateById(process); |
| | | } |
| | | |
| | | private boolean matchesCondition(BigDecimal amount, ApproveNodeVO node) { |
| | | String operator = node.getConditionOperator(); |
| | | if (!StringUtils.hasText(operator) || "ALWAYS".equalsIgnoreCase(operator)) return true; |
| | | if (!"amount".equals(node.getConditionField())) throw new RuntimeException("审批条件仅支持金额字段"); |
| | | if (amount == null || !StringUtils.hasText(node.getConditionValue())) return false; |
| | | try { |
| | | if ("BETWEEN".equalsIgnoreCase(operator)) { |
| | | String[] values = node.getConditionValue().replace("[", "").replace("]", "").split(","); |
| | | if (values.length != 2) throw new RuntimeException("金额区间格式不正确"); |
| | | return amount.compareTo(new BigDecimal(values[0].trim())) >= 0 |
| | | && amount.compareTo(new BigDecimal(values[1].trim())) <= 0; |
| | | } |
| | | int compared = amount.compareTo(new BigDecimal(node.getConditionValue())); |
| | | if ("GT".equalsIgnoreCase(operator)) return compared > 0; |
| | | if ("GTE".equalsIgnoreCase(operator)) return compared >= 0; |
| | | if ("LT".equalsIgnoreCase(operator)) return compared < 0; |
| | | if ("LTE".equalsIgnoreCase(operator)) return compared <= 0; |
| | | if ("EQ".equalsIgnoreCase(operator)) return compared == 0; |
| | | } catch (NumberFormatException ex) { |
| | | throw new RuntimeException("审批条件金额格式不正确"); |
| | | } |
| | | throw new RuntimeException("不支持的审批条件操作符"); |
| | | } |
| | | |
| | | @Override |
| | | public List<ApproveNode> details(String id) { |
| | | ApproveProcess approve = approveProcessService.getApproveById(id); |
| | | Long approveId = approve.getId(); |
| | | |
| | | LambdaQueryWrapper<ApproveNode> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(ApproveNode::getApproveProcessId, approveId); |
| | | List<ApproveNode> list = list(queryWrapper); |
| | | // 按照 approveNodeOrder 字段升序排序 |
| | | list.sort(Comparator.comparingInt(ApproveNode::getApproveNodeOrder)); |
| | | return list; |
| | | getApproveById(id); |
| | | List<ApproveNode> nodes = approveNodeMapper.selectList(new LambdaQueryWrapper<ApproveNode>() |
| | | .eq(ApproveNode::getApproveProcessId, id) |
| | | .eq(ApproveNode::getDeleteFlag, 0) |
| | | .eq(ApproveNode::getTenantId, tenantId()) |
| | | .orderByAsc(ApproveNode::getApproveNodeOrder)); |
| | | for (ApproveNode node : nodes) { |
| | | List<CommonFile> files = fileMapper.selectList(new LambdaQueryWrapper<CommonFile>() |
| | | .eq(CommonFile::getCommonId, node.getId()) |
| | | .eq(CommonFile::getType, FileNameType.ApproveNode.getValue())); |
| | | if (!CollectionUtils.isEmpty(files)) node.setUrl(files.get(0).getUrl()); |
| | | node.setIsShen(Integer.valueOf(1).equals(node.getIsCurrent()) |
| | | && node.getApproveNodeUserId().equals(SecurityUtils.getUserId())); |
| | | } |
| | | nodes.sort(Comparator.comparingInt(ApproveNode::getApproveNodeOrder)); |
| | | return nodes; |
| | | } |
| | | |
| | | @Override |
| | | public void updateApproveNode(ApproveNode approveNode) { |
| | | approveProcessService.updateApproveProcessStatus(approveNode); |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateApproveNode(ApproveNode request) throws IOException { |
| | | if (request == null || request.getId() == null) throw new RuntimeException("审批节点不能为空"); |
| | | if (request.getApproveNodeStatus() == null || (request.getApproveNodeStatus() != 1 && request.getApproveNodeStatus() != 2)) { |
| | | throw new RuntimeException("审批结果不正确"); |
| | | } |
| | | if (!StringUtils.hasText(request.getApproveNodeReason())) throw new RuntimeException("审批意见不能为空"); |
| | | Long tenantId = tenantId(); |
| | | ApproveNode node = approveNodeMapper.selectOne(new LambdaQueryWrapper<ApproveNode>() |
| | | .eq(ApproveNode::getId, request.getId()) |
| | | .eq(ApproveNode::getTenantId, tenantId) |
| | | .eq(ApproveNode::getDeleteFlag, 0)); |
| | | if (node == null) throw new RuntimeException("审批节点不存在"); |
| | | if (!Integer.valueOf(0).equals(node.getApproveNodeStatus()) || !Integer.valueOf(1).equals(node.getIsCurrent())) { |
| | | throw new RuntimeException("该节点已经处理或不是当前审批节点"); |
| | | } |
| | | if (!SecurityUtils.getUserId().equals(node.getApproveNodeUserId())) throw new RuntimeException("当前用户无权审批此节点"); |
| | | |
| | | approveNode.setApproveNodeTime(new Date()); |
| | | ApproveProcess process = getApproveById(node.getApproveProcessId()); |
| | | if (Integer.valueOf(2).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus())) { |
| | | throw new RuntimeException("审批流程已经结束"); |
| | | } |
| | | node.setApproveNodeStatus(request.getApproveNodeStatus()); |
| | | node.setApproveNodeReason(request.getApproveNodeReason().trim()); |
| | | node.setApproveNodeRemark(request.getApproveNodeRemark()); |
| | | node.setApproveNodeTime(new Date()); |
| | | node.setIsCurrent(0); |
| | | node.setUpdateUser(SecurityUtils.getUserId()); |
| | | node.setUpdateTime(LocalDateTime.now()); |
| | | approveNodeMapper.updateById(node); |
| | | |
| | | approveNodeMapper.updateById(approveNode); |
| | | if (node.getApproveNodeStatus() == 2) { |
| | | process.setApproveStatus(3); |
| | | process.setApproveUserCurrentId(null); |
| | | process.setApproveUserCurrentName(null); |
| | | process.setApproveOverTime(new Date()); |
| | | } else { |
| | | ApproveNode next = approveNodeMapper.selectOne(new LambdaQueryWrapper<ApproveNode>() |
| | | .eq(ApproveNode::getApproveProcessId, node.getApproveProcessId()) |
| | | .eq(ApproveNode::getTenantId, tenantId) |
| | | .eq(ApproveNode::getDeleteFlag, 0) |
| | | .eq(ApproveNode::getApproveNodeStatus, 0) |
| | | .gt(ApproveNode::getApproveNodeOrder, node.getApproveNodeOrder()) |
| | | .orderByAsc(ApproveNode::getApproveNodeOrder) |
| | | .last("limit 1")); |
| | | if (next == null) { |
| | | process.setApproveStatus(2); |
| | | process.setApproveOverTime(new Date()); |
| | | process.setApproveUserCurrentId(null); |
| | | process.setApproveUserCurrentName(null); |
| | | } else { |
| | | next.setIsCurrent(1); |
| | | next.setUpdateTime(LocalDateTime.now()); |
| | | approveNodeMapper.updateById(next); |
| | | process.setApproveStatus(1); |
| | | process.setApproveUserCurrentId(next.getApproveNodeUserId()); |
| | | process.setApproveUserCurrentName(next.getApproveNodeUser()); |
| | | } |
| | | } |
| | | process.setUpdateTime(LocalDateTime.now()); |
| | | approveProcessMapper.updateById(process); |
| | | |
| | | ApproveLog log = new ApproveLog(); |
| | | log.setApproveId(process.getId()); |
| | | log.setApproveProcessId(process.getId()); |
| | | log.setApproveNodeId(node.getId()); |
| | | log.setApproveNodeOrder(node.getApproveNodeOrder()); |
| | | log.setApproveUser(SecurityUtils.getUserId()); |
| | | log.setApproveUserName(node.getApproveNodeUser()); |
| | | log.setApproveTime(new Date()); |
| | | log.setApproveStatus(node.getApproveNodeStatus()); |
| | | log.setApproveRemark(node.getApproveNodeReason()); |
| | | log.setTenantId(tenantId); |
| | | approveLogMapper.insert(log); |
| | | |
| | | if (!CollectionUtils.isEmpty(request.getTempFileIds()) && node.getApproveNodeStatus() == 1) { |
| | | tempFileService.migrateTempFilesToFormal(node.getId(), request.getTempFileIds(), FileNameType.ApproveNode.getValue()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void delApproveNodeByApproveId(String id) { |
| | | UpdateWrapper<ApproveNode> wrapper = new UpdateWrapper<>(); |
| | | wrapper.lambda().set(ApproveNode::getDeleteFlag, 1) |
| | | .set(ApproveNode::getIsCurrent, 0) |
| | | .eq(ApproveNode::getApproveProcessId, id) |
| | | .eq(ApproveNode::getTenantId, tenantId()); |
| | | update(wrapper); |
| | | } |
| | | |
| | | private Long tenantId() { |
| | | return SecurityUtils.getLoginUser().getTenantId(); |
| | | } |
| | | } |