Преглед изворни кода

✨ feat(mes): 新增根据行ID删除明细功能,优化数据校验逻辑

YunaiV пре 3 месеци
родитељ
комит
e081a59949

+ 7 - 0
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productissue/MesWmProductIssueDetailService.java

@@ -64,4 +64,11 @@ public interface MesWmProductIssueDetailService {
      */
     void deleteProductIssueDetailByIssueId(Long issueId);
 
+    /**
+     * 根据行ID删除明细
+     *
+     * @param lineId 行ID
+     */
+    void deleteProductIssueDetailByLineId(Long lineId);
+
 }

+ 51 - 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productissue/MesWmProductIssueDetailServiceImpl.java

@@ -1,9 +1,14 @@
 package cn.iocoder.yudao.module.mes.service.wm.productissue;
 
+import cn.hutool.core.util.ObjUtil;
 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.productissue.vo.detail.MesWmProductIssueDetailSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueDetailDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueLineDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productissue.MesWmProductIssueDetailMapper;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductIssueStatusEnum;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -12,7 +17,7 @@ import org.springframework.validation.annotation.Validated;
 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_PRODUCT_ISSUE_DETAIL_NOT_EXISTS;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
 /**
  * MES 领料出库明细 Service 实现类
@@ -24,14 +29,17 @@ public class MesWmProductIssueDetailServiceImpl implements MesWmProductIssueDeta
     @Resource
     private MesWmProductIssueDetailMapper issueDetailMapper;
 
+    @Resource
+    @Lazy
+    private MesWmProductIssueService issueService;
     @Resource
     @Lazy
     private MesWmProductIssueLineService issueLineService;
 
     @Override
     public Long createProductIssueDetail(MesWmProductIssueDetailSaveReqVO createReqVO) {
-        // 校验数据存在
-        issueLineService.validateProductIssueLineExists(createReqVO.getLineId());
+        // 校验数据
+        validateProductIssueDetailSaveData(createReqVO);
 
         // 插入
         MesWmProductIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductIssueDetailDO.class);
@@ -43,8 +51,8 @@ public class MesWmProductIssueDetailServiceImpl implements MesWmProductIssueDeta
     public void updateProductIssueDetail(MesWmProductIssueDetailSaveReqVO updateReqVO) {
         // 校验存在
         validateProductIssueDetailExists(updateReqVO.getId());
-        // 校验数据存在
-        issueLineService.validateProductIssueLineExists(updateReqVO.getLineId());
+        // 校验数据
+        validateProductIssueDetailSaveData(updateReqVO);
 
         // 更新
         MesWmProductIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductIssueDetailDO.class);
@@ -54,7 +62,19 @@ public class MesWmProductIssueDetailServiceImpl implements MesWmProductIssueDeta
     @Override
     public void deleteProductIssueDetail(Long id) {
         // 校验存在
-        validateProductIssueDetailExists(id);
+        MesWmProductIssueDetailDO detail = issueDetailMapper.selectById(id);
+        if (detail == null) {
+            throw exception(WM_PRODUCT_ISSUE_DETAIL_NOT_EXISTS);
+        }
+        // 校验主单状态为草稿或待拣货(允许在拣货模式删除明细)
+        MesWmProductIssueLineDO line = issueLineService.validateProductIssueLineExists(detail.getLineId());
+        MesWmProductIssueDO issue = issueService.validateProductIssueExists(line.getIssueId());
+        if (!ObjectUtils.equalsAny(issue.getStatus(),
+                MesWmProductIssueStatusEnum.PREPARE.getStatus(),
+                MesWmProductIssueStatusEnum.APPROVING.getStatus())) {
+            throw exception(WM_PRODUCT_ISSUE_STATUS_INVALID);
+        }
+
         // 删除
         issueDetailMapper.deleteById(id);
     }
@@ -79,10 +99,35 @@ public class MesWmProductIssueDetailServiceImpl implements MesWmProductIssueDeta
         issueDetailMapper.deleteByIssueId(issueId);
     }
 
+    @Override
+    public void deleteProductIssueDetailByLineId(Long lineId) {
+        issueDetailMapper.deleteByLineId(lineId);
+    }
+
     private void validateProductIssueDetailExists(Long id) {
         if (issueDetailMapper.selectById(id) == null) {
             throw exception(WM_PRODUCT_ISSUE_DETAIL_NOT_EXISTS);
         }
     }
 
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateProductIssueDetailSaveData(MesWmProductIssueDetailSaveReqVO reqVO) {
+        // 校验父数据存在
+        MesWmProductIssueLineDO line = issueLineService.validateProductIssueLineExists(reqVO.getLineId());
+        // 校验物料匹配(明细 itemId 必须与行 itemId 一致)
+        validateDetailItemMatch(reqVO.getItemId(), line.getItemId());
+    }
+
+    /**
+     * 校验明细物料与行物料一致
+     */
+    private void validateDetailItemMatch(Long detailItemId, Long lineItemId) {
+        if (ObjUtil.notEqual(detailItemId, lineItemId)) {
+            throw exception(WM_PRODUCT_ISSUE_DETAIL_ITEM_MISMATCH);
+        }
+    }
+
 }
