20 小时以前 61f1de60e6f58dd8e19f01c56f2e56e40885d65b
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -40,12 +40,15 @@
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.utils.QualityInspectHelper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.SalesQuotationMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.mapper.ShippingProductDetailMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.pojo.ShippingProductDetail;
import com.ruoyi.staff.mapper.HolidayApplicationMapper;
import com.ruoyi.staff.pojo.HolidayApplication;
import lombok.RequiredArgsConstructor;
@@ -94,9 +97,13 @@
    private final EnterpriseNewsMapper enterpriseNewsMapper;
    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
    private final ShippingProductDetailMapper shippingProductDetailMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    @Override
    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
        // 注入当前用户ID,用于过滤只查看申请人和审核人是自己的数据
        approvalInstanceDto.setCurrentUserId(SecurityUtils.getUserId());
        IPage<ApprovalInstanceVo> approvalInstanceVoIPage = approvalInstanceMapper.listPage(page, approvalInstanceDto);
        List<ApprovalInstanceVo> records = approvalInstanceVoIPage.getRecords();
@@ -105,6 +112,30 @@
        }
        records.forEach(vo -> {
            vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType()));
            // 根据业务类型查询对应的单号
            if (vo.getBusinessType() != null && vo.getBusinessId() != null) {
                if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(vo.getBusinessType())) {
                    // 采购审批 - 查询采购单号
                    PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(vo.getBusinessId());
                    System.out.println("业务类型:" + purchaseLedger.getPurchaseContractNumber());
                    if (purchaseLedger != null) {
                        vo.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber());
                    }
                } else if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(vo.getBusinessType())) {
                    // 报价审批 - 查询报价单号
                    SalesQuotation salesQuotation = salesQuotationMapper.selectById(vo.getBusinessId());
                    if (salesQuotation != null) {
                        vo.setQuotationNo(salesQuotation.getQuotationNo());
                    }
                } else if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(vo.getBusinessType())) {
                    // 发货审批 - 查询发货单号
                    ShippingInfo shippingInfo = shippingInfoMapper.selectById(vo.getBusinessId());
                    if (shippingInfo != null) {
                        vo.setShippingNo(shippingInfo.getShippingNo());
                    }
                }
            }
        });
        Long currentUserId = SecurityUtils.getUserId();
@@ -140,7 +171,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(ApprovalInstanceDto approvalInstanceDto) {
        String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no");
        String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", approvalInstanceDto.getCreateTime() != null ? approvalInstanceDto.getCreateTime() : LocalDateTime.now());
        approvalInstanceDto.setInstanceNo(instanceNo);
        approvalInstanceDto.setStatus("PENDING");
        approvalInstanceDto.setCurrentLevel(1);
@@ -231,6 +262,12 @@
            return R.fail("审批实例不存在");
        }
        // 如果前端传递了仓库信息,更新审批实例的仓库字段
        if (StringUtils.hasText(approvalInstanceDto.getWarehouse())) {
            instance.setWarehouse(approvalInstanceDto.getWarehouse());
            this.updateById(instance);
        }
        ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(instance.getId());
        if (currentNode == null) {
            return R.fail("当前没有待处理的审批节点");
@@ -268,6 +305,87 @@
        }
        return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R autoApprove(Long instanceId) {
        if (instanceId == null) {
            return R.fail("审批实例 ID 不能为空");
        }
        ApprovalInstance instance = getPendingApprovalInstance(instanceId);
        if (instance == null) {
            return R.fail("审批实例不存在");
        }
        if ("REJECTED".equals(instance.getStatus())) {
            return R.fail("审批已驳回,无法自动通过");
        }
        if ("APPROVED".equals(instance.getStatus())) {
            return R.ok("审批已完成");
        }
        ApprovalInstanceDto autoApproveDto = new ApprovalInstanceDto();
        autoApproveDto.setId(instanceId);
        autoApproveDto.setApproveComment("系统自动审批");
        int loopCount = 0;
        while (loopCount++ < 20) {
            ApprovalInstance currentInstance = getPendingApprovalInstance(instanceId);
            if (currentInstance == null) {
                return R.fail("审批实例不存在");
            }
            if ("APPROVED".equals(currentInstance.getStatus())) {
                return R.ok("审批已完成");
            }
            if ("REJECTED".equals(currentInstance.getStatus())) {
                return R.fail("审批已驳回,无法自动通过");
            }
            ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(currentInstance.getId());
            if (currentNode == null) {
                currentInstance.setStatus("APPROVED");
                currentInstance.setFinishTime(LocalDateTime.now());
                this.updateById(currentInstance);
                handleBusinessAfterApprovalFinished(currentInstance);
                return R.ok("审批已完成");
            }
            List<ApprovalTask> pendingTasks = approvalTaskService.list(
                    Wrappers.<ApprovalTask>lambdaQuery()
                            .eq(ApprovalTask::getInstanceId, currentInstance.getId())
                            .eq(ApprovalTask::getNodeId, currentNode.getId())
                            .eq(ApprovalTask::getTaskStatus, "PENDING")
                            .eq(ApprovalTask::getDeleted, 0)
            );
            LocalDateTime now = LocalDateTime.now();
            for (ApprovalTask currentTask : pendingTasks) {
                if (!updateCurrentTask(autoApproveDto, "APPROVED", currentTask, now)) {
                    return R.fail("当前任务已被处理,请刷新后重试");
                }
                saveApprovalRecord(
                        currentInstance.getId(),
                        currentNode.getId(),
                        currentTask.getId(),
                        0L,
                        "系统自动审批",
                        "APPROVED",
                        autoApproveDto.getApproveComment()
                );
            }
            if (!approveProcessConfigNodeUtils.canProceedToNextLevel(currentInstance.getId(), currentNode.getApproveType())) {
                return R.ok("审批成功,等待其他审批人处理");
            }
            R moveResult = moveToNextLevel(currentInstance, currentNode, autoApproveDto, now, false);
            if (!R.isSuccess(moveResult)) {
                return moveResult;
            }
        }
        return R.fail("自动审批循环次数超限");
    }
    private String normalizeApproveAction(String approveAction) {
@@ -336,6 +454,14 @@
                                 ApprovalInstanceNode currentNode,
                                 ApprovalInstanceDto approvalInstanceDto,
                                 LocalDateTime now) {
        return moveToNextLevel(instance, currentNode, approvalInstanceDto, now, true);
    }
    private R moveToNextLevel(ApprovalInstance instance,
                              ApprovalInstanceNode currentNode,
                              ApprovalInstanceDto approvalInstanceDto,
                              LocalDateTime now,
                              boolean notifyNextNode) {
        if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", now)) {
            return R.ok("当前节点已处理完成");
        }
