Commit f7b06a095267da7562c47c29a7dbbf84a0d85a27

Authored by YunaiV
1 parent 7098655a

fix(mes): 完善生产工单模块,优化 BOM 展开、工单状态校验及仓库删除保护

1. BomController:新增物料需求接口 /item-list-by-work-order-id,
   采用逐层 IN 查询展开 BOM 到叶子物料(替代递归),使用 convertMultiMap 统一风格;
   补充 BomRespVO 的 itemOrProduct 字段及 itemType 拼接
2. WorkOrderController:新增 confirmWorkOrder 确认接口,
   调整 confirm/finish/cancel 端点顺序;parentMap 改用 getWorkOrderMap
3. WorkOrderService/ServiceImpl:新增 getWorkOrderList 空判断、getWorkOrderMap、
   confirmWorkOrder 状态校验,finish/cancel 增加"已确认"状态前置校验,
   新增 PRO_WORK_ORDER_NOT_CONFIRMED 错误码
4. ProductBomMapper/Service:新增 selectByItemIds 批量查询方法
5. 仓库/库区/库位删除:补充库存记录占用校验(WM_WAREHOUSE_HAS_MATERIAL_STOCK 等)
6. 移除工单 batchCode 字段(DO/SaveReqVO/RespVO)
Showing 13 changed files with 228 additions and 45 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java
... ... @@ -5,13 +5,18 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO;
8 9 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO;
9 10 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomRespVO;
10 11 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO;
11 12 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
12 15 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
13 16 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
14 17 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  18 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService;
  19 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService;
15 20 import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
16 21 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService;
17 22 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -23,11 +28,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
23 28 import org.springframework.validation.annotation.Validated;
24 29 import org.springframework.web.bind.annotation.*;
25 30  
26   -import java.util.Collections;
27   -import java.util.List;
28   -import java.util.Map;
29   -
  31 +import java.math.BigDecimal;
  32 +import java.util.*;
30 33 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
31 35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
32 36  
33 37 @Tag(name = "管理后台 - MES 生产工单 BOM")
... ... @@ -45,6 +49,12 @@ public class MesProWorkOrderBomController {
45 49 @Resource
46 50 private MesMdUnitMeasureService unitMeasureService;
47 51  
  52 + @Resource
  53 + private MesMdItemTypeService itemTypeService;
  54 +
  55 + @Resource
  56 + private MesMdProductBomService productBomService;
  57 +
48 58 @PostMapping("/create")
49 59 @Operation(summary = "创建工单 BOM")
50 60 @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')")
... ... @@ -89,6 +99,44 @@ public class MesProWorkOrderBomController {
89 99 return success(new PageResult<>(buildWorkOrderBomRespVOList(pageResult.getList()), pageResult.getTotal()));
90 100 }
91 101  
  102 + @GetMapping("/item-list-by-work-order-id")
  103 + @Operation(summary = "获得工单物料需求列表")
  104 + @Parameter(name = "workOrderId", description = "工单编号", required = true)
  105 + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')")
  106 + public CommonResult<List<MesProWorkOrderItemRespVO>> getWorkOrderBomItemListByWorkOrderId(
  107 + @RequestParam("workOrderId") Long workOrderId) {
  108 + // 1. 获取工单 BOM 行
  109 + List<MesProWorkOrderBomDO> bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId);
  110 + if (CollUtil.isEmpty(bomList)) {
  111 + return success(Collections.emptyList());
  112 + }
  113 +
  114 + // 2. 逐层展开,得到叶子物料 itemId → quantity
  115 + Map<Long, BigDecimal> leafItems = buildWorkOrderItems(bomList);
  116 + if (leafItems.isEmpty()) {
  117 + return success(Collections.emptyList());
  118 + }
  119 +
  120 + // 3. 拼接 VO 字段
  121 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(leafItems.keySet());
  122 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  123 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  124 + List<MesProWorkOrderItemRespVO> result = new ArrayList<>(leafItems.size());
  125 + for (Map.Entry<Long, BigDecimal> entry : leafItems.entrySet()) {
  126 + MesMdItemDO item = itemMap.get(entry.getKey());
  127 + if (item == null) {
  128 + continue;
  129 + }
  130 + MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO()
  131 + .setItemId(item.getId()).setQuantity(entry.getValue())
  132 + .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification());
  133 + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
  134 + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
  135 + result.add(vo);
  136 + }
  137 + return success(result);
  138 + }
  139 +
