Commit 67193b0c3b4eb90bc13ba1804243ffbbe617e542

Authored by YunaiV
1 parent 6f4aa8fd

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

新增生产领料出库单的相关数据模型、接口及前端组件,支持领料单的创建、编辑和完成操作。优化了数据校验逻辑,并添加了物料、库存和工单选择器,提升用户体验。

- 实现领料单的基本 CRUD 操作
- 增加物料和库存选择功能
- 优化前端表单布局与交互
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java
@@ -34,6 +34,9 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPOR @@ -34,6 +34,9 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPOR
34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
36 36
  37 +// TODO @AI:方法的排序,参考别的模块;
  38 +// TODO @AI:controller、service、包括其他的,都需要全。createProductitonIssue 这种;其它模块也是;
  39 +// TODO @AI:需要新增 line、detail 的 controller;参考 /Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt
37 @Tag(name = "管理后台 - MES 领料出库单") 40 @Tag(name = "管理后台 - MES 领料出库单")
38 @RestController 41 @RestController
39 @RequestMapping("/mes/wm/production-issue") 42 @RequestMapping("/mes/wm/production-issue")
@@ -102,24 +105,6 @@ public class MesWmProductionIssueController { @@ -102,24 +105,6 @@ public class MesWmProductionIssueController {
102 buildRespVOList(pageResult.getList())); 105 buildRespVOList(pageResult.getList()));
103 } 106 }
104 107
105 - @PutMapping("/approve")  
106 - @Operation(summary = "审批领料出库单")  
107 - @Parameter(name = "id", description = "编号", required = true)  
108 - @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update-status')")  
109 - public CommonResult<Boolean> approveIssue(@RequestParam("id") Long id) {  
110 - issueService.approveIssue(id);  
111 - return success(true);  
112 - }  
113 -  
114 - @PutMapping("/unapprove")  
115 - @Operation(summary = "反审批领料出库单")  
116 - @Parameter(name = "id", description = "编号", required = true)  
117 - @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update-status')")  
118 - public CommonResult<Boolean> unapproveIssue(@RequestParam("id") Long id) {  
119 - issueService.unapproveIssue(id);  
120 - return success(true);  
121 - }  
122 -  
123 @PutMapping("/finish") 108 @PutMapping("/finish")
124 @Operation(summary = "完成领料出库单") 109 @Operation(summary = "完成领料出库单")
125 @Parameter(name = "id", description = "编号", required = true) 110 @Parameter(name = "id", description = "编号", required = true)
@@ -131,6 +116,7 @@ public class MesWmProductionIssueController { @@ -131,6 +116,7 @@ public class MesWmProductionIssueController {
131 116
132 // ==================== 拼接 VO ==================== 117 // ==================== 拼接 VO ====================
133 118
  119 + // TODO @AI:这个方法的拼接,在优化下;
134 private List<MesWmProductionIssueRespVO> buildRespVOList(List<MesWmProductionIssueDO> list) { 120 private List<MesWmProductionIssueRespVO> buildRespVOList(List<MesWmProductionIssueDO> list) {
135 if (CollUtil.isEmpty(list)) { 121 if (CollUtil.isEmpty(list)) {
136 return Collections.emptyList(); 122 return Collections.emptyList();
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java
@@ -13,28 +13,25 @@ public class MesWmProductionIssueSaveReqVO { @@ -13,28 +13,25 @@ public class MesWmProductionIssueSaveReqVO {
13 @Schema(description = "编号", example = "1024") 13 @Schema(description = "编号", example = "1024")
14 private Long id; 14 private Long id;
15 15
  16 + // TODO @AI:必须传递
16 @Schema(description = "领料单编号", example = "ISSUE20250226001") 17 @Schema(description = "领料单编号", example = "ISSUE20250226001")
17 private String code; 18 private String code;
18 19
  20 + // TODO @AI:必须传递
19 @Schema(description = "领料单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "生产领料") 21 @Schema(description = "领料单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "生产领料")
20 private String name; 22 private String name;
21 23
22 - @Schema(description = "工作站ID", example = "1") 24 + // TODO @AI:必须传递
  25 + // TODO @AI:service 需要校验存在
  26 + @Schema(description = "工作站 ID", example = "1")
23 private Long workstationId; 27 private Long workstationId;
24 28
25 - @Schema(description = "生产工单ID", example = "1") 29 + @Schema(description = "生产工单 ID", example = "1")
  30 + // TODO @AI:service 需要校验存在
26 private Long workorderId; 31 private Long workorderId;
27 32
28 - @Schema(description = "生产任务ID", example = "1")  
29 - private Long taskId;  
30 -  
31 - @Schema(description = "客户ID", example = "1")  
32 - private Long clientId;  
33 -  
34 - @Schema(description = "领料日期")  
35 - private LocalDateTime issueDate;  
36 -  
37 @Schema(description = "需求时间") 33 @Schema(description = "需求时间")
  34 + // TODO @AI:必须传递
38 private LocalDateTime requiredTime; 35 private LocalDateTime requiredTime;
39 36
40 @Schema(description = "备注", example = "备注") 37 @Schema(description = "备注", example = "备注")
@@ -52,6 +49,7 @@ public class MesWmProductionIssueSaveReqVO { @@ -52,6 +49,7 @@ public class MesWmProductionIssueSaveReqVO {
52 @Schema(description = "预留字段4") 49 @Schema(description = "预留字段4")
53 private Integer attribute4; 50 private Integer attribute4;
54 51
  52 + // TODO @AI:应该单独接口,传递这个;参考别的模块;
55 @Schema(description = "领料单行列表") 53 @Schema(description = "领料单行列表")
56 private List<MesWmProductionIssueLineSaveReqVO> lines; 54 private List<MesWmProductionIssueLineSaveReqVO> lines;
57 55
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -357,4 +357,17 @@ public interface ErrorCodeConstants { @@ -357,4 +357,17 @@ public interface ErrorCodeConstants {
357 ErrorCode WM_OUTSOURCE_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_707_002, "出库单行数量与明细数量不一致"); 357 ErrorCode WM_OUTSOURCE_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_707_002, "出库单行数量与明细数量不一致");
358 ErrorCode WM_OUTSOURCE_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_707_100, "外协出库单行不存在"); 358 ErrorCode WM_OUTSOURCE_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_707_100, "外协出库单行不存在");
359 359
  360 + // ========== MES 仓库管理-生产领料出库单(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, "生产领料出库单状态不正确,无法执行该操作");
  363 + // TODO @AI:不需要的错误码,需要处理下。
  364 + ErrorCode WM_PRODUCTION_ISSUE_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_708_002, "仓库不存在");
  365 + ErrorCode WM_PRODUCTION_ISSUE_ITEM_NOT_EXISTS = new ErrorCode(1_040_708_003, "物料不存在");
  366 + ErrorCode WM_PRODUCTION_ISSUE_WORKORDER_NOT_EXISTS = new ErrorCode(1_040_708_004, "生产工单不存在");
  367 + ErrorCode WM_PRODUCTION_ISSUE_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_708_005, "工作站不存在");
  368 + ErrorCode WM_PRODUCTION_ISSUE_NO_LINE = new ErrorCode(1_040_708_006, "至少需要一条行项目");
  369 + ErrorCode WM_PRODUCTION_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_708_007, "领料单行数量与明细数量不一致");
  370 + ErrorCode WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_708_100, "生产领料出库单行不存在");
  371 + ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在");
  372 +
360 } 373 }
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.enums.MesOrderStatusConstants;
4 import lombok.AllArgsConstructor; 5 import lombok.AllArgsConstructor;
5 import lombok.Getter; 6 import lombok.Getter;
6 7
7 import java.util.Arrays; 8 import java.util.Arrays;
8 9
9 -// TODO @AI:需要使用 status constants 去映射;  
10 /** 10 /**
11 * MES 领料出库单状态枚举 11 * MES 领料出库单状态枚举
12 */ 12 */
@@ -14,9 +14,8 @@ import java.util.Arrays; @@ -14,9 +14,8 @@ import java.util.Arrays;
14 @AllArgsConstructor 14 @AllArgsConstructor
15 public enum MesWmProductionIssueStatusEnum implements ArrayValuable<Integer> { 15 public enum MesWmProductionIssueStatusEnum implements ArrayValuable<Integer> {
16 16
17 - PREPARE(10, "准备中"),  
18 - APPROVED(20, "已审批"),  
19 - FINISHED(30, "已完成"); 17 + PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
  18 + FINISHED(MesOrderStatusConstants.FINISHED, "已完成");
20 19
21 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductionIssueStatusEnum::getStatus).toArray(Integer[]::new); 20 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductionIssueStatusEnum::getStatus).toArray(Integer[]::new);
22 21
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java
@@ -53,21 +53,7 @@ public interface MesWmProductionIssueService { @@ -53,21 +53,7 @@ public interface MesWmProductionIssueService {
53 PageResult<MesWmProductionIssueDO> getIssuePage(MesWmProductionIssuePageReqVO pageReqVO); 53 PageResult<MesWmProductionIssueDO> getIssuePage(MesWmProductionIssuePageReqVO pageReqVO);
54 54
55 /** 55 /**
56 - * 审批领料出库单(准备中 → 已审批,扣减库存)  
57 - *  
58 - * @param id 编号  
59 - */  
60 - void approveIssue(Long id);  
61 -  
62 - /**  
63 - * 反审批领料出库单(已审批 → 准备中,恢复库存)  
64 - *  
65 - * @param id 编号  
66 - */  
67 - void unapproveIssue(Long id);  
68 -  
69 - /**  
70 - * 完成领料出库单(已审批 → 已完成) 56 + * 完成领料出库单(草稿 → 已完成,执行出库)
71 * 57 *
72 * @param id 编号 58 * @param id 编号
73 */ 59 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.java
@@ -4,14 +4,19 @@ import cn.hutool.core.collection.CollUtil; @@ -4,14 +4,19 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
5 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.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueLineSaveReqVO;
7 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssuePageReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssuePageReqVO;
8 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO; 9 import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO;
9 -import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueLineSaveReqVO;  
10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO;
11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO; 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO;
12 -import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper; 12 +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper;
  13 +import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper;
  14 +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper;
13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper; 15 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper;
  16 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper;
  17 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper;
14 import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductionIssueStatusEnum; 18 import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductionIssueStatusEnum;
  19 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
15 import jakarta.annotation.Resource; 20 import jakarta.annotation.Resource;
16 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
17 import org.springframework.transaction.annotation.Transactional; 22 import org.springframework.transaction.annotation.Transactional;
@@ -21,6 +26,11 @@ import java.util.Collection; @@ -21,6 +26,11 @@ import java.util.Collection;
21 import java.util.Collections; 26 import java.util.Collections;
22 import java.util.List; 27 import java.util.List;
23 28
  29 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  30 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_NOT_EXISTS;
  31 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_STATUS_INVALID;
  32 +
  33 +// TODO @AI:参考别的模块,拆分多个;
24 /** 34 /**
25 * MES 领料出库单 Service 实现类 35 * MES 领料出库单 Service 实现类
26 */ 36 */
@@ -40,17 +50,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -40,17 +50,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
40 @Resource 50 @Resource
41 private MesWmProductionIssueDetailService issueDetailService; 51 private MesWmProductionIssueDetailService issueDetailService;
42 52
  53 + @Resource
  54 + private MesWmWarehouseMapper warehouseMapper;
  55 +
  56 + @Resource
  57 + private MesMdItemMapper itemMapper;
  58 +
  59 + @Resource
  60 + private MesMdWorkstationMapper workstationMapper;
  61 +
  62 + @Resource
  63 + private MesProWorkOrderMapper workOrderMapper;
  64 +
  65 + @Resource
  66 + private MesWmMaterialStockService materialStockService;
  67 +
43 @Override 68 @Override
44 @Transactional(rollbackFor = Exception.class) 69 @Transactional(rollbackFor = Exception.class)
45 public Long createIssue(MesWmProductionIssueSaveReqVO createReqVO) { 70 public Long createIssue(MesWmProductionIssueSaveReqVO createReqVO) {
46 - // TODO @AI:领料出库关联数据校验待完善(仓库、物料、工单、工位等基础数据校验) 71 + // 1. 校验关联数据
  72 + validateRelatedData(createReqVO);
47 73
48 - // 1. 插入主表 74 + // 2. 插入主表
49 MesWmProductionIssueDO issueHeader = BeanUtils.toBean(createReqVO, MesWmProductionIssueDO.class); 75 MesWmProductionIssueDO issueHeader = BeanUtils.toBean(createReqVO, MesWmProductionIssueDO.class);
50 issueHeader.setStatus(MesWmProductionIssueStatusEnum.PREPARE.getStatus()); 76 issueHeader.setStatus(MesWmProductionIssueStatusEnum.PREPARE.getStatus());
51 issueHeaderMapper.insert(issueHeader); 77 issueHeaderMapper.insert(issueHeader);
52 78
53 - // 2. 插入行表 79 + // 3. 插入行表
54 if (CollUtil.isNotEmpty(createReqVO.getLines())) { 80 if (CollUtil.isNotEmpty(createReqVO.getLines())) {
55 for (MesWmProductionIssueLineSaveReqVO lineVO : createReqVO.getLines()) { 81 for (MesWmProductionIssueLineSaveReqVO lineVO : createReqVO.getLines()) {
56 MesWmProductionIssueLineDO line = BeanUtils.toBean(lineVO, MesWmProductionIssueLineDO.class); 82 MesWmProductionIssueLineDO line = BeanUtils.toBean(lineVO, MesWmProductionIssueLineDO.class);
@@ -67,13 +93,15 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -67,13 +93,15 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
67 public void updateIssue(MesWmProductionIssueSaveReqVO updateReqVO) { 93 public void updateIssue(MesWmProductionIssueSaveReqVO updateReqVO) {
68 // 1. 校验存在 + 准备中状态 94 // 1. 校验存在 + 准备中状态
69 validateIssueExistsAndPrepare(updateReqVO.getId()); 95 validateIssueExistsAndPrepare(updateReqVO.getId());
70 - // TODO @AI:领料出库关联数据校验待完善(仓库、物料、工单、工位等基础数据校验)  
71 96
72 - // 2. 更新主表 97 + // 2. 校验关联数据
  98 + validateRelatedData(updateReqVO);
  99 +
  100 + // 3. 更新主表
73 MesWmProductionIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueDO.class); 101 MesWmProductionIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueDO.class);
74 issueHeaderMapper.updateById(updateObj); 102 issueHeaderMapper.updateById(updateObj);
75 103
76 - // 3. 更新行表:先删除旧数据,再插入新数据 104 + // 4. 更新行表:先删除旧数据,再插入新数据
77 issueLineMapper.deleteByIssueId(updateReqVO.getId()); 105 issueLineMapper.deleteByIssueId(updateReqVO.getId());
78 if (CollUtil.isNotEmpty(updateReqVO.getLines())) { 106 if (CollUtil.isNotEmpty(updateReqVO.getLines())) {
79 for (MesWmProductionIssueLineSaveReqVO lineVO : updateReqVO.getLines()) { 107 for (MesWmProductionIssueLineSaveReqVO lineVO : updateReqVO.getLines()) {
@@ -110,51 +138,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -110,51 +138,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
110 138
111 @Override 139 @Override
112 @Transactional(rollbackFor = Exception.class) 140 @Transactional(rollbackFor = Exception.class)
113 - public void approveIssue(Long id) { 141 + public void finishIssue(Long id) {
114 // 1.1 校验存在 142 // 1.1 校验存在
115 MesWmProductionIssueDO issueHeader = validateIssueExists(id); 143 MesWmProductionIssueDO issueHeader = validateIssueExists(id);
116 - // 1.2 校验状态:只有准备中才允许审批 144 + // 1.2 校验状态:只有草稿才允许完成
117 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) { 145 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) {
118 -// throw exception(WM_ISSUE_STATUS_INVALID);  
119 - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下;  
120 - }  
121 -  
122 - // 2. 准备中 → 已审批  
123 - issueHeaderMapper.updateById(new MesWmProductionIssueDO()  
124 - .setId(id).setStatus(MesWmProductionIssueStatusEnum.APPROVED.getStatus()));  
125 -  
126 - // TODO @AI:扣减库存逻辑待完善(需要调用库存服务,根据 detail 表扣减库存)  
127 - }  
128 -  
129 - @Override  
130 - @Transactional(rollbackFor = Exception.class)  
131 - public void unapproveIssue(Long id) {  
132 - // 1.1 校验存在  
133 - MesWmProductionIssueDO issueHeader = validateIssueExists(id);  
134 - // 1.2 校验状态:只有已审批才允许反审批  
135 - if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVED.getStatus(), issueHeader.getStatus())) {  
136 -// throw exception(WM_ISSUE_STATUS_INVALID);  
137 - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; 146 + throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID);
138 } 147 }
139 148
140 - // 2. 已审批 → 准备中  
141 - issueHeaderMapper.updateById(new MesWmProductionIssueDO()  
142 - .setId(id).setStatus(MesWmProductionIssueStatusEnum.PREPARE.getStatus()));  
143 -  
144 - // TODO @AI:恢复库存逻辑待完善(需要调用库存服务,根据 detail 表恢复库存)  
145 - }  
146 -  
147 - @Override  
148 - public void finishIssue(Long id) {  
149 - // 1.1 校验存在  
150 - MesWmProductionIssueDO issueHeader = validateIssueExists(id);  
151 - // 1.2 校验状态:只有已审批才允许完成  
152 - if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVED.getStatus(), issueHeader.getStatus())) {  
153 -// throw exception(WM_ISSUE_STATUS_INVALID);  
154 - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; 149 + // 2. 扣减库存(根据 line 表)
  150 + List<MesWmProductionIssueLineDO> lines = issueLineMapper.selectByIssueId(id);
  151 + if (CollUtil.isNotEmpty(lines)) {
  152 + for (MesWmProductionIssueLineDO line : lines) {
  153 + materialStockService.increaseStock(
  154 + line.getItemId(),
  155 + issueHeader.getWarehouseId(), // 使用主表的仓库ID
  156 + null, // locationId
  157 + null, // areaId
  158 + line.getBatchId(),
  159 + line.getQuantityIssued().negate(), // 负数表示扣减
  160 + null, // vendorId
  161 + null, // productionDate
  162 + null // expireDate
  163 + );
  164 + }
155 } 165 }
156 166
157 - // 2. 已审批 → 已完成 167 + // 3. 草稿 → 已完成
158 issueHeaderMapper.updateById(new MesWmProductionIssueDO() 168 issueHeaderMapper.updateById(new MesWmProductionIssueDO()
159 .setId(id).setStatus(MesWmProductionIssueStatusEnum.FINISHED.getStatus())); 169 .setId(id).setStatus(MesWmProductionIssueStatusEnum.FINISHED.getStatus()));
160 } 170 }
@@ -170,8 +180,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -170,8 +180,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
170 private MesWmProductionIssueDO validateIssueExists(Long id) { 180 private MesWmProductionIssueDO validateIssueExists(Long id) {
171 MesWmProductionIssueDO issueHeader = issueHeaderMapper.selectById(id); 181 MesWmProductionIssueDO issueHeader = issueHeaderMapper.selectById(id);
172 if (issueHeader == null) { 182 if (issueHeader == null) {
173 -// throw exception(WM_ISSUE_NOT_EXISTS);  
174 - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; 183 + throw exception(WM_PRODUCTION_ISSUE_NOT_EXISTS);
175 } 184 }
176 return issueHeader; 185 return issueHeader;
177 } 186 }
@@ -182,8 +191,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @@ -182,8 +191,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ
182 private MesWmProductionIssueDO validateIssueExistsAndPrepare(Long id) { 191 private MesWmProductionIssueDO validateIssueExistsAndPrepare(Long id) {
183 MesWmProductionIssueDO issueHeader = validateIssueExists(id); 192 MesWmProductionIssueDO issueHeader = validateIssueExists(id);
184 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) { 193 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) {
185 -// throw exception(WM_ISSUE_STATUS_INVALID);  
186 - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; 194 + throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID);
187 } 195 }
188 return issueHeader; 196 return issueHeader;
189 } 197 }