Browse Source

✨ feat(mes): 新增退货明细数量校验逻辑

新增校验逻辑以确保退货明细总数量不超过对应退货行的数量,提升数据一致性和准确性。
同时,重构相关方法以简化数据验证过程。
YunaiV 3 months ago
parent
commit
9221527d92

+ 1 - 0
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java

@@ -517,6 +517,7 @@ public interface ErrorCodeConstants {
     ErrorCode WM_RETURN_SALES_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_713_007, "销售退货单已完成或已取消,无法取消");
     ErrorCode WM_RETURN_SALES_LINE_NOT_EXISTS = new ErrorCode(1_040_713_100, "销售退货单行不存在");
     ErrorCode WM_RETURN_SALES_DETAIL_NOT_EXISTS = new ErrorCode(1_040_713_200, "销售退货单明细不存在");
+    ErrorCode WM_RETURN_SALES_DETAIL_QUANTITY_EXCEED = new ErrorCode(1_040_713_201, "上架明细总数量不能超过退货行数量");
 
     // ========== MES 仓库管理-盘点方案/任务/结果(1-040-714-100) ==========
     ErrorCode WM_STOCK_TAKING_PLAN_NOT_EXISTS = new ErrorCode(1_040_714_100, "盘点方案不存在");

+ 50 - 10
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesDetailServiceImpl.java

@@ -1,19 +1,24 @@
 package cn.iocoder.yudao.module.mes.service.wm.returnsales;
 
+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.detail.MesWmReturnSalesDetailSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDetailDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesDetailMapper;
-import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
 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.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_SALES_DETAIL_NOT_EXISTS;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_SALES_DETAIL_QUANTITY_EXCEED;
 
 /**
  * MES 销售退货明细 Service 实现类
@@ -32,14 +37,15 @@ public class MesWmReturnSalesDetailServiceImpl implements MesWmReturnSalesDetail
     private MesWmReturnSalesLineService returnSalesLineService;
 
     @Resource
-    private MesMdItemService itemService;
+    private MesWmWarehouseAreaService warehouseAreaService;
+
+    @Resource
+    @Lazy
+    private MesWmMaterialStockService materialStockService;
 
     @Override
     public Long createReturnSalesDetail(MesWmReturnSalesDetailSaveReqVO createReqVO) {
-        // 校验父数据存在
-        returnSalesLineService.validateReturnSalesLineExists(createReqVO.getLineId());
-        // 校验物料存在
-        itemService.validateItemExists(createReqVO.getItemId());
+        validateReturnSalesDetailSaveData(createReqVO);
 
         // 插入
         MesWmReturnSalesDetailDO detail = BeanUtils.toBean(createReqVO, MesWmReturnSalesDetailDO.class);
@@ -51,10 +57,7 @@ public class MesWmReturnSalesDetailServiceImpl implements MesWmReturnSalesDetail
     public void updateReturnSalesDetail(MesWmReturnSalesDetailSaveReqVO updateReqVO) {
         // 校验存在
         validateReturnSalesDetailExists(updateReqVO.getId());
-        // 校验父数据存在
-        returnSalesLineService.validateReturnSalesLineExists(updateReqVO.getLineId());
-        // 校验物料存在
-        itemService.validateItemExists(updateReqVO.getItemId());
+        validateReturnSalesDetailSaveData(updateReqVO);
 
         // 更新
         MesWmReturnSalesDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnSalesDetailDO.class);
@@ -95,4 +98,41 @@ public class MesWmReturnSalesDetailServiceImpl implements MesWmReturnSalesDetail
         }
     }
 
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateReturnSalesDetailSaveData(MesWmReturnSalesDetailSaveReqVO reqVO) {
+        // 校验父数据存在
+        MesWmReturnSalesLineDO line = returnSalesLineService.validateReturnSalesLineExists(reqVO.getLineId());
+        // 校验仓库、库区、库位的关联关系
+        warehouseAreaService.validateWarehouseAreaExists(
+                reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId());
+        // 校验库位物料/批次混放规则
+        materialStockService.checkAreaMixingRule(reqVO.getAreaId(), reqVO.getItemId(), reqVO.getBatchId());
+        // 校验明细总数量不超过行数量(排除自身)
+        validateDetailQuantityNotExceed(reqVO.getLineId(), reqVO.getQuantity(), reqVO.getId(), line);
+    }
+
+    /**
+     * 校验明细总数量不超过行数量
+     *
+     * @param lineId          行 ID
+     * @param newQuantity     本次新增/修改的数量
+     * @param excludeDetailId 排除的明细 ID(更新时排除自身,新增时传 null)
+     * @param line            退货单行
+     */
+    private void validateDetailQuantityNotExceed(Long lineId, BigDecimal newQuantity,
+                                                  Long excludeDetailId, MesWmReturnSalesLineDO line) {
+        // 计算已有明细总数量(排除自身)
+        List<MesWmReturnSalesDetailDO> details = returnSalesDetailMapper.selectListByLineId(lineId);
+        BigDecimal existingTotal = CollectionUtils.getSumValue(details,
+                detail -> excludeDetailId != null && excludeDetailId.equals(detail.getId())
+                        ? BigDecimal.ZERO : detail.getQuantity(),
+                BigDecimal::add, BigDecimal.ZERO);
+        // 校验:已有 + 本次 <= 行数量
+        if (existingTotal.add(newQuantity).compareTo(line.getQuantity()) > 0) {
+            throw exception(WM_RETURN_SALES_DETAIL_QUANTITY_EXCEED);
+        }
+    }
+
 }

+ 12 - 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java

@@ -45,10 +45,7 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
 
     @Override
     public Long createReturnSalesLine(MesWmReturnSalesLineSaveReqVO createReqVO) {
-        // 校验父数据存在
-        returnSalesService.validateReturnSalesExists(createReqVO.getReturnId());
-        // 校验物料存在
-        validateItemBatchManagement(createReqVO.getItemId(), createReqVO.getBatchId());
+        validateLineSaveData(createReqVO);
 
         // 插入
         MesWmReturnSalesLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnSalesLineDO.class);
@@ -62,10 +59,7 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
     public void updateReturnSalesLine(MesWmReturnSalesLineSaveReqVO updateReqVO) {
         // 校验存在
         validateReturnSalesLineExists(updateReqVO.getId());
-        // 校验父数据存在
-        returnSalesService.validateReturnSalesExists(updateReqVO.getReturnId());
-        // 校验物料存在
-        validateItemBatchManagement(updateReqVO.getItemId(), updateReqVO.getBatchId());
+        validateLineSaveData(updateReqVO);
 
         // 更新
         MesWmReturnSalesLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnSalesLineDO.class);
@@ -74,6 +68,16 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
         returnSalesLineMapper.updateById(updateObj);
     }
 
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateLineSaveData(MesWmReturnSalesLineSaveReqVO reqVO) {
+        // 校验退货单存在
+        returnSalesService.validateReturnSalesExists(reqVO.getReturnId());
+        // 校验物料存在 + 批次管理
+        validateItemBatchManagement(reqVO.getItemId(), reqVO.getBatchId());
+    }
+
     @Override
     public void deleteReturnSalesLine(Long id) {
         // 校验存在