92 140 // ==================== 拼接 VO ====================
93 141  
94 142 private List<MesProWorkOrderBomRespVO> buildWorkOrderBomRespVOList(List<MesProWorkOrderBomDO> list) {
... ... @@ -100,14 +148,62 @@ public class MesProWorkOrderBomController {
100 148 convertSet(list, MesProWorkOrderBomDO::getItemId));
101 149 Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
102 150 convertSet(list, MesProWorkOrderBomDO::getUnitMeasureId));
  151 + Map<Long, MesMdItemTypeDO> itemTypeMap = itemTypeService.getItemTypeMap(
  152 + convertSet(itemMap.values(), MesMdItemDO::getItemTypeId));
103 153 // 2. 拼接 VO
104 154 return BeanUtils.toBean(list, MesProWorkOrderBomRespVO.class, vo -> {
105   - MapUtils.findAndThen(itemMap, vo.getItemId(), item ->
106   - vo.setItemName(item.getName()).setItemCode(item.getCode())
107   - .setItemSpec(item.getSpecification()));
  155 + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
  156 + vo.setItemName(item.getName()).setItemCode(item.getCode())
  157 + .setItemSpec(item.getSpecification());
  158 + MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(),
  159 + itemType -> vo.setItemOrProduct(itemType.getItemOrProduct()));
  160 + });
108 161 MapUtils.findAndThen(unitMeasureMap, vo.getUnitMeasureId(),
109 162 unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
110 163 });
111 164 }
112 165  
  166 + // ==================== 物料需求逐层展开 ====================
  167 +
  168 + /**
  169 + * 逐层 IN 查询展开工单 BOM 到叶子物料,合并同物料的需求数量
  170 + *
  171 + * @param bomList 工单 BOM 列表
  172 + * @return 叶子物料 Map:itemId → 合并后的需求数量
  173 + */
  174 + private Map<Long, BigDecimal> buildWorkOrderItems(List<MesProWorkOrderBomDO> bomList) {
  175 + // 1. 初始化:收集第一层物料 ID 和对应数量
  176 + Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>();
  177 + for (MesProWorkOrderBomDO bom : bomList) {
  178 + currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add);
  179 + }
  180 +
  181 + // 2. 逐层 IN 查询展开 BOM
  182 + Map<Long, BigDecimal> leafItems = new LinkedHashMap<>();
  183 + for (int i = 0; i < Byte.MAX_VALUE && CollUtil.isNotEmpty(currentLayer); i++) {
  184 + // 2.1 批量查询当前层所有物料的子 BOM
  185 + List<MesMdProductBomDO> subBomList = productBomService.getProductBomListByItemIds(currentLayer.keySet());
  186 + // 2.2 按 itemId 分组
  187 + Map<Long, List<MesMdProductBomDO>> subBomMap = convertMultiMap(subBomList, MesMdProductBomDO::getItemId);
  188 + // 2.3 区分叶子节点和非叶子节点
  189 + Map<Long, BigDecimal> nextLayer = new LinkedHashMap<>();
  190 + for (Map.Entry<Long, BigDecimal> entry : currentLayer.entrySet()) {
  191 + Long itemId = entry.getKey();
  192 + BigDecimal quantity = entry.getValue();
  193 + List<MesMdProductBomDO> children = subBomMap.get(itemId);
  194 + // 情况一:叶子节点,累加到结果
  195 + if (CollUtil.isEmpty(children)) {
  196 + leafItems.merge(itemId, quantity, BigDecimal::add);
  197 + continue;
  198 + }
  199 + // 情况二:非叶子,子物料进入下一层
  200 + for (MesMdProductBomDO child : children) {
  201 + nextLayer.merge(child.getBomItemId(), quantity.multiply(child.getQuantity()), BigDecimal::add);
  202 + }
  203 + }
  204 + currentLayer = nextLayer;
  205 + }
  206 + return leafItems;
  207 + }
  208 +
