liu
8 天以前 06c312e584b99df613728d5ea8b32df4e156f3cc
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorServiceImpl.java
@@ -2,12 +2,14 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.MesWmReturnVendorPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.MesWmReturnVendorSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.line.MesWmReturnVendorLineSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorLineDO;
@@ -15,7 +17,10 @@
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnVendorStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService;
import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchaseOrderApi;
import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO;
import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderRespDTO;
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import jakarta.annotation.Resource;
@@ -24,7 +29,9 @@
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -45,32 +52,71 @@
    @Resource
    private MesWmReturnVendorDetailService returnVendorDetailService;
    @Resource
    private MesMdVendorService vendorService;
    private SrmSupplierApi srmSupplierApi;
    @Resource
    private MesWmTransactionService wmTransactionService;
    @Resource
    private ErpPurchaseOrderApi purchaseOrderApi;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createReturnVendor(MesWmReturnVendorSaveReqVO createReqVO) {
        // 1. 校验数据
        validateReturnVendorSaveData(createReqVO);
        // 1.1. 若采购订单号为空但关联了采购订单,则从 ERP 采购订单补齐订单号
        fillPurchaseOrderCode(createReqVO);
        // 2. 插入主表
        MesWmReturnVendorDO returnVendor = BeanUtils.toBean(createReqVO, MesWmReturnVendorDO.class);
        returnVendor.setStatus(MesWmReturnVendorStatusEnum.PREPARE.getStatus());
        returnVendorMapper.insert(returnVendor);
        // 2.1. 关联了采购订单:自动把订单物料带入退货行(无可退物料时静默,不影响单据创建)
        if (returnVendor.getPurchaseOrderId() != null) {
            autoImportLinesFromLinkedOrder(returnVendor.getId(), false);
        }
        return returnVendor.getId();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateReturnVendor(MesWmReturnVendorSaveReqVO updateReqVO) {
        // 1. 校验数据
        validateReturnVendorSaveData(updateReqVO);
        // 1. 校验数据(含存在 + 草稿状态)
        MesWmReturnVendorDO oldReturnVendor = validateReturnVendorSaveData(updateReqVO);
        // 1.1. 若采购订单号为空但关联了采购订单,则从 ERP 采购订单补齐订单号
        fillPurchaseOrderCode(updateReqVO);
        Long oldPurchaseOrderId = oldReturnVendor != null ? oldReturnVendor.getPurchaseOrderId() : null;
        Long newPurchaseOrderId = updateReqVO.getPurchaseOrderId();
        boolean purchaseOrderChanged = !ObjUtil.equal(oldPurchaseOrderId, newPurchaseOrderId);
        // 2. 更新主表
        MesWmReturnVendorDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorDO.class);
        returnVendorMapper.updateById(updateObj);
        // 3. 关联了采购订单:自动同步物料行,保证行物料与该采购订单一致
        //    3.1 更换了采购订单 → 先清空旧订单带入的行,再按新订单重新带入
        //    3.2 采购订单未变但当前无行 → 兜底自动带入(历史数据或带料被中断的场景)
        if (newPurchaseOrderId != null) {
            autoImportLinesFromLinkedOrder(updateReqVO.getId(), purchaseOrderChanged);
        }
    }
    /**
     * 当采购订单号为空、但关联了采购订单时,从 ERP 采购订单补齐采购订单号
     */
    private void fillPurchaseOrderCode(MesWmReturnVendorSaveReqVO reqVO) {
        if (reqVO == null || reqVO.getPurchaseOrderId() == null) {
            return;
        }
        if (cn.hutool.core.util.StrUtil.isNotBlank(reqVO.getPurchaseOrderCode())) {
            return;
        }
        ErpPurchaseOrderRespDTO purchaseOrder =
                purchaseOrderApi.getPurchaseOrder(reqVO.getPurchaseOrderId()).getCheckedData();
        if (purchaseOrder != null) {
            reqVO.setPurchaseOrderCode(purchaseOrder.getNo());
        }
    }
    @Override
