云
4 天以前 5d818f39c862884b7087488d588fef5b7ce47386
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
@@ -2,30 +2,36 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
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.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLinePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLineSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnSalesStatusEnum;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService;
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_BATCH_REQUIRED;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_SALES_LINE_NOT_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
 * MES 销售退货单行 Service 实现类
@@ -43,12 +49,15 @@
    @Lazy
    private MesWmReturnSalesService returnSalesService;
    @Resource
    private MesMdmItemService mdmItemService;
    private MdmItemApi mdmItemApi;
    @Resource
    private MesWmBatchService batchService;
    @Resource
    @Lazy
    private MesWmReturnSalesDetailService returnSalesDetailService;
    @Resource
    @Lazy
    private MesWmProductSalesLineService productSalesLineService;
    @Override
    public Long createReturnSalesLine(MesWmReturnSalesLineSaveReqVO createReqVO) {
@@ -79,12 +88,46 @@
    /**
     * 校验保存时的关联数据
     *
     * <p>退货单关联了销售出库单时,物料、批次一律取自出库行,并校验可退数量;
     * 未关联出库单(如售后模块创建)时,保持原有物料/批次校验逻辑。
     */
    private void validateLineSaveData(MesWmReturnSalesLineSaveReqVO reqVO) {
        // 校验退货单存在 + 草稿状态
        returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId());
        MesWmReturnSalesDO returnSales = returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId());
        if (returnSales.getProductSalesId() != null) {
            validateOutboundLine(reqVO, returnSales);
            return;
        }
        // 校验物料存在 + 批次管理
        validateItemBatchManagement(reqVO.getReturnId(), reqVO.getItemId(), reqVO.getBatchId());
    }
    /**
     * 校验出库行归属与可退数量,并从出库行回填物料、批次
     */
    private void validateOutboundLine(MesWmReturnSalesLineSaveReqVO reqVO, MesWmReturnSalesDO returnSales) {
        if (reqVO.getProductSalesLineId() == null) {
            throw exception(WM_RETURN_SALES_LINE_PRODUCT_SALES_REQUIRED);
        }
        MesWmProductSalesLineDO outboundLine =
                productSalesLineService.validateProductSalesLineExists(reqVO.getProductSalesLineId());
        if (ObjUtil.notEqual(outboundLine.getSalesId(), returnSales.getProductSalesId())) {
            throw exception(WM_RETURN_SALES_LINE_PRODUCT_SALES_NOT_MATCH);
        }
        // 物料、批次必须与出库行一致
        reqVO.setItemId(outboundLine.getItemId());
        reqVO.setBatchId(outboundLine.getBatchId());
        reqVO.setBatchCode(outboundLine.getBatchCode());
        // 可退数量 = 出库数量 - 其它退货单已退数量(排除当前退货单)
        BigDecimal returned = getReturnedQuantityMap(
                Collections.singletonList(outboundLine.getId()), returnSales.getId())
                .getOrDefault(outboundLine.getId(), BigDecimal.ZERO);
        BigDecimal returnable = outboundLine.getQuantity().subtract(returned);
        if (reqVO.getQuantity().compareTo(returnable) > 0) {
            throw exception(WM_RETURN_SALES_LINE_QUANTITY_EXCEED);
        }
    }
    @Override
@@ -129,6 +172,16 @@
    }
    @Override
    public Map<Long, BigDecimal> getReturnedQuantityMap(Collection<Long> productSalesLineIds, Long excludeReturnId) {
        if (CollUtil.isEmpty(productSalesLineIds)) {
            return Collections.emptyMap();
        }
        List<KeyValue<Long, BigDecimal>> list = returnSalesLineMapper.selectReturnedQuantityList(
                productSalesLineIds, MesWmReturnSalesStatusEnum.CANCELED.getStatus(), excludeReturnId);
        return CollectionUtils.convertMap(list, KeyValue::getKey, KeyValue::getValue);
    }
    @Override
    public void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus) {
        List<MesWmReturnSalesLineDO> lines = returnSalesLineMapper.selectListByReturnId(returnId);
        for (MesWmReturnSalesLineDO line : lines) {
@@ -155,7 +208,7 @@
     * @param batchId  批次ID
     */
    private void validateItemBatchManagement(Long returnId, Long itemId, Long batchId) {
        MesMdmItemDO item = mdmItemService.validateItemExistsAndEnable(itemId);
        MdmItemRespDTO item = mdmItemApi.validateItemExistsAndEnable(itemId).getCheckedData();
        // 如果物料启用了批次管理,则必须选择批次
        if (Boolean.TRUE.equals(item.getIsBatchManaged()) && batchId == null) {
            throw exception(MD_ITEM_BATCH_REQUIRED);
@@ -189,9 +242,11 @@
            // 1.C.1 新增一行不合格品
            MesWmReturnSalesLineDO unqualifiedLine = new MesWmReturnSalesLineDO()
                    .setReturnId(sourceLine.getReturnId())
                    .setProductSalesLineId(sourceLine.getProductSalesLineId())
                    .setItemId(sourceLine.getItemId())
                    .setQuantity(unqualifiedQuantity)
                    .setBatchId(sourceLine.getBatchId())
                    .setBatchCode(sourceLine.getBatchCode())
                    .setRqcId(sourceLine.getRqcId())
                    .setRqcCheckFlag(sourceLine.getRqcCheckFlag())
                    .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())