113 209 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java
... ... @@ -32,14 +32,10 @@ import org.springframework.validation.annotation.Validated;
32 32 import org.springframework.web.bind.annotation.*;
33 33  
34 34 import java.io.IOException;
35   -import java.util.Collections;
36   -import java.util.List;
37   -import java.util.Map;
38   -import java.util.Set;
  35 +import java.util.*;
39 36  
40 37 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
41 38 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
42   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
43 39 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
44 40  
45 41 @Tag(name = "管理后台 - MES 生产工单")
... ... @@ -119,6 +115,15 @@ public class MesProWorkOrderController {
119 115 ExcelUtils.write(response, "生产工单.xls", "数据", MesProWorkOrderRespVO.class, voList);
120 116 }
121 117  
  118 + @PutMapping("/confirm")
  119 + @Operation(summary = "确认工单")
  120 + @Parameter(name = "id", description = "编号", required = true)
  121 + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')")
  122 + public CommonResult<Boolean> confirmWorkOrder(@RequestParam("id") Long id) {
  123 + workOrderService.confirmWorkOrder(id);
  124 + return success(true);
  125 + }
  126 +
122 127 @PutMapping("/finish")
123 128 @Operation(summary = "完成工单")
124 129 @Parameter(name = "id", description = "编号", required = true)
... ... @@ -152,11 +157,8 @@ public class MesProWorkOrderController {
152 157 convertSet(list, MesProWorkOrderDO::getVendorId));
153 158 Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
154 159 convertSet(list, MesProWorkOrderDO::getUnitMeasureId));
155   - // TODO @AI:直接 workOrderService.getWorkOrderMap,内部调用 workOrderService.getWorkOrderList
156   - Set<Long> parentIds = convertSet(list, MesProWorkOrderDO::getParentId);
157   - Map<Long, MesProWorkOrderDO> parentMap = CollUtil.isEmpty(parentIds)
158   - ? Collections.emptyMap()
159   - : convertMap(workOrderService.getWorkOrderList(parentIds), MesProWorkOrderDO::getId);
  160 + Map<Long, MesProWorkOrderDO> parentMap = workOrderService.getWorkOrderMap(
  161 + convertSet(list, MesProWorkOrderDO::getParentId));
