Commit fe9d7bb2d0ce78f9e15b7e37a7675afbf6c333ea

Authored by YunaiV
1 parent 892ce3e1

✨ feat(mes): 添加领料出库单行物料在工单 BOM 中校验功能

新增物料在工单 BOM 中的校验逻辑,确保领料单行的物料有效性,避免错误领料。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/detail/MesWmProductionIssueDetailSaveReqVO.java
@@ -35,9 +35,6 @@ public class MesWmProductionIssueDetailSaveReqVO { @@ -35,9 +35,6 @@ public class MesWmProductionIssueDetailSaveReqVO {
35 @Schema(description = "批次号", example = "BATCH20260101001") 35 @Schema(description = "批次号", example = "BATCH20260101001")
36 private String batchCode; 36 private String batchCode;
37 37
38 - @Schema(description = "库存记录编号", example = "1")  
39 - private Long materialStockId;  
40 -  
41 @Schema(description = "仓库编号", example = "1") 38 @Schema(description = "仓库编号", example = "1")
42 private Long warehouseId; 39 private Long warehouseId;
43 40
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/line/MesWmProductionIssueLineSaveReqVO.java
1 package cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line; 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotNull;
4 import lombok.Data; 6 import lombok.Data;
5 7
6 import java.math.BigDecimal; 8 import java.math.BigDecimal;
@@ -13,12 +15,16 @@ public class MesWmProductionIssueLineSaveReqVO { @@ -13,12 +15,16 @@ public class MesWmProductionIssueLineSaveReqVO {
13 private Long id; 15 private Long id;
14 16
15 @Schema(description = "领料单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 17 @Schema(description = "领料单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "领料单ID不能为空")
16 private Long issueId; 19 private Long issueId;
17 20
18 @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 21 @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + @NotNull(message = "物料ID不能为空")
19 private Long itemId; 23 private Long itemId;
20 24
21 @Schema(description = "领料数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") 25 @Schema(description = "领料数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  26 + @NotNull(message = "领料数量不能为空")
  27 + @DecimalMin(value = "0", inclusive = false, message = "领料数量必须大于 0")
22 private BigDecimal quantity; 28 private BigDecimal quantity;
23 29
24 @Schema(description = "批次ID", example = "1") 30 @Schema(description = "批次ID", example = "1")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialrequest/MesWmMaterialRequestDO.java
@@ -69,6 +69,8 @@ public class MesWmMaterialRequestDO extends BaseDO { @@ -69,6 +69,8 @@ public class MesWmMaterialRequestDO extends BaseDO {
69 * 备注 69 * 备注
70 */ 70 */
71 private String remark; 71 private String remark;
  72 +
  73 + // TODO @AI:删除 attribute1-4 字段
72 /** 74 /**
73 * 预留字段1 75 * 预留字段1
74 */ 76 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialrequest/MesWmMaterialRequestLineDO.java
@@ -54,6 +54,8 @@ public class MesWmMaterialRequestLineDO extends BaseDO { @@ -54,6 +54,8 @@ public class MesWmMaterialRequestLineDO extends BaseDO {
54 * 备注 54 * 备注
55 */ 55 */
56 private String remark; 56 private String remark;
  57 +
  58 + // TODO @AI:删除 attribute1-4 字段
57 /** 59 /**
58 * 预留字段1 60 * 预留字段1
59 */ 61 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -366,6 +366,7 @@ public interface ErrorCodeConstants { @@ -366,6 +366,7 @@ public interface ErrorCodeConstants {
366 ErrorCode WM_PRODUCTION_ISSUE_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_708_005, "工作站不存在"); 366 ErrorCode WM_PRODUCTION_ISSUE_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_708_005, "工作站不存在");
367 ErrorCode WM_PRODUCTION_ISSUE_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_708_006, "生产领料出库单已完成或已取消,无法取消"); 367 ErrorCode WM_PRODUCTION_ISSUE_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_708_006, "生产领料出库单已完成或已取消,无法取消");
368 ErrorCode WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_708_100, "生产领料出库单行不存在"); 368 ErrorCode WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_708_100, "生产领料出库单行不存在");
  369 + ErrorCode WM_PRODUCTION_ISSUE_LINE_ITEM_NOT_IN_BOM = new ErrorCode(1_040_708_101, "当前物料不在生产工单的 BOM 物料清单中");
369 ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在"); 370 ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在");
370 371
371 } 372 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialRequestStatusEnum.java
@@ -7,7 +7,6 @@ import lombok.Getter; @@ -7,7 +7,6 @@ import lombok.Getter;
7 7
8 import java.util.Arrays; 8 import java.util.Arrays;
9 9
10 -// TODO @AI:这里需要迁移下;  
11 /** 10 /**
12 * MES 领料申请单状态枚举 11 * MES 领料申请单状态枚举
13 * 12 *
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueLineServiceImpl.java
1 package cn.iocoder.yudao.module.mes.service.wm.productionissue; 1 package cn.iocoder.yudao.module.mes.service.wm.productionissue;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLinePageReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLinePageReqVO;
6 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLineSaveReqVO; 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLineSaveReqVO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO;
8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper;
9 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; 12 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  13 +import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService;
10 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
11 import org.springframework.context.annotation.Lazy; 15 import org.springframework.context.annotation.Lazy;
12 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
@@ -15,6 +19,7 @@ import org.springframework.validation.annotation.Validated; @@ -15,6 +19,7 @@ import org.springframework.validation.annotation.Validated;
15 import java.util.List; 19 import java.util.List;
16 20
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_ITEM_NOT_IN_BOM;
18 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS; 23 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS;
19 24
20 /** 25 /**
@@ -32,11 +37,13 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -32,11 +37,13 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
32 private MesWmProductionIssueService issueService; 37 private MesWmProductionIssueService issueService;
33 @Resource 38 @Resource
34 private MesMdItemService itemService; 39 private MesMdItemService itemService;
  40 + @Resource
  41 + private MesProWorkOrderBomService workOrderBomService;
35 42
36 @Override 43 @Override
37 public Long createProductionIssueLine(MesWmProductionIssueLineSaveReqVO createReqVO) { 44 public Long createProductionIssueLine(MesWmProductionIssueLineSaveReqVO createReqVO) {
38 - // 校验父数据存在  
39 - issueService.validateProductionIssueExists(createReqVO.getIssueId()); 45 + // 校验父数据存在 + 校验物料在工单 BOM 中
  46 + validateItemInWorkOrderBom(createReqVO.getIssueId(), createReqVO.getItemId());
40 // 校验物料存在 47 // 校验物料存在
41 itemService.validateItemExists(createReqVO.getItemId()); 48 itemService.validateItemExists(createReqVO.getItemId());
42 49
@@ -50,8 +57,8 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -50,8 +57,8 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
50 public void updateProductionIssueLine(MesWmProductionIssueLineSaveReqVO updateReqVO) { 57 public void updateProductionIssueLine(MesWmProductionIssueLineSaveReqVO updateReqVO) {
51 // 校验存在 58 // 校验存在
52 validateProductionIssueLineExists(updateReqVO.getId()); 59 validateProductionIssueLineExists(updateReqVO.getId());
53 - // 校验父数据存在  
54 - issueService.validateProductionIssueExists(updateReqVO.getIssueId()); 60 + // 校验父数据存在 + 校验物料在工单 BOM 中
  61 + validateItemInWorkOrderBom(updateReqVO.getIssueId(), updateReqVO.getItemId());
55 // 校验物料存在 62 // 校验物料存在
56 itemService.validateItemExists(updateReqVO.getItemId()); 63 itemService.validateItemExists(updateReqVO.getItemId());
57 64
@@ -97,4 +104,19 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -97,4 +104,19 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
97 return line; 104 return line;
98 } 105 }
99 106
  107 + private void validateItemInWorkOrderBom(Long issueId, Long itemId) {
  108 + // 校验领料单存在,并获取工单编号
  109 + MesWmProductionIssueDO issue = issueService.validateProductionIssueExists(issueId);
  110 + // 校验物料是否在工单 BOM 中(防错料)
  111 + List<MesProWorkOrderBomDO> workOrderBoms = workOrderBomService.getWorkOrderBomListByWorkOrderId(issue.getWorkOrderId());
  112 + if (CollUtil.isEmpty(workOrderBoms)) {
  113 + return;
  114 + }
  115 + MesProWorkOrderBomDO workOrderBom = CollUtil.findOne(workOrderBoms,
  116 + bom -> bom.getItemId().equals(itemId));
  117 + if (workOrderBom == null) {
  118 + throw exception(WM_PRODUCTION_ISSUE_LINE_ITEM_NOT_IN_BOM);
  119 + }
  120 + }
  121 +
100 } 122 }