@@ -210,16 +256,50 @@
    /**
     * 校验退货单创建/修改的公共数据
     *
     * @return 修改时返回旧单据(用于比较采购订单是否变更);创建时返回 null
     */
    private void validateReturnVendorSaveData(MesWmReturnVendorSaveReqVO reqVO) {
    private MesWmReturnVendorDO validateReturnVendorSaveData(MesWmReturnVendorSaveReqVO reqVO) {
        // 校验存在 + 草稿状态(仅修改时)
        MesWmReturnVendorDO oldReturnVendor = null;
        if (reqVO.getId() != null) {
            validateReturnVendorExistsAndPrepare(reqVO.getId());
            oldReturnVendor = validateReturnVendorExistsAndPrepare(reqVO.getId());
        }
        // 校验供应商存在
        vendorService.validateVendorExistsAndEnable(reqVO.getVendorId());
        srmSupplierApi.getSupplier(reqVO.getVendorId());
        // 校验编码唯一
        validateCodeUnique(reqVO.getId(), reqVO.getCode());
        return oldReturnVendor;
    }
    /**
     * 把关联采购订单的物料自动带入退货单行(仅草稿状态且已关联采购订单时生效)。
     *
     * @param id         退货单编号
     * @param clearFirst 是否先清空已有行再带入;更换采购订单时传 true
     */
    private void autoImportLinesFromLinkedOrder(Long id, boolean clearFirst) {
        MesWmReturnVendorDO returnVendor = returnVendorMapper.selectById(id);
        if (returnVendor == null || returnVendor.getPurchaseOrderId() == null) {
            return;
        }
        List<MesWmReturnVendorLineDO> existingLines =
                returnVendorLineService.getReturnVendorLineListByReturnId(id);
        if (clearFirst) {
            if (CollUtil.isNotEmpty(existingLines)) {
                // 级联删除旧明细与行
                returnVendorDetailService.deleteReturnVendorDetailByReturnId(id);
                returnVendorLineService.deleteReturnVendorLineByReturnId(id);
            }
        } else if (CollUtil.isNotEmpty(existingLines)) {
            // 已有行且未更换采购订单:不重复带入,避免覆盖用户已调整的数量
            return;
        }
        try {
            importPurchaseOrderItems(id);
        } catch (ServiceException ignore) {
            // 采购订单无明细 / 无可退物料等业务异常:单据主体仍正常保存,可在物料区另行处理
        }
    }
    /**
@@ -240,4 +320,53 @@
        return returnVendorMapper.selectCountByVendorId(vendorId);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int importPurchaseOrderItems(Long id) {
        // 1. 校验退货单存在且为草稿状态
        MesWmReturnVendorDO returnVendor = validateReturnVendorExistsAndPrepare(id);
        if (returnVendor.getPurchaseOrderId() == null) {
            throw exception(WM_RETURN_VENDOR_PURCHASE_ORDER_REQUIRED);
        }
        // 2. 获取采购订单及明细
        ErpPurchaseOrderRespDTO purchaseOrder = purchaseOrderApi.getPurchaseOrder(returnVendor.getPurchaseOrderId()).getCheckedData();
        if (purchaseOrder == null) {
            throw exception(WM_PURCHASE_ORDER_NOT_EXISTS);
        }
        List<ErpPurchaseOrderItemRespDTO> items = purchaseOrderApi.getPurchaseOrderItemList(returnVendor.getPurchaseOrderId()).getCheckedData();
        if (CollUtil.isEmpty(items)) {
            throw exception(WM_RETURN_VENDOR_PURCHASE_ORDER_NO_ITEM);
        }
        // 3. 已存在的行物料集合(按物料去重,避免重复带入)
        Set<Long> existsItemIds = new HashSet<>();
        List<MesWmReturnVendorLineDO> existingLines = returnVendorLineService.getReturnVendorLineListByReturnId(id);
        if (CollUtil.isNotEmpty(existingLines)) {
            existsItemIds.addAll(convertList(existingLines, MesWmReturnVendorLineDO::getItemId));
        }
        // 4. 遍历采购订单明细,生成退货行(可退数量 = 已入库 - 已退货)
        int importedCount = 0;
        for (ErpPurchaseOrderItemRespDTO item : items) {
            if (item.getProductId() == null || existsItemIds.contains(item.getProductId())) {
                continue;
            }
            BigDecimal inCount = item.getInCount() != null ? item.getInCount() : BigDecimal.ZERO;
            BigDecimal returnCount = item.getReturnCount() != null ? item.getReturnCount() : BigDecimal.ZERO;
            BigDecimal quantity = inCount.subtract(returnCount);
            if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            MesWmReturnVendorLineSaveReqVO lineReqVO = new MesWmReturnVendorLineSaveReqVO();
            lineReqVO.setReturnId(id);
            lineReqVO.setItemId(item.getProductId());
            lineReqVO.setQuantity(quantity);
            lineReqVO.setRemark(item.getRemark());
            returnVendorLineService.createReturnVendorLine(lineReqVO);
            importedCount++;
        }
        return importedCount;
    }
}