160 162 // 2. 拼接 VO
161 163 return BeanUtils.toBean(list, MesProWorkOrderRespVO.class, vo -> {
162 164 MapUtils.findAndThen(itemMap, vo.getProductId(), item ->
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +
  8 +@Schema(description = "管理后台 - MES 工单物料需求 Response VO")
  9 +@Data
  10 +public class MesProWorkOrderItemRespVO {
  11 +
  12 + @Schema(description = "物料编号", example = "100")
  13 + private Long itemId;
  14 +
  15 + @Schema(description = "物料编码", example = "M-001")
  16 + private String itemCode;
  17 +
  18 + @Schema(description = "物料名称", example = "电阻 10K")
  19 + private String itemName;
  20 +
  21 + @Schema(description = "规格型号", example = "0603")
  22 + private String itemSpec;
  23 +
  24 + @Schema(description = "单位名称", example = "个")
  25 + private String unitMeasureName;
  26 +
  27 + @Schema(description = "需求数量", example = "1000.00")
  28 + private BigDecimal quantity;
  29 +
  30 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkorderRespVO.java
... ... @@ -98,10 +98,6 @@ public class MesProWorkOrderRespVO {
98 98 @ExcelProperty("供应商名称")
99 99 private String vendorName;
100 100  
101   - @Schema(description = "批次号", example = "BATCH-001")
102   - @ExcelProperty("批次号")
103   - private String batchCode;
104   -
105 101 @Schema(description = "需求日期")
106 102 @ExcelProperty("需求日期")
107 103 private LocalDateTime requestDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkorderSaveReqVO.java
... ... @@ -61,9 +61,6 @@ public class MesProWorkOrderSaveReqVO {
61 61 @Schema(description = "供应商编号", example = "400")
62 62 private Long vendorId;
63 63  
64   - @Schema(description = "批次号", example = "BATCH-001")
65   - private String batchCode;
66   -
67 64 @Schema(description = "需求日期", requiredMode = Schema.RequiredMode.REQUIRED)
68 65 @NotNull(message = "需求日期不能为空")
69 66 private LocalDateTime requestDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java
... ... @@ -50,6 +50,9 @@ public class MesProWorkOrderBomRespVO {
50 50 @ExcelProperty("备注")
51 51 private String remark;
52 52  
  53 + @Schema(description = "物料产品标识", example = "PRODUCT")
  54 + private String itemOrProduct;
  55 +
53 56 @Schema(description = "预留字段1")
54 57 private String attribute1;
55 58  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java
... ... @@ -101,10 +101,6 @@ public class MesProWorkOrderDO extends BaseDO {
101 101 */
102 102 private Long vendorId;
103 103 /**
104   - * 批次号
105   - */
106   - private String batchCode;
107   - /**
108 104 * 需求日期
109 105 */
110 106 private LocalDateTime requestDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductB
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
  10 +import java.util.Collection;
10 11 import java.util.List;
11 12  
12 13 /**
... ... @@ -28,6 +29,10 @@ public interface MesMdProductBomMapper extends BaseMapperX&lt;MesMdProductBomDO&gt; {
28 29 return selectList(MesMdProductBomDO::getItemId, itemId);
29 30 }
30 31  
  32 + default List<MesMdProductBomDO> selectByItemIds(Collection<Long> itemIds) {
  33 + return selectList(MesMdProductBomDO::getItemId, itemIds);
  34 + }
  35 +
31 36 default List<MesMdProductBomDO> selectAll() {
32 37 return selectList();
33 38 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -167,6 +167,7 @@ public interface ErrorCodeConstants {
167 167 ErrorCode PRO_WORK_ORDER_NOT_EXISTS = new ErrorCode(1_040_502_000, "生产工单不存在");
168 168 ErrorCode PRO_WORK_ORDER_CODE_DUPLICATE = new ErrorCode(1_040_502_001, "生产工单编码已存在");
169 169 ErrorCode PRO_WORK_ORDER_NOT_PREPARE = new ErrorCode(1_040_502_002, "只能删除草稿状态的工单");
  170 + ErrorCode PRO_WORK_ORDER_NOT_CONFIRMED = new ErrorCode(1_040_502_003, "只有已确认状态的工单才能执行此操作");
170 171 ErrorCode PRO_WORK_ORDER_BOM_NOT_EXISTS = new ErrorCode(1_040_502_100, "生产工单BOM不存在");
171 172  
172 173 // ========== MES 生产管理-生产任务(1-040-503-000) ==========
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductB
6 6 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
7 7 import jakarta.validation.Valid;
8 8  
  9 +import java.util.Collection;
9 10 import java.util.List;
10 11  
11 12 /**
... ... @@ -62,6 +63,14 @@ public interface MesMdProductBomService {
62 63 List<MesMdProductBomDO> getProductBomListByItemId(Long itemId);
63 64  
64 65 /**
  66 + * 根据物料产品编号批量获得产品BOM列表
  67 + *
  68 + * @param itemIds 物料产品编号数组
  69 + * @return 产品BOM列表
  70 + */
  71 + List<MesMdProductBomDO> getProductBomListByItemIds(Collection<Long> itemIds);
  72 +
  73 + /**
65 74 * 根据物料产品编号删除产品BOM
66 75 *
67 76 * @param itemId 物料产品编号
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java
... ... @@ -133,6 +133,11 @@ public class MesMdProductBomServiceImpl implements MesMdProductBomService {
133 133 }
134 134  
135 135 @Override
  136 + public List<MesMdProductBomDO> getProductBomListByItemIds(Collection<Long> itemIds) {
  137 + return productBomMapper.selectByItemIds(itemIds);
  138 + }
  139 +
  140 + @Override
136 141 public void deleteProductBomByItemId(Long itemId) {
137 142 productBomMapper.deleteByItemId(itemId);
138 143 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java
... ... @@ -8,6 +8,9 @@ import jakarta.validation.Valid;
8 8  
9 9 import java.util.Collection;
10 10 import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
11 14  
12 15 /**
13 16 * MES 生产工单 Service 接口
... ... @@ -63,25 +66,42 @@ public interface MesProWorkOrderService {
63 66 PageResult<MesProWorkOrderDO> getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO);
64 67  
65 68 /**
66   - * 完成工单
  69 + * 获得工单列表
  70 + *
  71 + * @param ids 编号数组
  72 + * @return 工单列表
  73 + */
  74 + List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids);
  75 +
  76 + /**
  77 + * 获得工单 Map
  78 + *
  79 + * @param ids 编号数组
  80 + * @return 工单 Map
  81 + */
  82 + default Map<Long, MesProWorkOrderDO> getWorkOrderMap(Collection<Long> ids) {
  83 + return convertMap(getWorkOrderList(ids), MesProWorkOrderDO::getId);
  84 + }
  85 +
  86 + /**
  87 + * 确认工单(草稿 → 已确认)
67 88 *
68 89 * @param id 编号
69 90 */
70   - void finishWorkOrder(Long id);
  91 + void confirmWorkOrder(Long id);
71 92  
72 93 /**
73   - * 取消工单
  94 + * 完成工单
74 95 *
75 96 * @param id 编号
76 97 */
77   - void cancelWorkOrder(Long id);
  98 + void finishWorkOrder(Long id);
78 99  
79 100 /**
80   - * 获得工单列表
  101 + * 取消工单
81 102 *
82   - * @param ids 编号数组
83   - * @return 工单列表
  103 + * @param id 编号
84 104 */
85   - List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids);
  105 + void cancelWorkOrder(Long id);
86 106  
87 107 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java
... ... @@ -25,6 +25,7 @@ import org.springframework.validation.annotation.Validated;
25 25 import java.math.BigDecimal;
26 26 import java.time.LocalDateTime;
27 27 import java.util.Collection;
  28 +import java.util.Collections;
28 29 import java.util.List;
29 30  
30 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -139,9 +140,33 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
139 140 }
140 141  
141 142 @Override
142   - public void finishWorkOrder(Long id) {
  143 + public List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids) {
  144 + if (CollUtil.isEmpty(ids)) {
  145 + return Collections.emptyList();
  146 + }
  147 + return workOrderMapper.selectByIds(ids);
  148 + }
  149 +
  150 + @Override
  151 + public void confirmWorkOrder(Long id) {
143 152 // 1. 校验存在
144   - validateWorkOrderExists(id);
  153 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
  154 + // 2. 只有草稿状态才能确认
  155 + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) {
  156 + throw exception(PRO_WORK_ORDER_NOT_PREPARE);
  157 + }
  158 + // 3. 更新状态为已确认
  159 + workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
  160 + .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus()));
  161 + }
  162 +
  163 + @Override
  164 + public void finishWorkOrder(Long id) {
  165 + // 1. 校验存在 + 只有已确认状态才能完成
  166 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
  167 + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
  168 + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
  169 + }
145 170  
146 171 // 2. 更新状态为已完成
147 172 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
... ... @@ -152,8 +177,11 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
152 177  
153 178 @Override
154 179 public void cancelWorkOrder(Long id) {
155   - // 1. 校验存在
156   - validateWorkOrderExists(id);
  180 + // 1. 校验存在 + 只有已确认状态才能取消
  181 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
  182 + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
  183 + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
  184 + }
157 185  
158 186 // 2. 更新状态为已取消
159 187 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
... ... @@ -162,11 +190,6 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
162 190 // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态
163 191 }
164 192  
165   - @Override
166   - public List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids) {
167   - return workOrderMapper.selectByIds(ids);
168   - }
169   -
170 193 // ==================== 校验方法 ====================
171 194  
172 195 private void validateWorkOrderCodeUnique(Long id, String code) {
... ...