Commit efde91601411e758e623ad950e865b3b14ddcf38

Authored by YunaiV
1 parent 8d2fc22d

✨ feat(mes): 添加生产领料出库单相关功能与接口

新增生产领料出库单的状态管理、行验证及明细查询功能,优化了相关数据模型和接口,提升了系统的可用性和用户体验。
Showing 18 changed files with 262 additions and 131 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java
@@ -109,13 +109,40 @@ public class MesWmProductionIssueController { @@ -109,13 +109,40 @@ public class MesWmProductionIssueController {
109 @PutMapping("/finish") 109 @PutMapping("/finish")
110 @Operation(summary = "完成领料出库单") 110 @Operation(summary = "完成领料出库单")
111 @Parameter(name = "id", description = "编号", required = true) 111 @Parameter(name = "id", description = "编号", required = true)
112 - @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update-status')") 112 + @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:execute')")
113 public CommonResult<Boolean> finishProductionIssue(@RequestParam("id") Long id) { 113 public CommonResult<Boolean> finishProductionIssue(@RequestParam("id") Long id) {
114 issueService.finishProductionIssue(id); 114 issueService.finishProductionIssue(id);
115 return success(true); 115 return success(true);
116 } 116 }
117 117
118 - // TODO @AI:check quantity 118 + @PutMapping("/submit")
  119 + @Operation(summary = "提交领料出库单")
  120 + @Parameter(name = "id", description = "编号", required = true)
  121 + @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update')")
  122 + public CommonResult<Boolean> submitProductionIssue(@RequestParam("id") Long id) {
  123 + issueService.submitProductionIssue(id);
  124 + return success(true);
  125 + }
  126 +
  127 + @PutMapping("/stock")
  128 + @Operation(summary = "执行拣货")
  129 + @Parameter(name = "id", description = "编号", required = true)
  130 + @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update')")
  131 + public CommonResult<Boolean> stockProductionIssue(@RequestParam("id") Long id) {
  132 + issueService.stockProductionIssue(id);
  133 + return success(true);
  134 + }
  135 +
  136 + @PutMapping("/cancel")
  137 + @Operation(summary = "取消领料出库单")
  138 + @Parameter(name = "id", description = "编号", required = true)
  139 + @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update')")
  140 + public CommonResult<Boolean> cancelProductionIssue(@RequestParam("id") Long id) {
  141 + issueService.cancelProductionIssue(id);
  142 + return success(true);
  143 + }
  144 +
  145 + // TODO @AI:【芋艿】check quantity;晚点搞;
119 146
120 // ==================== 拼接 VO ==================== 147 // ==================== 拼接 VO ====================
121 148
@@ -127,15 +154,15 @@ public class MesWmProductionIssueController { @@ -127,15 +154,15 @@ public class MesWmProductionIssueController {
127 Map<Long, MesMdWorkstationDO> workstationMap = workstationService.getWorkstationMap( 154 Map<Long, MesMdWorkstationDO> workstationMap = workstationService.getWorkstationMap(
128 convertSet(list, MesWmProductionIssueDO::getWorkstationId)); 155 convertSet(list, MesWmProductionIssueDO::getWorkstationId));
129 Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap( 156 Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap(
130 - convertSet(list, MesWmProductionIssueDO::getWorkorderId)); 157 + convertSet(list, MesWmProductionIssueDO::getWorkOrderId));
131 // 2. 构建结果 158 // 2. 构建结果
132 return BeanUtils.toBean(list, MesWmProductionIssueRespVO.class, vo -> { 159 return BeanUtils.toBean(list, MesWmProductionIssueRespVO.class, vo -> {
133 // 2.1 填充工作站名称 160 // 2.1 填充工作站名称
134 MapUtils.findAndThen(workstationMap, vo.getWorkstationId(), 161 MapUtils.findAndThen(workstationMap, vo.getWorkstationId(),
135 workstation -> vo.setWorkstationName(workstation.getName())); 162 workstation -> vo.setWorkstationName(workstation.getName()));
136 // 2.2 填充工单编号 163 // 2.2 填充工单编号
137 - MapUtils.findAndThen(workOrderMap, vo.getWorkorderId(),  
138 - workOrder -> vo.setWorkorderCode(workOrder.getCode())); 164 + MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(),
  165 + workOrder -> vo.setWorkOrderCode(workOrder.getCode()));
139 }); 166 });
140 } 167 }
141 168
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssuePageReqVO.java
@@ -25,7 +25,7 @@ public class MesWmProductionIssuePageReqVO extends PageParam { @@ -25,7 +25,7 @@ public class MesWmProductionIssuePageReqVO extends PageParam {
25 private Long workstationId; 25 private Long workstationId;
26 26
27 @Schema(description = "生产工单ID", example = "1") 27 @Schema(description = "生产工单ID", example = "1")
28 - private Long workorderId; 28 + private Long workOrderId;
29 29
30 @Schema(description = "生产任务ID", example = "1") 30 @Schema(description = "生产任务ID", example = "1")
31 private Long taskId; 31 private Long taskId;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueRespVO.java
@@ -25,10 +25,10 @@ public class MesWmProductionIssueRespVO { @@ -25,10 +25,10 @@ public class MesWmProductionIssueRespVO {
25 private String workstationName; 25 private String workstationName;
26 26
27 @Schema(description = "生产工单 ID", example = "1") 27 @Schema(description = "生产工单 ID", example = "1")
28 - private Long workorderId; 28 + private Long workOrderId;
29 29
30 @Schema(description = "生产工单编号", example = "WO20250226001") 30 @Schema(description = "生产工单编号", example = "WO20250226001")
31 - private String workorderCode; 31 + private String workOrderCode;
32 32
33 @Schema(description = "生产任务 ID", example = "1") 33 @Schema(description = "生产任务 ID", example = "1")
34 private Long taskId; 34 private Long taskId;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java
@@ -23,11 +23,12 @@ public class MesWmProductionIssueSaveReqVO { @@ -23,11 +23,12 @@ public class MesWmProductionIssueSaveReqVO {
23 private String name; 23 private String name;
24 24
25 @Schema(description = "工作站 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 25 @Schema(description = "工作站 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
26 - @NotNull(message = "工作站ID不能为空") 26 + @NotNull(message = "工作站 ID 不能为空")
27 private Long workstationId; 27 private Long workstationId;
28 28
29 - @Schema(description = "生产工单 ID", example = "1")  
30 - private Long workorderId; 29 + @Schema(description = "生产工单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "生产工单 ID 不能为空")
  31 + private Long workOrderId;
31 32
32 @Schema(description = "需求时间", requiredMode = Schema.RequiredMode.REQUIRED) 33 @Schema(description = "需求时间", requiredMode = Schema.RequiredMode.REQUIRED)
33 @NotNull(message = "需求时间不能为空") 34 @NotNull(message = "需求时间不能为空")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/line/MesWmProductionIssueLineSaveReqVO.java
@@ -12,6 +12,9 @@ public class MesWmProductionIssueLineSaveReqVO { @@ -12,6 +12,9 @@ public class MesWmProductionIssueLineSaveReqVO {
12 @Schema(description = "行ID", example = "1") 12 @Schema(description = "行ID", example = "1")
13 private Long id; 13 private Long id;
14 14
  15 + @Schema(description = "领料单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Long issueId;
  17 +
15 @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 18 @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 private Long itemId; 19 private Long itemId;
17 20
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productionissue/MesWmProductionIssueDO.java
1 package cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue; 1 package cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 -import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO;  
5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
6 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; 5 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; 6 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
@@ -13,12 +12,11 @@ import lombok.*; @@ -13,12 +12,11 @@ import lombok.*;
13 12
14 import java.time.LocalDateTime; 13 import java.time.LocalDateTime;
15 14
16 -// TODO @AI:【需要一起讨论】不要直接改;是不是叫 issueheader 包?主要后续别的表也有 issue,希望区分下;还是加个合理的前缀?就像 wm_outsource_issue 这种;  
17 /** 15 /**
18 * MES 领料出库单 DO 16 * MES 领料出库单 DO
19 */ 17 */
20 -@TableName("mes_wm_issue_header")  
21 -@KeySequence("mes_wm_issue_header_seq") 18 +@TableName("mes_wm_production_issue")
  19 +@KeySequence("mes_wm_production_issue_seq")
22 @Data 20 @Data
23 @EqualsAndHashCode(callSuper = true) 21 @EqualsAndHashCode(callSuper = true)
24 @ToString(callSuper = true) 22 @ToString(callSuper = true)
@@ -46,28 +44,20 @@ public class MesWmProductionIssueDO extends BaseDO { @@ -46,28 +44,20 @@ public class MesWmProductionIssueDO extends BaseDO {
46 * 关联 {@link MesMdWorkstationDO#getId()} 44 * 关联 {@link MesMdWorkstationDO#getId()}
47 */ 45 */
48 private Long workstationId; 46 private Long workstationId;
49 - // TODO @AI:workOrderId;  
50 /** 47 /**
51 * 生产工单 ID 48 * 生产工单 ID
52 * 49 *
53 * 关联 {@link MesProWorkOrderDO#getId()} 50 * 关联 {@link MesProWorkOrderDO#getId()}
54 */ 51 */
55 - private Long workorderId;  
56 - // TODO @芋艿:【疑问】这个字段的来源? 52 + private Long workOrderId;
  53 + // TODO @芋艿:【疑问,不要动】这个字段的来源?
57 /** 54 /**
58 * 生产任务 ID 55 * 生产任务 ID
59 * 56 *
60 * 关联 {@link MesProTaskDO#getId()} 57 * 关联 {@link MesProTaskDO#getId()}
61 */ 58 */
62 private Long taskId; 59 private Long taskId;
63 - // TODO @AI:应该不用记录?因为 workorderId 字段的;  
64 - /**  
65 - * 客户 ID  
66 - *  
67 - * 关联 {@link MesMdClientDO#getId()}  
68 - */  
69 - private Long clientId;  
70 - // TODO @芋艿:【疑问】这个字段的更新时间; 60 + // TODO @芋艿:【疑问,不要动】这个字段的更新时间;
71 /** 61 /**
72 * 领料日期 62 * 领料日期
73 */ 63 */
@@ -86,21 +76,5 @@ public class MesWmProductionIssueDO extends BaseDO { @@ -86,21 +76,5 @@ public class MesWmProductionIssueDO extends BaseDO {
86 * 备注 76 * 备注
87 */ 77 */
88 private String remark; 78 private String remark;
89 - /**  
90 - * 预留字段 1  
91 - */  
92 - private String attribute1;  
93 - /**  
94 - * 预留字段 2  
95 - */  
96 - private String attribute2;  
97 - /**  
98 - * 预留字段 3  
99 - */  
100 - private Integer attribute3;  
101 - /**  
102 - * 预留字段 4  
103 - */  
104 - private Integer attribute4;  
105 79
106 } 80 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productionissue/MesWmProductionIssueDetailDO.java
@@ -16,8 +16,8 @@ import java.math.BigDecimal; @@ -16,8 +16,8 @@ import java.math.BigDecimal;
16 /** 16 /**
17 * MES 领料出库明细 DO 17 * MES 领料出库明细 DO
18 */ 18 */
19 -@TableName("mes_wm_issue_detail")  
20 -@KeySequence("mes_wm_issue_detail_seq") 19 +@TableName("mes_wm_production_issue_detail")
  20 +@KeySequence("mes_wm_production_issue_detail_seq")
21 @Data 21 @Data
22 @EqualsAndHashCode(callSuper = true) 22 @EqualsAndHashCode(callSuper = true)
23 @ToString(callSuper = true) 23 @ToString(callSuper = true)
@@ -85,21 +85,5 @@ public class MesWmProductionIssueDetailDO extends BaseDO { @@ -85,21 +85,5 @@ public class MesWmProductionIssueDetailDO extends BaseDO {
85 * 备注 85 * 备注
86 */ 86 */
87 private String remark; 87 private String remark;
88 - /**  
89 - * 预留字段1  
90 - */  
91 - private String attribute1;  
92 - /**  
93 - * 预留字段2  
94 - */  
95 - private String attribute2;  
96 - /**  
97 - * 预留字段3  
98 - */  
99 - private Integer attribute3;  
100 - /**  
101 - * 预留字段4  
102 - */  
103 - private Integer attribute4;  
104 88
105 } 89 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productionissue/MesWmProductionIssueLineDO.java
@@ -12,8 +12,8 @@ import java.math.BigDecimal; @@ -12,8 +12,8 @@ import java.math.BigDecimal;
12 /** 12 /**
13 * MES 领料出库单行 DO 13 * MES 领料出库单行 DO
14 */ 14 */
15 -@TableName("mes_wm_issue_line")  
16 -@KeySequence("mes_wm_issue_line_seq") 15 +@TableName("mes_wm_production_issue_line")
  16 +@KeySequence("mes_wm_production_issue_line_seq")
17 @Data 17 @Data
18 @EqualsAndHashCode(callSuper = true) 18 @EqualsAndHashCode(callSuper = true)
19 @ToString(callSuper = true) 19 @ToString(callSuper = true)
@@ -51,21 +51,5 @@ public class MesWmProductionIssueLineDO extends BaseDO { @@ -51,21 +51,5 @@ public class MesWmProductionIssueLineDO extends BaseDO {
51 * 备注 51 * 备注
52 */ 52 */
53 private String remark; 53 private String remark;
54 - /**  
55 - * 预留字段 1  
56 - */  
57 - private String attribute1;  
58 - /**  
59 - * 预留字段 2  
60 - */  
61 - private String attribute2;  
62 - /**  
63 - * 预留字段 3  
64 - */  
65 - private Integer attribute3;  
66 - /**  
67 - * 预留字段 4  
68 - */  
69 - private Integer attribute4;  
70 54
71 } 55 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productionissue/MesWmProductionIssueDetailMapper.java
@@ -16,6 +16,10 @@ public interface MesWmProductionIssueDetailMapper extends BaseMapperX&lt;MesWmProdu @@ -16,6 +16,10 @@ public interface MesWmProductionIssueDetailMapper extends BaseMapperX&lt;MesWmProdu
16 return selectList(MesWmProductionIssueDetailDO::getLineId, lineId); 16 return selectList(MesWmProductionIssueDetailDO::getLineId, lineId);
17 } 17 }
18 18
  19 + default List<MesWmProductionIssueDetailDO> selectListByIssueId(Long issueId) {
  20 + return selectList(MesWmProductionIssueDetailDO::getIssueId, issueId);
  21 + }
  22 +
19 default void deleteByIssueId(Long issueId) { 23 default void deleteByIssueId(Long issueId) {
20 delete(MesWmProductionIssueDetailDO::getIssueId, issueId); 24 delete(MesWmProductionIssueDetailDO::getIssueId, issueId);
21 } 25 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productionissue/MesWmProductionIssueMapper.java
@@ -18,9 +18,7 @@ public interface MesWmProductionIssueMapper extends BaseMapperX&lt;MesWmProductionI @@ -18,9 +18,7 @@ public interface MesWmProductionIssueMapper extends BaseMapperX&lt;MesWmProductionI
18 .likeIfPresent(MesWmProductionIssueDO::getCode, reqVO.getCode()) 18 .likeIfPresent(MesWmProductionIssueDO::getCode, reqVO.getCode())
19 .likeIfPresent(MesWmProductionIssueDO::getName, reqVO.getName()) 19 .likeIfPresent(MesWmProductionIssueDO::getName, reqVO.getName())
20 .eqIfPresent(MesWmProductionIssueDO::getWorkstationId, reqVO.getWorkstationId()) 20 .eqIfPresent(MesWmProductionIssueDO::getWorkstationId, reqVO.getWorkstationId())
21 - .eqIfPresent(MesWmProductionIssueDO::getWorkorderId, reqVO.getWorkorderId())  
22 - .eqIfPresent(MesWmProductionIssueDO::getTaskId, reqVO.getTaskId())  
23 - .eqIfPresent(MesWmProductionIssueDO::getClientId, reqVO.getClientId()) 21 + .eqIfPresent(MesWmProductionIssueDO::getWorkOrderId, reqVO.getWorkOrderId())
24 .eqIfPresent(MesWmProductionIssueDO::getStatus, reqVO.getStatus()) 22 .eqIfPresent(MesWmProductionIssueDO::getStatus, reqVO.getStatus())
25 .betweenIfPresent(MesWmProductionIssueDO::getIssueDate, reqVO.getIssueDate()) 23 .betweenIfPresent(MesWmProductionIssueDO::getIssueDate, reqVO.getIssueDate())
26 .orderByDesc(MesWmProductionIssueDO::getId)); 24 .orderByDesc(MesWmProductionIssueDO::getId));
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -360,9 +360,11 @@ public interface ErrorCodeConstants { @@ -360,9 +360,11 @@ public interface ErrorCodeConstants {
360 // ========== MES 仓库管理-生产领料出库单(1-040-708-000) ========== 360 // ========== MES 仓库管理-生产领料出库单(1-040-708-000) ==========
361 ErrorCode WM_PRODUCTION_ISSUE_NOT_EXISTS = new ErrorCode(1_040_708_000, "生产领料出库单不存在"); 361 ErrorCode WM_PRODUCTION_ISSUE_NOT_EXISTS = new ErrorCode(1_040_708_000, "生产领料出库单不存在");
362 ErrorCode WM_PRODUCTION_ISSUE_STATUS_INVALID = new ErrorCode(1_040_708_001, "生产领料出库单状态不正确,无法执行该操作"); 362 ErrorCode WM_PRODUCTION_ISSUE_STATUS_INVALID = new ErrorCode(1_040_708_001, "生产领料出库单状态不正确,无法执行该操作");
363 - // DONE @AI:不需要的错误码,需要处理下 - 已删除不需要的错误码(WM_PRODUCTION_ISSUE_WAREHOUSE_NOT_EXISTS, WM_PRODUCTION_ISSUE_ITEM_NOT_EXISTS, WM_PRODUCTION_ISSUE_NO_LINE, WM_PRODUCTION_ISSUE_QUANTITY_MISMATCH),保留需要的错误码 363 + ErrorCode WM_PRODUCTION_ISSUE_NO_LINE = new ErrorCode(1_040_708_002, "生产领料出库单至少需要一条行数据");
  364 + ErrorCode WM_PRODUCTION_ISSUE_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_708_003, "领料出库单行数量与明细数量不一致");
364 ErrorCode WM_PRODUCTION_ISSUE_WORKORDER_NOT_EXISTS = new ErrorCode(1_040_708_004, "生产工单不存在"); 365 ErrorCode WM_PRODUCTION_ISSUE_WORKORDER_NOT_EXISTS = new ErrorCode(1_040_708_004, "生产工单不存在");
365 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, "生产领料出库单已完成或已取消,无法取消");
366 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, "生产领料出库单行不存在");
367 ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在"); 369 ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在");
368 370
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductionIssueStatusEnum.java
1 package cn.iocoder.yudao.module.mes.enums.wm; 1 package cn.iocoder.yudao.module.mes.enums.wm;
2 2
3 import cn.iocoder.yudao.framework.common.core.ArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO;
4 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; 5 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  6 +import cn.iocoder.yudao.module.mes.service.wm.productionissue.MesWmProductionIssueService;
5 import lombok.AllArgsConstructor; 7 import lombok.AllArgsConstructor;
6 import lombok.Getter; 8 import lombok.Getter;
7 9
@@ -9,18 +11,48 @@ import java.util.Arrays; @@ -9,18 +11,48 @@ import java.util.Arrays;
9 11
10 /** 12 /**
11 * MES 领料出库单状态枚举 13 * MES 领料出库单状态枚举
  14 + *
  15 + * @author 芋道源码
12 */ 16 */
13 @Getter 17 @Getter
14 @AllArgsConstructor 18 @AllArgsConstructor
15 public enum MesWmProductionIssueStatusEnum implements ArrayValuable<Integer> { 19 public enum MesWmProductionIssueStatusEnum implements ArrayValuable<Integer> {
16 20
  21 + /**
  22 + * 草稿
  23 + *
  24 + * 对应方法:{@link MesWmProductionIssueService#createProductionIssue(MesWmProductionIssueSaveReqVO)}
  25 + */
17 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), 26 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
18 - FINISHED(MesOrderStatusConstants.FINISHED, "已完成"); 27 + /**
  28 + * 待拣货
  29 + *
  30 + * 对应方法:{@link MesWmProductionIssueService#submitProductionIssue(Long)}
  31 + */
  32 + APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"),
  33 + /**
  34 + * 待执行领出
  35 + *
  36 + * 对应方法:{@link MesWmProductionIssueService#stockProductionIssue(Long)}
  37 + */
  38 + APPROVED(MesOrderStatusConstants.APPROVED, "待执行领出"),
  39 + /**
  40 + * 已完成
  41 + *
  42 + * 对应方法:{@link MesWmProductionIssueService#finishProductionIssue(Long)}
  43 + */
  44 + FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
  45 + /**
  46 + * 已取消
  47 + *
  48 + * 对应方法:{@link MesWmProductionIssueService#cancelProductionIssue(Long)}
  49 + */
  50 + CANCELED(MesOrderStatusConstants.CANCELLED, "已取消");
19 51
20 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductionIssueStatusEnum::getStatus).toArray(Integer[]::new); 52 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductionIssueStatusEnum::getStatus).toArray(Integer[]::new);
21 53
22 /** 54 /**
23 - * 状态 55 + * 状态值
24 */ 56 */
25 private final Integer status; 57 private final Integer status;
26 /** 58 /**
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueDetailService.java
@@ -50,6 +50,14 @@ public interface MesWmProductionIssueDetailService { @@ -50,6 +50,14 @@ public interface MesWmProductionIssueDetailService {
50 List<MesWmProductionIssueDetailDO> getProductionIssueDetailListByLineId(Long lineId); 50 List<MesWmProductionIssueDetailDO> getProductionIssueDetailListByLineId(Long lineId);
51 51
52 /** 52 /**
  53 + * 根据领料单ID获取明细列表
  54 + *
  55 + * @param issueId 领料单ID
  56 + * @return 明细列表
  57 + */
  58 + List<MesWmProductionIssueDetailDO> getProductionIssueDetailListByIssueId(Long issueId);
  59 +
  60 + /**
53 * 根据领料单ID删除明细 61 * 根据领料单ID删除明细
54 * 62 *
55 * @param issueId 领料单ID 63 * @param issueId 领料单ID
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueDetailServiceImpl.java
@@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.detail.MesWmProductionIssueDetailSaveReqVO; 4 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.detail.MesWmProductionIssueDetailSaveReqVO;
5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDetailDO; 5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDetailDO;
6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueDetailMapper; 6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueDetailMapper;
7 -import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper;  
8 import jakarta.annotation.Resource; 7 import jakarta.annotation.Resource;
  8 +import org.springframework.context.annotation.Lazy;
9 import org.springframework.stereotype.Service; 9 import org.springframework.stereotype.Service;
10 import org.springframework.validation.annotation.Validated; 10 import org.springframework.validation.annotation.Validated;
11 11
@@ -13,7 +13,6 @@ import java.util.List; @@ -13,7 +13,6 @@ import java.util.List;
13 13
14 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 14 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS; 15 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS;
16 -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS;  
17 16
18 /** 17 /**
19 * MES 领料出库明细 Service 实现类 18 * MES 领料出库明细 Service 实现类
@@ -24,13 +23,15 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss @@ -24,13 +23,15 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss
24 23
25 @Resource 24 @Resource
26 private MesWmProductionIssueDetailMapper issueDetailMapper; 25 private MesWmProductionIssueDetailMapper issueDetailMapper;
  26 +
27 @Resource 27 @Resource
28 - private MesWmProductionIssueLineMapper issueLineMapper; 28 + @Lazy
  29 + private MesWmProductionIssueLineService issueLineService;
29 30
30 @Override 31 @Override
31 public Long createProductionIssueDetail(MesWmProductionIssueDetailSaveReqVO createReqVO) { 32 public Long createProductionIssueDetail(MesWmProductionIssueDetailSaveReqVO createReqVO) {
32 // 校验父数据存在 33 // 校验父数据存在
33 - validateParentIssueLineExists(createReqVO.getLineId()); 34 + issueLineService.validateProductionIssueLineExists(createReqVO.getLineId());
34 35
35 // 插入 36 // 插入
36 MesWmProductionIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductionIssueDetailDO.class); 37 MesWmProductionIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductionIssueDetailDO.class);
@@ -41,9 +42,9 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss @@ -41,9 +42,9 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss
41 @Override 42 @Override
42 public void updateProductionIssueDetail(MesWmProductionIssueDetailSaveReqVO updateReqVO) { 43 public void updateProductionIssueDetail(MesWmProductionIssueDetailSaveReqVO updateReqVO) {
43 // 校验存在 44 // 校验存在
44 - validateIssueDetailExists(updateReqVO.getId()); 45 + validateProductionIssueDetailExists(updateReqVO.getId());
45 // 校验父数据存在 46 // 校验父数据存在
46 - validateParentIssueLineExists(updateReqVO.getLineId()); 47 + issueLineService.validateProductionIssueLineExists(updateReqVO.getLineId());
47 48
48 // 更新 49 // 更新
49 MesWmProductionIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueDetailDO.class); 50 MesWmProductionIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueDetailDO.class);
@@ -53,7 +54,7 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss @@ -53,7 +54,7 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss
53 @Override 54 @Override
54 public void deleteProductionIssueDetail(Long id) { 55 public void deleteProductionIssueDetail(Long id) {
55 // 校验存在 56 // 校验存在
56 - validateIssueDetailExists(id); 57 + validateProductionIssueDetailExists(id);
57 // 删除 58 // 删除
58 issueDetailMapper.deleteById(id); 59 issueDetailMapper.deleteById(id);
59 } 60 }
@@ -69,20 +70,19 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss @@ -69,20 +70,19 @@ public class MesWmProductionIssueDetailServiceImpl implements MesWmProductionIss
69 } 70 }
70 71
71 @Override 72 @Override
  73 + public List<MesWmProductionIssueDetailDO> getProductionIssueDetailListByIssueId(Long issueId) {
  74 + return issueDetailMapper.selectListByIssueId(issueId);
  75 + }
  76 +
  77 + @Override
72 public void deleteProductionIssueDetailByIssueId(Long issueId) { 78 public void deleteProductionIssueDetailByIssueId(Long issueId) {
73 issueDetailMapper.deleteByIssueId(issueId); 79 issueDetailMapper.deleteByIssueId(issueId);
74 } 80 }
75 81
76 - private void validateIssueDetailExists(Long id) { 82 + private void validateProductionIssueDetailExists(Long id) {
77 if (issueDetailMapper.selectById(id) == null) { 83 if (issueDetailMapper.selectById(id) == null) {
78 throw exception(WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS); 84 throw exception(WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS);
79 } 85 }
80 } 86 }
81 87
82 - private void validateParentIssueLineExists(Long lineId) {  
83 - if (issueLineMapper.selectById(lineId) == null) {  
84 - throw exception(WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS);  
85 - }  
86 - }  
87 -  
88 } 88 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueLineService.java
@@ -66,4 +66,12 @@ public interface MesWmProductionIssueLineService { @@ -66,4 +66,12 @@ public interface MesWmProductionIssueLineService {
66 */ 66 */
67 void deleteProductionIssueLineByIssueId(Long issueId); 67 void deleteProductionIssueLineByIssueId(Long issueId);
68 68
  69 + /**
  70 + * 校验领料出库单行是否存在
  71 + *
  72 + * @param id 编号
  73 + * @return 领料出库单行
  74 + */
  75 + MesWmProductionIssueLineDO validateProductionIssueLineExists(Long id);
  76 +
69 } 77 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueLineServiceImpl.java
@@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.M @@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.M
6 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLineSaveReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.line.MesWmProductionIssueLineSaveReqVO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO; 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO;
8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper; 8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper;
9 -import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper; 9 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
10 import jakarta.annotation.Resource; 10 import jakarta.annotation.Resource;
  11 +import org.springframework.context.annotation.Lazy;
11 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
12 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
13 14
@@ -15,7 +16,6 @@ import java.util.List; @@ -15,7 +16,6 @@ import java.util.List;
15 16
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS; 18 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS;
18 -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_NOT_EXISTS;  
19 19
20 /** 20 /**
21 * MES 领料出库单行 Service 实现类 21 * MES 领料出库单行 Service 实现类
@@ -26,13 +26,19 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -26,13 +26,19 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
26 26
27 @Resource 27 @Resource
28 private MesWmProductionIssueLineMapper issueLineMapper; 28 private MesWmProductionIssueLineMapper issueLineMapper;
  29 +
  30 + @Resource
  31 + @Lazy
  32 + private MesWmProductionIssueService issueService;
29 @Resource 33 @Resource
30 - private MesWmProductionIssueMapper issueMapper; 34 + private MesMdItemService itemService;
31 35
32 @Override 36 @Override
33 public Long createProductionIssueLine(MesWmProductionIssueLineSaveReqVO createReqVO) { 37 public Long createProductionIssueLine(MesWmProductionIssueLineSaveReqVO createReqVO) {
34 // 校验父数据存在 38 // 校验父数据存在
35 - validateParentIssueExists(createReqVO.getIssueId()); 39 + issueService.validateProductionIssueExists(createReqVO.getIssueId());
  40 + // 校验物料存在
  41 + itemService.validateItemExists(createReqVO.getItemId());
36 42
37 // 插入 43 // 插入
38 MesWmProductionIssueLineDO line = BeanUtils.toBean(createReqVO, MesWmProductionIssueLineDO.class); 44 MesWmProductionIssueLineDO line = BeanUtils.toBean(createReqVO, MesWmProductionIssueLineDO.class);
@@ -43,9 +49,11 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -43,9 +49,11 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
43 @Override 49 @Override
44 public void updateProductionIssueLine(MesWmProductionIssueLineSaveReqVO updateReqVO) { 50 public void updateProductionIssueLine(MesWmProductionIssueLineSaveReqVO updateReqVO) {
45 // 校验存在 51 // 校验存在
46 - validateIssueLineExists(updateReqVO.getId()); 52 + validateProductionIssueLineExists(updateReqVO.getId());
47 // 校验父数据存在 53 // 校验父数据存在
48 - validateParentIssueExists(updateReqVO.getIssueId()); 54 + issueService.validateProductionIssueExists(updateReqVO.getIssueId());
  55 + // 校验物料存在
  56 + itemService.validateItemExists(updateReqVO.getItemId());
49 57
50 // 更新 58 // 更新
51 MesWmProductionIssueLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueLineDO.class); 59 MesWmProductionIssueLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueLineDO.class);
@@ -55,7 +63,7 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -55,7 +63,7 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
55 @Override 63 @Override
56 public void deleteProductionIssueLine(Long id) { 64 public void deleteProductionIssueLine(Long id) {
57 // 校验存在 65 // 校验存在
58 - validateIssueLineExists(id); 66 + validateProductionIssueLineExists(id);
59 // 删除 67 // 删除
60 issueLineMapper.deleteById(id); 68 issueLineMapper.deleteById(id);
61 } 69 }
@@ -80,16 +88,13 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue @@ -80,16 +88,13 @@ public class MesWmProductionIssueLineServiceImpl implements MesWmProductionIssue
80 issueLineMapper.deleteByIssueId(issueId); 88 issueLineMapper.deleteByIssueId(issueId);
81 } 89 }
82 90
83 - private void validateIssueLineExists(Long id) {  
84 - if (issueLineMapper.selectById(id) == null) { 91 + @Override
  92 + public MesWmProductionIssueLineDO validateProductionIssueLineExists(Long id) {
  93 + MesWmProductionIssueLineDO line = issueLineMapper.selectById(id);
  94 + if (line == null) {
85 throw exception(WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS); 95 throw exception(WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS);
86 } 96 }
87 - }  
88 -  
89 - private void validateParentIssueExists(Long issueId) {  
90 - if (issueMapper.selectById(issueId) == null) {  
91 - throw exception(WM_PRODUCTION_ISSUE_NOT_EXISTS);  
92 - } 97 + return line;
93 } 98 }
94 99
95 } 100 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java
@@ -50,10 +50,39 @@ public interface MesWmProductionIssueService { @@ -50,10 +50,39 @@ public interface MesWmProductionIssueService {
50 PageResult<MesWmProductionIssueDO> getProductionIssuePage(MesWmProductionIssuePageReqVO pageReqVO); 50 PageResult<MesWmProductionIssueDO> getProductionIssuePage(MesWmProductionIssuePageReqVO pageReqVO);
51 51
52 /** 52 /**
53 - * 完成领料出库单(草稿 → 已完成,执行出库) 53 + * 校验领料出库单是否存在
  54 + *
  55 + * @param id 编号
  56 + * @return 领料出库单
  57 + */
  58 + MesWmProductionIssueDO validateProductionIssueExists(Long id);
  59 +
  60 + /**
  61 + * 提交领料出库单(草稿 → 待拣货)
  62 + *
  63 + * @param id 编号
  64 + */
  65 + void submitProductionIssue(Long id);
  66 +
  67 + /**
  68 + * 执行拣货(待拣货 → 待执行领出)
  69 + *
  70 + * @param id 编号
  71 + */
  72 + void stockProductionIssue(Long id);
  73 +
  74 + /**
  75 + * 执行领出/出库(待执行领出 → 已完成),更新库存台账
54 * 76 *
55 * @param id 编号 77 * @param id 编号
56 */ 78 */
57 void finishProductionIssue(Long id); 79 void finishProductionIssue(Long id);
58 80
  81 + /**
  82 + * 取消领料出库单(任意非已完成/已取消状态 → 已取消)
  83 + *
  84 + * @param id 编号
  85 + */
  86 + void cancelProductionIssue(Long id);
  87 +
59 } 88 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.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.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
6 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssuePageReqVO; 9 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssuePageReqVO;
7 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO; 10 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDetailDO;
8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO; 12 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO;
9 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper; 14 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper;
10 import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductionIssueStatusEnum; 15 import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductionIssueStatusEnum;
11 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; 16 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
@@ -15,6 +20,9 @@ import org.springframework.stereotype.Service; @@ -15,6 +20,9 @@ import org.springframework.stereotype.Service;
15 import org.springframework.transaction.annotation.Transactional; 20 import org.springframework.transaction.annotation.Transactional;
16 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
17 22
  23 +import java.math.BigDecimal;
  24 +import java.util.List;
  25 +
18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 27 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
20 28
@@ -41,9 +49,9 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -41,9 +49,9 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
41 @Transactional(rollbackFor = Exception.class) 49 @Transactional(rollbackFor = Exception.class)
42 public Long createProductionIssue(MesWmProductionIssueSaveReqVO createReqVO) { 50 public Long createProductionIssue(MesWmProductionIssueSaveReqVO createReqVO) {
43 // 1. 校验关联数据 51 // 1. 校验关联数据
44 - workstationService.validateWorkstationExists(createReqVO.getWorkstationId());  
45 - if (createReqVO.getWorkorderId() != null) {  
46 - workOrderService.validateWorkOrderExists(createReqVO.getWorkorderId()); 52 + workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
  53 + if (createReqVO.getWorkstationId() != null) {
  54 + workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
47 } 55 }
48 56
49 // 2. 插入主表 57 // 2. 插入主表
@@ -57,11 +65,11 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -57,11 +65,11 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
57 @Transactional(rollbackFor = Exception.class) 65 @Transactional(rollbackFor = Exception.class)
58 public void updateProductionIssue(MesWmProductionIssueSaveReqVO updateReqVO) { 66 public void updateProductionIssue(MesWmProductionIssueSaveReqVO updateReqVO) {
59 // 1.1 校验存在 + 准备中状态 67 // 1.1 校验存在 + 准备中状态
60 - validateIssueExistsAndPrepare(updateReqVO.getId()); 68 + validateProductionIssueExistsAndPrepare(updateReqVO.getId());
61 // 1.2 校验关联数据 69 // 1.2 校验关联数据
62 - workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());  
63 - if (updateReqVO.getWorkorderId() != null) {  
64 - workOrderService.validateWorkOrderExists(updateReqVO.getWorkorderId()); 70 + workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
  71 + if (updateReqVO.getWorkstationId() != null) {
  72 + workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
65 } 73 }
66 74
67 // 2. 更新主表 75 // 2. 更新主表
@@ -73,7 +81,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -73,7 +81,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
73 @Transactional(rollbackFor = Exception.class) 81 @Transactional(rollbackFor = Exception.class)
74 public void deleteProductionIssue(Long id) { 82 public void deleteProductionIssue(Long id) {
75 // 1. 校验存在 + 准备中状态 83 // 1. 校验存在 + 准备中状态
76 - validateIssueExistsAndPrepare(id); 84 + validateProductionIssueExistsAndPrepare(id);
77 85
78 // 2.1 级联删除明细 86 // 2.1 级联删除明细
79 issueDetailService.deleteProductionIssueDetailByIssueId(id); 87 issueDetailService.deleteProductionIssueDetailByIssueId(id);
@@ -95,21 +103,85 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -95,21 +103,85 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
95 103
96 @Override 104 @Override
97 @Transactional(rollbackFor = Exception.class) 105 @Transactional(rollbackFor = Exception.class)
  106 + public void submitProductionIssue(Long id) {
  107 + // 校验存在 + 草稿状态
  108 + validateProductionIssueExistsAndPrepare(id);
  109 + // 校验至少有一条行
  110 + List<MesWmProductionIssueLineDO> lines = issueLineService.getProductionIssueLineListByIssueId(id);
  111 + if (CollUtil.isEmpty(lines)) {
  112 + throw exception(WM_PRODUCTION_ISSUE_NO_LINE);
  113 + }
  114 +
  115 + // 提交(草稿 → 待拣货)
  116 + issueMapper.updateById(new MesWmProductionIssueDO()
  117 + .setId(id).setStatus(MesWmProductionIssueStatusEnum.APPROVING.getStatus()));
  118 + }
  119 +
  120 + @Override
  121 + @Transactional(rollbackFor = Exception.class)
  122 + public void stockProductionIssue(Long id) {
  123 + // 校验存在
  124 + MesWmProductionIssueDO issue = validateProductionIssueExists(id);
  125 + if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVING.getStatus(), issue.getStatus())) {
  126 + throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID);
  127 + }
  128 + // 校验每行明细数量之和是否等于行领料数量
  129 + List<MesWmProductionIssueLineDO> lines = issueLineService.getProductionIssueLineListByIssueId(id);
  130 + for (MesWmProductionIssueLineDO line : lines) {
  131 + List<MesWmProductionIssueDetailDO> details = issueDetailService.getProductionIssueDetailListByLineId(line.getId());
  132 + BigDecimal totalDetailQty = CollectionUtils.getSumValue(details,
  133 + MesWmProductionIssueDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);
  134 + if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) {
  135 + throw exception(WM_PRODUCTION_ISSUE_DETAIL_QUANTITY_MISMATCH);
  136 + }
  137 + }
  138 +
  139 + // 执行拣货(待拣货 → 待执行领出)
  140 + issueMapper.updateById(new MesWmProductionIssueDO()
  141 + .setId(id).setStatus(MesWmProductionIssueStatusEnum.APPROVED.getStatus()));
  142 + }
  143 +
  144 + @Override
  145 + @Transactional(rollbackFor = Exception.class)
98 public void finishProductionIssue(Long id) { 146 public void finishProductionIssue(Long id) {
99 - // 1.1 校验存在  
100 - MesWmProductionIssueDO issue = validateIssueExists(id);  
101 - // 1.2 校验状态:只有草稿才允许完成  
102 - if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issue.getStatus())) { 147 + // 校验存在
  148 + MesWmProductionIssueDO issue = validateProductionIssueExists(id);
  149 + if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVED.getStatus(), issue.getStatus())) {
103 throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID); 150 throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID);
104 } 151 }
105 152
106 - // 2. 草稿 → 已完成  
107 - // TODO @芋艿:库存扣减逻辑待完善(需要确定仓库ID的来源,可能需要在 line 或 detail 表中添加 warehouseId 字段) 153 + // 遍历所有明细,更新库存台账(扣减库存)
  154 + // TODO @芋艿:【后续在弄】这里可能有点问题;缺少库存更新;后面在弄;
  155 + List<MesWmProductionIssueDetailDO> details = issueDetailService.getProductionIssueDetailListByIssueId(id);
  156 + for (MesWmProductionIssueDetailDO detail : details) {
  157 + // materialStockService.decreaseStock(
  158 + // detail.getItemId(), detail.getWarehouseId(), detail.getLocationId(), detail.getAreaId(),
  159 + // detail.getBatchId(), detail.getQuantity(), issue.getWorkOrderId(), null, null);
  160 + }
  161 +
  162 + // 更新出库单状态
108 issueMapper.updateById(new MesWmProductionIssueDO() 163 issueMapper.updateById(new MesWmProductionIssueDO()
109 .setId(id).setStatus(MesWmProductionIssueStatusEnum.FINISHED.getStatus())); 164 .setId(id).setStatus(MesWmProductionIssueStatusEnum.FINISHED.getStatus()));
110 } 165 }
111 166
112 - private MesWmProductionIssueDO validateIssueExists(Long id) { 167 + @Override
  168 + @Transactional(rollbackFor = Exception.class)
  169 + public void cancelProductionIssue(Long id) {
  170 + // 校验存在
  171 + MesWmProductionIssueDO issue = validateProductionIssueExists(id);
  172 + // 已完成和已取消不允许取消
  173 + if (ObjectUtils.equalsAny(issue.getStatus(),
  174 + MesWmProductionIssueStatusEnum.FINISHED.getStatus(),
  175 + MesWmProductionIssueStatusEnum.CANCELED.getStatus())) {
  176 + throw exception(WM_PRODUCTION_ISSUE_CANCEL_NOT_ALLOWED);
  177 + }
  178 + // 取消
  179 + issueMapper.updateById(new MesWmProductionIssueDO()
  180 + .setId(id).setStatus(MesWmProductionIssueStatusEnum.CANCELED.getStatus()));
  181 + }
  182 +
  183 + @Override
  184 + public MesWmProductionIssueDO validateProductionIssueExists(Long id) {
113 MesWmProductionIssueDO issue = issueMapper.selectById(id); 185 MesWmProductionIssueDO issue = issueMapper.selectById(id);
114 if (issue == null) { 186 if (issue == null) {
115 throw exception(WM_PRODUCTION_ISSUE_NOT_EXISTS); 187 throw exception(WM_PRODUCTION_ISSUE_NOT_EXISTS);
@@ -120,8 +192,8 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -120,8 +192,8 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
120 /** 192 /**
121 * 校验领料出库单存在且为准备中状态 193 * 校验领料出库单存在且为准备中状态
122 */ 194 */
123 - private MesWmProductionIssueDO validateIssueExistsAndPrepare(Long id) {  
124 - MesWmProductionIssueDO issue = validateIssueExists(id); 195 + private MesWmProductionIssueDO validateProductionIssueExistsAndPrepare(Long id) {
  196 + MesWmProductionIssueDO issue = validateProductionIssueExists(id);
125 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issue.getStatus())) { 197 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issue.getStatus())) {
126 throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID); 198 throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID);
127 } 199 }