gaoluyang
5 天以前 defe1e1c3ade87de0a7990f565f08f93aeb2decc
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
@@ -2,16 +2,23 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi;
import cn.iocoder.yudao.module.aftersales.api.AfterSaleTicketApi;
import cn.iocoder.yudao.module.aftersales.api.dto.AfterSaleWarehouseReturnStageReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.batch.MesWmBatchDO;
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.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnSalesStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import jakarta.annotation.Resource;
@@ -26,15 +33,20 @@
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.WM_RETURN_SALES_REEL_MISMATCH;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_SALES_BATCH_NOT_SHIPPED;
/**
 * MES 销售退货单行 Service 实现类
 *
 * @author 芋道源码
 * @author 超级管理员
 */
@Service
@Validated
public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineService {
    @Resource
    private AfterSaleTicketApi afterSaleTicketApi;
    @Resource
    private MesWmReturnSalesLineMapper returnSalesLineMapper;
@@ -46,6 +58,10 @@
    private MesMdmItemService mdmItemService;
    @Resource
    private MesWmBatchService batchService;
    @Resource
    private ErpSaleOrderApi saleOrderApi;
    @Resource
    private MesWmProductSalesDetailMapper productSalesDetailMapper;
    @Resource
    @Lazy
    private MesWmReturnSalesDetailService returnSalesDetailService;
@@ -82,9 +98,33 @@
     */
    private void validateLineSaveData(MesWmReturnSalesLineSaveReqVO reqVO) {
        // 校验退货单存在 + 草稿状态
        returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId());
        MesWmReturnSalesDO returnSales = returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId());
        // 校验物料存在 + 批次管理
        validateItemBatchManagement(reqVO.getReturnId(), reqVO.getItemId(), reqVO.getBatchId());
        MesWmBatchDO batch = validateItemBatchManagement(returnSales, reqVO.getItemId(), reqVO.getBatchId());
        if (batch != null) {
            reqVO.setBatchCode(batch.getCode());
        }
        if (returnSales.getSaleOrderId() != null) {
            var items = saleOrderApi.getSaleOrderItemList(returnSales.getSaleOrderId()).getCheckedData();
            var reelNumbers = items.stream().filter(item -> Objects.equals(reqVO.getItemId(), item.getProductId()))
                    .map(item -> item.getReelNo()).filter(StrUtil::isNotBlank).toList();
            if (!reelNumbers.isEmpty() && (batch == null || !reelNumbers.contains(batch.getReelNo())
                    || (StrUtil.isNotBlank(batch.getSalesOrderCode())
                    && !Objects.equals(returnSales.getSalesOrderCode(), batch.getSalesOrderCode())))) {
                throw exception(WM_RETURN_SALES_REEL_MISMATCH);
            }
            if (!reelNumbers.isEmpty() && productSalesDetailMapper.countFinishedSaleBatch(
                    returnSales.getSaleOrderId(), reqVO.getItemId(), batch.getId(),
                    MesWmProductSalesStatusEnum.FINISHED.getStatus()) == 0) {
                throw exception(WM_RETURN_SALES_BATCH_NOT_SHIPPED);
            }
            // 手工入库批次可能没有客户;仅在订单盘号及已完成出库都已验证后允许退货。
            if (batch != null && (batch.getClientId() != null || reelNumbers.isEmpty())) {
                batchService.validateBatchExists(batch.getId(), reqVO.getItemId(), returnSales.getClientId(), null);
            }
        } else if (batch != null) {
            batchService.validateBatchExists(batch.getId(), reqVO.getItemId(), returnSales.getClientId(), null);
        }
    }
    @Override
@@ -150,11 +190,11 @@
    /**
     * 校验物料批次管理
     *
     * @param returnId 退货单ID
     * @param returnSales 退货单
     * @param itemId   物料ID
     * @param batchId  批次ID
     */
    private void validateItemBatchManagement(Long returnId, Long itemId, Long batchId) {
    private MesWmBatchDO validateItemBatchManagement(MesWmReturnSalesDO returnSales, Long itemId, Long batchId) {
        MesMdmItemDO item = mdmItemService.validateItemExistsAndEnable(itemId);
        // 如果物料启用了批次管理,则必须选择批次
        if (Boolean.TRUE.equals(item.getIsBatchManaged()) && batchId == null) {
@@ -162,10 +202,9 @@
        }
        // 校验批次存在且属于当前物料和客户
        if (batchId != null) {
            // 从父单获取客户ID,校验批次归属
            MesWmReturnSalesDO returnSales = returnSalesService.validateReturnSalesExistsAndPrepare(returnId);
            batchService.validateBatchExists(batchId, itemId, returnSales.getClientId(), null);
            return batchService.validateBatchExists(batchId, itemId);
        }
        return null;
    }
    @Override
@@ -192,6 +231,7 @@
                    .setItemId(sourceLine.getItemId())
                    .setQuantity(unqualifiedQuantity)
                    .setBatchId(sourceLine.getBatchId())
                    .setBatchCode(sourceLine.getBatchCode())
                    .setRqcId(sourceLine.getRqcId())
                    .setRqcCheckFlag(sourceLine.getRqcCheckFlag())
                    .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())
@@ -211,6 +251,14 @@
                    line -> Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus()));
            if (allInspected) {
                returnSalesService.updateReturnSalesStatus(sourceDocId, MesWmReturnSalesStatusEnum.APPROVING.getStatus());
                MesWmReturnSalesDO returnSales = returnSalesService.getReturnSales(sourceDocId);
                if (returnSales != null && returnSales.getSaleOrderId() != null) {
                    afterSaleTicketApi.onWarehouseReturnQualityFinished(new AfterSaleWarehouseReturnStageReqDTO()
                            .setSaleOrderId(returnSales.getSaleOrderId())
                            .setReturnSalesId(returnSales.getId())
                            .setReturnSalesCode(returnSales.getCode())
                            .setQualityResult("全部待检行已完成检验"));
                }
            }
        }
    }