+

+ 21 - 10
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productissue/MesWmProductIssueLineServiceImpl.java

@@ -39,13 +39,13 @@ public class MesWmProductIssueLineServiceImpl implements MesWmProductIssueLineSe
     private MesMdItemService itemService;
     @Resource
     private MesProWorkOrderBomService workOrderBomService;
+    @Resource
+    @Lazy
+    private MesWmProductIssueDetailService issueDetailService;
 
     @Override
     public Long createProductIssueLine(MesWmProductIssueLineSaveReqVO createReqVO) {
-        // 校验父数据存在 + 校验物料在工单 BOM 中
-        validateItemInWorkOrderBom(createReqVO.getIssueId(), createReqVO.getItemId());
-        // 校验物料存在
-        itemService.validateItemExists(createReqVO.getItemId());
+        validateProductIssueLineSaveData(createReqVO);
 
         // 插入
         MesWmProductIssueLineDO line = BeanUtils.toBean(createReqVO, MesWmProductIssueLineDO.class);
@@ -57,10 +57,7 @@ public class MesWmProductIssueLineServiceImpl implements MesWmProductIssueLineSe
     public void updateProductIssueLine(MesWmProductIssueLineSaveReqVO updateReqVO) {
         // 校验存在
         validateProductIssueLineExists(updateReqVO.getId());
-        // 校验父数据存在 + 校验物料在工单 BOM 中
-        validateItemInWorkOrderBom(updateReqVO.getIssueId(), updateReqVO.getItemId());
-        // 校验物料存在
-        itemService.validateItemExists(updateReqVO.getItemId());
+        validateProductIssueLineSaveData(updateReqVO);
 
         // 更新
         MesWmProductIssueLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductIssueLineDO.class);
@@ -70,8 +67,12 @@ public class MesWmProductIssueLineServiceImpl implements MesWmProductIssueLineSe
     @Override
     public void deleteProductIssueLine(Long id) {
         // 校验存在
-        validateProductIssueLineExists(id);
-        // 删除
+        MesWmProductIssueLineDO line = validateProductIssueLineExists(id);
+        // 校验主单为草稿状态才允许删除行
+        issueService.validateProductIssueExistsAndPrepare(line.getIssueId());
+        // 级联删除该行的明细
+        issueDetailService.deleteProductIssueDetailByLineId(id);
+        // 删除行
         issueLineMapper.deleteById(id);
     }
 
@@ -104,6 +105,16 @@ public class MesWmProductIssueLineServiceImpl implements MesWmProductIssueLineSe
         return line;
     }
 
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateProductIssueLineSaveData(MesWmProductIssueLineSaveReqVO reqVO) {
+        // 校验父数据存在 + 校验物料在工单 BOM 中
+        validateItemInWorkOrderBom(reqVO.getIssueId(), reqVO.getItemId());
+        // 校验物料存在
+        itemService.validateItemExists(reqVO.getItemId());
+    }
+
     private void validateItemInWorkOrderBom(Long issueId, Long itemId) {
         // 校验领料单存在,并获取工单编号
         MesWmProductIssueDO issue = issueService.validateProductIssueExists(issueId);

+ 32 - 11
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productissue/MesWmProductIssueServiceImpl.java

@@ -31,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -67,10 +68,7 @@ public class MesWmProductIssueServiceImpl implements MesWmProductIssueService {
     @Transactional(rollbackFor = Exception.class)
     public Long createProductIssue(MesWmProductIssueSaveReqVO createReqVO) {
         // 1. 校验关联数据
-        workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
-        if (createReqVO.getWorkstationId() != null) {
-            workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
-        }
+        validateProductIssueSaveData(createReqVO);
 
         // 2. 插入主表
         MesWmProductIssueDO issue = BeanUtils.toBean(createReqVO, MesWmProductIssueDO.class);
@@ -85,10 +83,7 @@ public class MesWmProductIssueServiceImpl implements MesWmProductIssueService {
         // 1.1 校验存在 + 准备中状态
         validateProductIssueExistsAndPrepare(updateReqVO.getId());
         // 1.2 校验关联数据
-        workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
-        if (updateReqVO.getWorkstationId() != null) {
-            workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
-        }
+        validateProductIssueSaveData(updateReqVO);
 
         // 2. 更新主表
         MesWmProductIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductIssueDO.class);
@@ -160,9 +155,10 @@ public class MesWmProductIssueServiceImpl implements MesWmProductIssueService {
         // 2. 遍历所有明细,创建库存事务(扣减库存 + 记录流水)
         createTransactionList(issue);
 
-        // 3. 更新出库单状态
+        // 3. 更新出库单状态 + 领料日期
         issueMapper.updateById(new MesWmProductIssueDO()
-                .setId(id).setStatus(MesWmProductIssueStatusEnum.FINISHED.getStatus()));
+                .setId(id).setStatus(MesWmProductIssueStatusEnum.FINISHED.getStatus())
+                .setIssueDate(LocalDateTime.now()));
     }
 
     private void createTransactionList(MesWmProductIssueDO issue) {
@@ -237,7 +233,8 @@ public class MesWmProductIssueServiceImpl implements MesWmProductIssueService {
     /**
      * 校验领料出库单存在且为准备中状态
      */
-    private MesWmProductIssueDO validateProductIssueExistsAndPrepare(Long id) {
+    @Override
+    public MesWmProductIssueDO validateProductIssueExistsAndPrepare(Long id) {
         MesWmProductIssueDO issue = validateProductIssueExists(id);
         if (ObjUtil.notEqual(MesWmProductIssueStatusEnum.PREPARE.getStatus(), issue.getStatus())) {
             throw exception(WM_PRODUCT_ISSUE_STATUS_INVALID);
@@ -245,4 +242,28 @@ public class MesWmProductIssueServiceImpl implements MesWmProductIssueService {
         return issue;
     }
 
+    /**
+     * 校验编码唯一性
+     */
+    private void validateCodeUnique(Long id, String code) {
+        MesWmProductIssueDO issue = issueMapper.selectByCode(code);
+        if (issue == null) {
+            return;
+        }
+        if (ObjUtil.notEqual(id, issue.getId())) {
+            throw exception(WM_PRODUCT_ISSUE_CODE_DUPLICATE);
+        }
+    }
+
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateProductIssueSaveData(MesWmProductIssueSaveReqVO reqVO) {
+        validateCodeUnique(reqVO.getId(), reqVO.getCode());
+        workOrderService.validateWorkOrderExists(reqVO.getWorkOrderId());
+        if (reqVO.getWorkstationId() != null) {
+            workstationService.validateWorkstationExists(reqVO.getWorkstationId());
+        }
+    }
+
 }

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

@@ -73,10 +73,7 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
     @Transactional(rollbackFor = Exception.class)
     public Long createReturnIssue(MesWmReturnIssueSaveReqVO createReqVO) {
         // 1. 校验关联数据
-        workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
-        if (createReqVO.getWorkstationId() != null) {
-            workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
-        }
+        validateReturnIssueSaveData(createReqVO);
 
         // 2. 插入主表
         MesWmReturnIssueDO issue = BeanUtils.toBean(createReqVO, MesWmReturnIssueDO.class);
@@ -91,10 +88,7 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
         // 1.1 校验存在 + 准备中状态
         MesWmReturnIssueDO oldIssue = validateReturnIssueExistsAndPrepare(updateReqVO.getId());
         // 1.2 校验关联数据
-        workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
-        if (updateReqVO.getWorkstationId() != null) {
-            workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
-        }
+        validateReturnIssueSaveData(updateReqVO);
 
         // 2. 更新主表
         MesWmReturnIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnIssueDO.class);
@@ -274,4 +268,14 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
         issueMapper.updateById(new MesWmReturnIssueDO().setId(id).setStatus(status));
     }
 
+    /**
+     * 校验保存时的关联数据
+     */
+    private void validateReturnIssueSaveData(MesWmReturnIssueSaveReqVO reqVO) {
+        workOrderService.validateWorkOrderExists(reqVO.getWorkOrderId());
+        if (reqVO.getWorkstationId() != null) {
+            workstationService.validateWorkstationExists(reqVO.getWorkstationId());
+        }
+    }
+
 }