liding
5 天以前 dc5e5c07549b493e21c11dc7929c32ea9fd732b0
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -5,28 +5,40 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.approve.enums.ApproveType;
import com.ruoyi.approve.mapper.ApproveFlowDefinitionMapper;
import com.ruoyi.approve.mapper.ApproveFlowNodeDefinitionMapper;
import com.ruoyi.approve.mapper.ApproveNodeMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveFlowDefinition;
import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
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.utils.DailyRedisCounter;
import com.ruoyi.approve.vo.ApproveGetAndUpdateVo;
import com.ruoyi.approve.vo.ApproveNodeVO;
import com.ruoyi.approve.vo.ApproveProcessVO;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.other.service.impl.TempFileServiceImpl;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import lombok.AllArgsConstructor;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.SalesLedger;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
@@ -35,7 +47,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@@ -43,120 +57,270 @@
public class ApproveProcessServiceImpl extends ServiceImpl<ApproveProcessMapper, ApproveProcess> implements IApproveProcessService {
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
    private final StringRedisTemplate redisTemplate;
    private final DailyRedisCounter dailyRedisCounter;
    private final SysDeptMapper sysDeptMapper;
    private final IApproveNodeService approveNodeService;
    private final SysUserMapper sysUserMapper;
    private final ApproveProcessMapper approveProcessMapper;
    private final ApproveNodeMapper approveNodeMapper;
    private final TempFileServiceImpl tempFileService;
    private final CommonFileMapper commonFileMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final ApproveFlowDefinitionMapper flowDefinitionMapper;
    private final ApproveFlowNodeDefinitionMapper flowNodeDefinitionMapper;
    private final ObjectMapper objectMapper;
    @Override
    public void addApprove(ApproveProcessVO approveProcessVO) throws ParseException {
        SysUser sysUser = sysUserMapper.selectUserById(approveProcessVO.getApproveUser());
        SysDept sysDept = sysDeptMapper.selectDeptById(approveProcessVO.getApproveDeptId());
        String[] split = approveProcessVO.getApproveUserIds().split(",");
        List<Long> longList = Arrays.stream(split)
                .map(Long::valueOf)  // 将每个 String 转换为 Long
                .collect(Collectors.toList());
        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(longList);
        if(CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("审核用户不存在");
        if(sysDept == null) throw new RuntimeException("部门不存在");
        if(sysUser == null) throw new RuntimeException("申请人不存在");
        String today = LocalDate.now().format(DATE_FORMAT);
        Long approveId = dailyRedisCounter.incrementAndGetByDb();
        String formattedCount = String.format("%03d", approveId);
        //流程 ID
        String approveID = today + formattedCount;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        ApproveProcess approveProcess = new ApproveProcess();
        approveProcess.setApproveId(approveID);
        approveProcess.setApproveUser(approveProcessVO.getApproveUser());
        approveProcess.setApproveUserName(sysUser.getNickName());
        approveProcess.setApproveDeptId(approveProcessVO.getApproveDeptId());
        approveProcess.setApproveDeptName(sysDept.getDeptName());
        approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? null : dateFormat.parse(approveProcessVO.getApproveTime()));
        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
        approveProcess.setApproveOverTime(null);
        approveProcess.setApproveStatus(0);
        approveProcess.setApproveDelete(0);
        approveProcess.setCreateTime(LocalDateTime.now());
        approveProcess.setTenantId(approveProcessVO.getApproveDeptId());
        approveProcess.setApproveUserIds(approveProcessVO.getApproveUserIds());
        approveProcess.setApproveUserCurrentId(longList.get(0));
        approveProcess.setApproveUserCurrentName(sysUsers
                .stream()
                .filter(SysUser -> SysUser.getUserId().equals(longList.get(0)))
                .collect(Collectors.toList())
                .get(0)
                .getNickName());
        save(approveProcess);
        //初始化审批节点
        approveNodeService.initApproveNodes(approveProcessVO.getApproveUserIds(),approveID,approveProcessVO.getApproveDeptId());
    public void addApprove(ApproveProcessVO request) throws Exception {
        if (request == null || request.getApproveType() == null) throw new RuntimeException("审批类型不能为空");
        ApproveType type = ApproveType.fromCode(request.getApproveType());
        Long tenantId = tenantId();
        SysUser applicant = SecurityUtils.getLoginUser().getUser();
        Long deptId = resolveDeptId(request.getApproveDeptId());
        SysDept dept = sysDeptMapper.selectDeptById(deptId);
        if (dept == null) throw new RuntimeException("申请部门不存在");
        List<ApproveNodeVO> nodes = resolveNodes(request, tenantId);
        List<SysUser> approvers = validateApprovers(nodes, tenantId);
        prepareBusinessData(request, type, tenantId);
        String approveCode = LocalDate.now().format(DATE_FORMAT)
                + String.format("%03d", dailyRedisCounter.incrementAndGetByDb());
        ApproveProcess process = new ApproveProcess();
        process.setApproveId(approveCode);
        process.setApproveUser(applicant.getUserId());
        process.setApproveUserName(applicant.getNickName());
        process.setApproveDeptId(deptId);
        process.setApproveDeptName(dept.getDeptName());
        process.setApproveUserIds(nodes.stream().map(item -> String.valueOf(item.getUserId())).collect(Collectors.joining(",")));
        process.setApproveUserNames(approvers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
        process.setApproveTime(parseDate(request.getApproveTime()));
        process.setApproveReason(request.getApproveReason());
        process.setApproveStatus(0);
        process.setApproveDelete(0);
        process.setApproveType(type.getCode());
        process.setTenantId(tenantId);
        process.setBusinessId(request.getBusinessId());
        process.setBusinessNo(request.getBusinessNo());
        process.setBusinessTitle(request.getBusinessTitle());
        process.setAmount(request.getAmount());
        process.setBusinessData(request.getBusinessData());
        process.setFlowDefinitionId(request.getFlowDefinitionId());
        process.setCreateTime(LocalDateTime.now());
        process.setUpdateTime(LocalDateTime.now());
        approveProcessMapper.insert(process);
        approveNodeService.initApproveNodes(nodes, approveCode, tenantId);
        tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
    }
    private void prepareBusinessData(ApproveProcessVO request, ApproveType type, Long tenantId) throws JsonProcessingException {
        if (type == ApproveType.SALES_CONTRACT) {
            if (request.getBusinessId() == null) throw new RuntimeException("请选择销售合同");
            SalesLedger ledger = salesLedgerMapper.selectById(request.getBusinessId());
            if (ledger == null || !tenantId.equals(ledger.getTenantId())) throw new RuntimeException("销售合同不存在或不属于当前租户");
            Long duplicate = approveProcessMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>()
                    .eq(ApproveProcess::getTenantId, tenantId)
                    .eq(ApproveProcess::getApproveType, ApproveType.SALES_CONTRACT.getCode())
                    .eq(ApproveProcess::getBusinessId, ledger.getId())
                    .in(ApproveProcess::getApproveStatus, Arrays.asList(0, 1))
                    .eq(ApproveProcess::getApproveDelete, 0));
            if (duplicate != null && duplicate > 0) throw new RuntimeException("该销售合同已有待审流程");
            Map<String, Object> snapshot = new LinkedHashMap<>();
            snapshot.put("salesLedgerId", ledger.getId());
            snapshot.put("salesContractNo", ledger.getSalesContractNo());
            snapshot.put("customerContractNo", ledger.getCustomerContractNo());
            snapshot.put("customerName", ledger.getCustomerName());
            snapshot.put("projectName", ledger.getProjectName());
            snapshot.put("salesman", ledger.getSalesman());
            snapshot.put("contractAmount", ledger.getContractAmount());
            snapshot.put("executionDate", ledger.getExecutionDate());
            snapshot.put("paymentMethod", ledger.getPaymentMethod());
            snapshot.put("remarks", ledger.getRemarks());
            request.setBusinessNo(ledger.getSalesContractNo());
            request.setBusinessTitle(StringUtils.hasText(request.getBusinessTitle())
                    ? request.getBusinessTitle() : "销售合同审批-" + ledger.getSalesContractNo());
            request.setAmount(ledger.getContractAmount());
            request.setBusinessData(objectMapper.writeValueAsString(snapshot));
        } else if (type == ApproveType.PURCHASE_PLAN || type == ApproveType.FREE_COLLABORATION) {
            if (!StringUtils.hasText(request.getBusinessTitle())) throw new RuntimeException("审批标题不能为空");
            if (type == ApproveType.PURCHASE_PLAN && request.getAmount() == null) throw new RuntimeException("采购预算金额不能为空");
            if (!StringUtils.hasText(request.getBusinessNo())) {
                String prefix = type == ApproveType.PURCHASE_PLAN ? "CG" : "XT";
                request.setBusinessNo(prefix + LocalDate.now().format(DATE_FORMAT)
                        + String.format("%03d", dailyRedisCounter.incrementAndGetByDb()));
            }
        }
    }
    private List<ApproveNodeVO> resolveNodes(ApproveProcessVO request, Long tenantId) {
        if (!CollectionUtils.isEmpty(request.getNodes())) return request.getNodes();
        if (request.getFlowDefinitionId() != null) {
            ApproveFlowDefinition definition = flowDefinitionMapper.selectOne(new LambdaQueryWrapper<ApproveFlowDefinition>()
                    .eq(ApproveFlowDefinition::getId, request.getFlowDefinitionId())
                    .eq(ApproveFlowDefinition::getTenantId, tenantId)
                    .eq(ApproveFlowDefinition::getApproveType, request.getApproveType())
                    .eq(ApproveFlowDefinition::getEnabled, 1)
                    .eq(ApproveFlowDefinition::getDeleteFlag, 0));
            if (definition == null) throw new RuntimeException("审批流程定义不存在或已停用");
            List<ApproveFlowNodeDefinition> definitions = flowNodeDefinitionMapper.selectList(
                    new LambdaQueryWrapper<ApproveFlowNodeDefinition>()
                            .eq(ApproveFlowNodeDefinition::getFlowDefinitionId, definition.getId())
                            .eq(ApproveFlowNodeDefinition::getTenantId, tenantId)
                            .eq(ApproveFlowNodeDefinition::getDeleteFlag, 0)
                            .orderByAsc(ApproveFlowNodeDefinition::getNodeOrder));
            List<ApproveNodeVO> result = new ArrayList<>();
            for (ApproveFlowNodeDefinition item : definitions) {
                if (!"USER".equals(item.getApproverType()) || !StringUtils.hasText(item.getApproverValue())) {
                    throw new RuntimeException("当前预设流程包含尚未指定的审批人");
                }
                ApproveNodeVO node = new ApproveNodeVO();
                node.setUserId(Long.valueOf(item.getApproverValue().split(",")[0].trim()));
                node.setNodeName(item.getNodeName());
                node.setConditionField(item.getConditionField());
                node.setConditionOperator(item.getConditionOperator());
                node.setConditionValue(item.getConditionValue());
                result.add(node);
            }
            if (!result.isEmpty()) return result;
        }
        if (!StringUtils.hasText(request.getApproveUserIds())) throw new RuntimeException("请选择审批人");
        List<ApproveNodeVO> result = new ArrayList<>();
        for (String id : request.getApproveUserIds().split(",")) {
            ApproveNodeVO node = new ApproveNodeVO();
            node.setUserId(Long.valueOf(id.trim()));
            node.setConditionOperator("ALWAYS");
            result.add(node);
        }
        return result;
    }
    private List<SysUser> validateApprovers(List<ApproveNodeVO> nodes, Long tenantId) {
        List<SysUser> users = new ArrayList<>();
        for (ApproveNodeVO node : nodes) {
            SysUser user = sysUserMapper.selectUserById(node.getUserId());
            if (user == null || !tenantId.equals(user.getTenantId())) throw new RuntimeException("审批人不存在或不属于当前租户");
            users.add(user);
        }
        return users;
    }
    @Override
    public List<SysDept> selectDeptListByDeptIds(Long[] deptIds) {
        List<SysDept> sysDeptList =new ArrayList<SysDept>();
        List<SysDept> departments = new ArrayList<>();
        if (deptIds == null) return departments;
        for (Long deptId : deptIds) {
            SysDept sysDept = sysDeptMapper.selectDeptById(deptId);
            sysDeptList.add(sysDept);
            SysDept dept = sysDeptMapper.selectDeptById(deptId);
            if (dept != null) departments.add(dept);
        }
        return sysDeptList;
        return departments;
    }
    @Override
    public IPage<ApproveProcess> listAll(Page page,ApproveProcess approveProcess) {
        IPage<ApproveProcess> approveProcessIPage = approveProcessMapper.listPage(page,approveProcess);
        return approveProcessIPage;
    public IPage<ApproveProcess> listAll(Page page, ApproveProcess request) {
        request.setTenantId(tenantId());
        IPage<ApproveProcess> result = approveProcessMapper.listPage(page, request);
        result.getRecords().forEach(record -> record.setCommonFileList(commonFileMapper.selectList(
                new LambdaQueryWrapper<CommonFile>()
                        .eq(CommonFile::getCommonId, record.getId())
                        .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()))));
        return result;
    }
    @Override
    public void delApprove(Long[] ids) {
        for (Long id : ids) {
            UpdateWrapper<ApproveProcess> queryWrapper = new UpdateWrapper<>();
            queryWrapper.lambda().set(ApproveProcess::getApproveDelete, 1)
                    .eq(ApproveProcess::getApproveId, id);
            update(queryWrapper);
            // 删除关联的审批节点
            approveNodeService.delApproveNodeByApproveId(id);
    public void delApprove(String[] ids) {
        if (ids == null) return;
        for (String code : ids) {
            ApproveProcess process = findOwnedByCode(code);
            if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("只能删除本人申请");
            if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
                throw new RuntimeException("审核中的流程不能删除");
            }
            UpdateWrapper<ApproveProcess> wrapper = new UpdateWrapper<>();
            wrapper.lambda().set(ApproveProcess::getApproveDelete, 1)
                    .set(ApproveProcess::getUpdateTime, LocalDateTime.now())
                    .eq(ApproveProcess::getApproveId, code)
                    .eq(ApproveProcess::getTenantId, tenantId());
            update(wrapper);
            approveNodeService.delApproveNodeByApproveId(code);
        }
    }
    @Override
    public ApproveProcess getApproveById(String id) {
        LambdaQueryWrapper<ApproveProcess> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApproveProcess::getApproveId, id);
        queryWrapper.eq(ApproveProcess::getApproveDelete, 0);
        queryWrapper.eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId());
        queryWrapper.last("limit 1");
        ApproveProcess one = getOne(queryWrapper);
        return one;
        ApproveProcess process = findOwnedByCode(id);
        process.setCommonFileList(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
                .eq(CommonFile::getCommonId, process.getId())
                .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue())));
        return process;
    }
    @Override
    public void updateApproveProcessStatus(ApproveNode approveNode,Integer status) {
        LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveId, approveNode.getApproveProcessId())
    public void updateByApproveId(ApproveGetAndUpdateVo request) throws IOException {
        ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
                .eq(ApproveProcess::getId, request.getId())
                .eq(ApproveProcess::getTenantId, tenantId())
                .eq(ApproveProcess::getApproveDelete, 0));
        if (process == null) throw new RuntimeException("审批不存在");
        if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("只能编辑本人申请");
        if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
            throw new RuntimeException("当前审批状态不允许编辑");
        }
        process.setApproveReason(request.getApproveReason());
        process.setBusinessTitle(request.getBusinessTitle());
        process.setAmount(request.getAmount());
        process.setBusinessData(request.getBusinessData());
        process.setUpdateTime(LocalDateTime.now());
        process.setApproveStatus(0);
        process.setApproveOverTime(null);
        approveProcessMapper.updateById(process);
        List<ApproveNodeVO> nodes = request.getNodes();
        if (CollectionUtils.isEmpty(nodes) && StringUtils.hasText(request.getApproveUserIds())) {
            nodes = new ArrayList<>();
            for (String id : request.getApproveUserIds().split(",")) {
                ApproveNodeVO node = new ApproveNodeVO();
                node.setUserId(Long.valueOf(id.trim()));
                node.setConditionOperator("ALWAYS");
                nodes.add(node);
            }
        }
        if (!CollectionUtils.isEmpty(nodes)) {
            validateApprovers(nodes, tenantId());
            UpdateWrapper<ApproveNode> oldNodes = new UpdateWrapper<>();
            oldNodes.lambda().set(ApproveNode::getDeleteFlag, 1)
                    .set(ApproveNode::getIsCurrent, 0)
                    .eq(ApproveNode::getApproveProcessId, process.getApproveId())
                    .eq(ApproveNode::getTenantId, tenantId());
            approveNodeMapper.update(null, oldNodes);
            approveNodeService.initApproveNodes(nodes, process.getApproveId(), tenantId());
        }
        tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
    }
    private ApproveProcess findOwnedByCode(String code) {
        ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
                .eq(ApproveProcess::getApproveId, code)
                .eq(ApproveProcess::getApproveDelete, 0)
                .eq(ApproveProcess::getTenantId, SecurityUtils.getLoginUser().getTenantId())
                .last("limit 1");
        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
        if(approveProcess == null) throw new RuntimeException("审批不存在");
        approveProcess.setApproveStatus(status);
        updateById(approveProcess);
                .eq(ApproveProcess::getTenantId, tenantId())
                .last("limit 1"));
        if (process == null) throw new RuntimeException("审批不存在");
        return process;
    }
    @Override
    public void updateByApproveId(ApproveGetAndUpdateVo approveGetAndUpdateVo) {
        ApproveProcess approve = getApproveById(approveGetAndUpdateVo.getId());
        approve.setApproveReason(approveGetAndUpdateVo.getApproveReason());
        updateById(approve);
    private Long resolveDeptId(Long requested) {
        Long[] allowed = SecurityUtils.getDeptId();
        if (requested == null) return SecurityUtils.getLoginUser().getCurrentDeptId();
        if (allowed != null && Arrays.asList(allowed).contains(requested)) return requested;
        Long current = SecurityUtils.getLoginUser().getCurrentDeptId();
        if (requested.equals(current)) return requested;
        throw new RuntimeException("无权使用该申请部门");
    }
    private Date parseDate(String value) throws ParseException {
        return StringUtils.hasText(value) ? new SimpleDateFormat("yyyy-MM-dd").parse(value) : new Date();
    }
    private Long tenantId() {
        return SecurityUtils.getLoginUser().getTenantId();
    }
}