@@ -359,14 +485,16 @@
            instance.setCurrentLevel(nextLevel);
            instance.setStatus("PENDING");
            this.updateById(instance);
            List<ApprovalTask> nextTasks = approvalTaskService.list(
                    Wrappers.<ApprovalTask>lambdaQuery()
                            .eq(ApprovalTask::getInstanceId, instance.getId())
                            .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
                            .eq(ApprovalTask::getTaskStatus, "PENDING")
                            .eq(ApprovalTask::getDeleted, 0)
            );
            sendApproveNotice(instance, nextTasks);
            if (notifyNextNode) {
                List<ApprovalTask> nextTasks = approvalTaskService.list(
                        Wrappers.<ApprovalTask>lambdaQuery()
                                .eq(ApprovalTask::getInstanceId, instance.getId())
                                .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
                                .eq(ApprovalTask::getTaskStatus, "PENDING")
                                .eq(ApprovalTask::getDeleted, 0)
                );
                sendApproveNotice(instance, nextTasks);
            }
            return R.ok("审批成功,已流转到下一节点");
        }
@@ -390,7 +518,9 @@
        instance.setStatus("PENDING");
        this.updateById(instance);
        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
        sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
        if (notifyNextNode) {
            sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
        }
        return R.ok("审批成功,已流转到下一节点");
    }
@@ -507,7 +637,7 @@
    private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(
                new LambdaQueryWrapper<PurchaseLedger>()
                        .eq(PurchaseLedger::getPurchaseContractNumber, instance.getTitle())
                        .eq(PurchaseLedger::getId, instance.getBusinessId())
                        .last("limit 1")
        );
        if (purchaseLedger == null) {
@@ -530,7 +660,9 @@
                            salesLedgerProduct.getQuantity(),
                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
                            purchaseLedger.getId(),
                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId()
                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId(),
                            null,
                            instance.getWarehouse()
                    );
                }
            }
@@ -545,7 +677,7 @@
    private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) {
        SalesQuotation salesQuote = salesQuotationMapper.selectOne(
                new LambdaQueryWrapper<SalesQuotation>()
                        .eq(SalesQuotation::getQuotationNo, instance.getTitle())
                        .eq(SalesQuotation::getId, instance.getBusinessId())
                        .last("limit 1")
        );
        if (salesQuote == null) {
@@ -565,8 +697,7 @@
    private void handleShippingApprovalFinished(ApprovalInstance instance, String status) {
        ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
                new LambdaQueryWrapper<ShippingInfo>()
                        .eq(ShippingInfo::getShippingNo, instance.getTitle())
                        .orderByDesc(ShippingInfo::getCreateTime)
                        .eq(ShippingInfo::getId, instance.getBusinessId())
                        .last("limit 1")
        );
        if (shippingInfo == null) {
@@ -577,6 +708,9 @@
            shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode());
            shippingInfo.setShippingDate(new Date());
            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
            // 发货审批通过后,自动生成出厂检验单
            createFactoryInspectForShipping(shippingInfo);
        } else if ("REJECTED".equals(status)) {
            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
            shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode());
@@ -586,6 +720,40 @@
        shippingInfoMapper.updateById(shippingInfo);
    }
    /**
     * 发货审批通过后,自动生成出厂检验单
     */
    private void createFactoryInspectForShipping(ShippingInfo shippingInfo) {
        // 查询发货产品明细
        List<ShippingProductDetail> detailList = shippingProductDetailMapper.selectList(
                new LambdaQueryWrapper<ShippingProductDetail>()
                        .eq(ShippingProductDetail::getShippingInfoId, shippingInfo.getId())
        );
        if (detailList == null || detailList.isEmpty()) {
            return;
        }
        // 获取客户名称
        String customerName = null;
        if (shippingInfo.getSalesLedgerId() != null) {
            com.ruoyi.sales.pojo.SalesLedger salesLedger = salesLedgerMapper.selectById(shippingInfo.getSalesLedgerId());
            if (salesLedger != null) {
                customerName = salesLedger.getCustomerName();
            }
        }
        // 为每个发货产品创建出厂检验单
        for (ShippingProductDetail detail : detailList) {
            qualityInspectHelper.addFactoryInspect(
                    shippingInfo,
                    detail,
                    customerName,
                    shippingInfo.getSalesLedgerId()
            );
        }
    }
    private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()