Commit f51654ccbc0213eb26208610586edc5de17c5c6d

Authored by YunaiV
1 parent dc7afd47

✨ feat(mes): 添加工单任务状态管理功能

yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/task/MesProTaskDO.java
1 1 package cn.iocoder.yudao.module.mes.dal.dataobject.pro.task;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO;
4 5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
6 7 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
7 8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
8 9 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
9 10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
  11 +import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
10 12 import com.baomidou.mybatisplus.annotation.KeySequence;
11 13 import com.baomidou.mybatisplus.annotation.TableId;
12 14 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -79,6 +81,7 @@ public class MesProTaskDO extends BaseDO {
79 81 * 关联 {@link MesMdUnitMeasureDO#getId()}
80 82 */
81 83 private Long unitMeasureId;
  84 +
82 85 /**
83 86 * 排产数量
84 87 */
... ... @@ -99,8 +102,11 @@ public class MesProTaskDO extends BaseDO {
99 102 * 调整数量
100 103 */
101 104 private BigDecimal changedQuantity;
  105 +
102 106 /**
103 107 * 客户编号
  108 + *
  109 + * 关联 {@link MesMdClientDO#getId()}
104 110 */
105 111 private Long clientId;
106 112 /**
... ... @@ -127,8 +133,11 @@ public class MesProTaskDO extends BaseDO {
127 133 * 取消日期
128 134 */
129 135 private LocalDateTime cancelDate;
  136 +
130 137 /**
131 138 * 任务状态
  139 + *
  140 + * 枚举 {@link MesProTaskStatusEnum}
132 141 */
133 142 private Integer status;
134 143 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java
... ... @@ -32,6 +32,11 @@ import java.time.LocalDateTime;
32 32 public class MesProWorkOrderDO extends BaseDO {
33 33  
34 34 /**
  35 + * 父工单编号,空值
  36 + */
  37 + public static final Long PARENT_ID_NULL = 0L;
  38 +
  39 + /**
35 40 * 编号
36 41 */
37 42 @TableId
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProTaskStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.pro;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO;
  5 +import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  6 +import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
  7 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  8 +import lombok.AllArgsConstructor;
  9 +import lombok.Getter;
  10 +
  11 +import java.util.Arrays;
  12 +
  13 +/**
  14 + * MES 生产任务状态枚举
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Getter
  19 +@AllArgsConstructor
  20 +public enum MesProTaskStatusEnum implements ArrayValuable<Integer> {
  21 +
  22 + /**
  23 + * 草稿
  24 + *
  25 + * 对应方法:{@link MesProTaskService#createTask(MesProTaskSaveReqVO)}
  26 + */
  27 + PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
  28 + /**
  29 + * 已完成
  30 + *
  31 + * 对应方法:{@link MesProTaskService#finishTaskByOrderId(Long)}
  32 + */
  33 + FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
  34 + /**
  35 + * 已取消
  36 + *
  37 + * 对应方法:{@link MesProTaskService#cancelTaskByOrderId(Long)}
  38 + */
  39 + CANCELED(MesOrderStatusConstants.CANCELLED, "已取消");
  40 +
  41 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProTaskStatusEnum::getStatus).toArray(Integer[]::new);
  42 +
  43 + /**
  44 + * 状态值
  45 + */
  46 + private final Integer status;
  47 + /**
  48 + * 状态名
  49 + */
  50 + private final String name;
  51 +
  52 + @Override
  53 + public Integer[] array() {
  54 + return ARRAYS;
  55 + }
  56 +
  57 + /**
  58 + * 判断是否为终态(已完成 或 已取消)
  59 + *
  60 + * @param status 状态值
  61 + * @return 是否为终态
  62 + */
  63 + public static boolean isEndStatus(Integer status) {
  64 + return ObjectUtils.equalsAny(status, FINISHED.status, CANCELED.status);
  65 + }
  66 +
  67 +}
  68 +
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java
... ... @@ -90,4 +90,18 @@ public interface MesProTaskService {
90 90 return convertMap(getTaskList(ids), MesProTaskDO::getId);
91 91 }
92 92  
  93 + /**
  94 + * 根据工单编号,完成所有关联任务
  95 + *
  96 + * @param workOrderId 工单编号
  97 + */
  98 + void finishTaskByOrderId(Long workOrderId);
  99 +
  100 + /**
  101 + * 根据工单编号,取消所有关联任务
  102 + *
  103 + * @param workOrderId 工单编号
  104 + */
  105 + void cancelTaskByOrderId(Long workOrderId);
  106 +
93 107 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.pro.task;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
6 7 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO;
7 8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
8 9 import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
  10 +import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
9 11 import jakarta.annotation.Resource;
10 12 import org.springframework.stereotype.Service;
11 13 import org.springframework.validation.annotation.Validated;
12 14  
  15 +import java.time.LocalDateTime;
13 16 import java.util.Collection;
14 17 import java.util.List;
15 18  
16 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
17 21 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_EXISTS;
18 22  
19 23 /**
... ... @@ -75,7 +79,38 @@ public class MesProTaskServiceImpl implements MesProTaskService {
75 79  
76 80 @Override
77 81 public List<MesProTaskDO> getTaskList(Collection<Long> ids) {
78   - return taskMapper.selectBatchIds(ids);
  82 + return taskMapper.selectByIds(ids);
  83 + }
  84 +
  85 + @Override
  86 + public void finishTaskByOrderId(Long workOrderId) {
  87 + // 1. 读取工单下所有任务,过滤掉已完成/已取消的
  88 + List<MesProTaskDO> tasks = taskMapper.selectListByWorkOrderId(workOrderId);
  89 + LocalDateTime now = LocalDateTime.now();
  90 + // 2. 构建待更新列表,批量更新
  91 + List<MesProTaskDO> updateList = convertList(tasks,
  92 + task -> new MesProTaskDO().setId(task.getId())
  93 + .setStatus(MesProTaskStatusEnum.FINISHED.getStatus()).setFinishDate(now),
  94 + task -> !MesProTaskStatusEnum.isEndStatus(task.getStatus()));
  95 + if (CollUtil.isNotEmpty(updateList)) {
  96 + taskMapper.updateBatch(updateList);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public void cancelTaskByOrderId(Long workOrderId) {
  102 + // 1. 读取工单下所有任务,过滤掉已完成/已取消的
  103 + List<MesProTaskDO> tasks = taskMapper.selectListByWorkOrderId(workOrderId);
  104 + LocalDateTime now = LocalDateTime.now();
  105 + // 2. 构建待更新列表,批量更新
  106 + List<MesProTaskDO> updateList = convertList(tasks,
  107 + task -> new MesProTaskDO().setId(task.getId())
  108 + .setStatus(MesProTaskStatusEnum.CANCELED.getStatus()).setCancelDate(now),
  109 + task -> !MesProTaskStatusEnum.isEndStatus(task.getStatus()));
  110 + if (CollUtil.isNotEmpty(updateList)) {
  111 + taskMapper.updateBatch(updateList);
  112 + }
79 113 }
80 114  
81 115 }
  116 +
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java
1 1 package cn.iocoder.yudao.module.mes.service.pro.workorder;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
4 5 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO;
5 6 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO;
6 7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
... ... @@ -68,4 +69,15 @@ public interface MesProWorkOrderBomService {
68 69 */
69 70 void deleteWorkOrderBomByWorkOrderId(Long workOrderId);
70 71  
  72 + /**
  73 + * 根据产品 BOM 自动生成工单 BOM 行
  74 + * <p>
  75 + * 如果 updated 为 true,会先清理旧的 BOM 数据再重新生成
  76 + *
  77 + * @param workOrderId 工单编号
  78 + * @param reqVO 工单创建/更新请求(取 productId、quantity)
  79 + * @param updated 是否为更新场景(true 时先删除旧 BOM)
  80 + */
  81 + void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated);
  82 +
71 83 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.pro.workorder;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
5 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO;
6 9 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
7 12 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
8 13 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderBomMapper;
  14 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  15 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService;
9 16 import jakarta.annotation.Resource;
10 17 import org.springframework.context.annotation.Lazy;
11 18 import org.springframework.stereotype.Service;
12 19 import org.springframework.validation.annotation.Validated;
13 20  
14   -import java.util.List;
  21 +import java.util.*;
15 22  
16 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  24 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS;
17 25 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORK_ORDER_BOM_NOT_EXISTS;
18 26  
19 27 /**
... ... @@ -31,11 +39,17 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
31 39 @Resource
32 40 @Lazy // 延迟加载,避免循环依赖
33 41 private MesProWorkOrderService workOrderService;
  42 + @Resource
  43 + private MesMdItemService itemService;
  44 + @Resource
  45 + private MesMdProductBomService productBomService;
34 46  
35 47 @Override
36 48 public Long createWorkOrderBom(MesProWorkOrderBomSaveReqVO createReqVO) {
37 49 // 校验工单存在
38 50 workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
  51 +
  52 + // 插入数据
39 53 MesProWorkOrderBomDO workOrderBom = BeanUtils.toBean(createReqVO, MesProWorkOrderBomDO.class);
40 54 workOrderBomMapper.insert(workOrderBom);
41 55 return workOrderBom.getId();
... ... @@ -45,7 +59,8 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
45 59 public void updateWorkOrderBom(MesProWorkOrderBomSaveReqVO updateReqVO) {
46 60 // 校验存在
47 61 validateWorkOrderBomExists(updateReqVO.getId());
48   - // 更新
  62 +
  63 + // 更新数据
49 64 MesProWorkOrderBomDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderBomDO.class);
50 65 workOrderBomMapper.updateById(updateObj);
51 66 }
... ... @@ -54,6 +69,7 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
54 69 public void deleteWorkOrderBom(Long id) {
55 70 // 校验存在
56 71 validateWorkOrderBomExists(id);
  72 +
57 73 // 删除
58 74 workOrderBomMapper.deleteById(id);
59 75 }
... ... @@ -84,4 +100,35 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
84 100 workOrderBomMapper.deleteByWorkOrderId(workOrderId);
85 101 }
86 102  
87   -}
  103 + @Override
  104 + public void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated) {
  105 + // 1. 如果是更新场景,先清理旧的 BOM 数据
  106 + if (updated) {
  107 + workOrderBomMapper.deleteByWorkOrderId(workOrderId);
  108 + }
  109 +
  110 + // 2.1 查询产品 BOM
  111 + List<MesMdProductBomDO> productBomList = productBomService.getProductBomListByItemId(reqVO.getProductId());
  112 + if (CollUtil.isEmpty(productBomList)) {
  113 + return;
  114 + }
  115 + // 2.2 批量获取并校验 BOM 物料
  116 + Set<Long> bomItemIds = CollectionUtils.convertSet(productBomList, MesMdProductBomDO::getBomItemId);
  117 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(bomItemIds);
  118 + bomItemIds.forEach(itemId -> {
  119 + if (itemMap.get(itemId) == null) {
  120 + throw exception(MD_ITEM_NOT_EXISTS);
  121 + }
  122 + });
  123 +
  124 + // 3. 构建工单 BOM 列表并批量插入
  125 + List<MesProWorkOrderBomDO> bomList = new ArrayList<>(productBomList.size());
  126 + for (MesMdProductBomDO productBom : productBomList) {
  127 + MesMdItemDO bomItem = itemMap.get(productBom.getBomItemId());
  128 + bomList.add(new MesProWorkOrderBomDO().setWorkOrderId(workOrderId).setItemId(productBom.getBomItemId())
  129 + .setQuantity(reqVO.getQuantity().multiply(productBom.getQuantity())).setUnitMeasureId(bomItem.getUnitMeasureId()));
  130 + }
  131 + workOrderBomMapper.insertBatch(bomList);
  132 + }
  133 +
  134 +}
88 135 \ No newline at end of file
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java
... ... @@ -7,24 +7,19 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 7 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO;
8 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
9 9 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO;
10   -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
11   -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
12   -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
13 10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
14   -import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderBomMapper;
15 11 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper;
16 12 import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum;
17 13 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
18 14 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService;
19 15 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
20   -import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService;
  16 +import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
21 17 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
22 18 import jakarta.annotation.Resource;
23 19 import org.springframework.stereotype.Service;
24 20 import org.springframework.transaction.annotation.Transactional;
25 21 import org.springframework.validation.annotation.Validated;
26 22  
27   -import java.math.BigDecimal;
28 23 import java.time.LocalDateTime;
29 24 import java.util.Collection;
30 25 import java.util.Collections;
... ... @@ -45,21 +40,16 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
45 40 @Resource
46 41 private MesProWorkOrderMapper workOrderMapper;
47 42  
48   - // TODO @AI:不应该直接这么调用,调用对应的 service
49 43 @Resource
50   - private MesProWorkOrderBomMapper workOrderBomMapper;
51   -
  44 + private MesProWorkOrderBomService workOrderBomService;
52 45 @Resource
53 46 private MesMdItemService itemService;
54   -
55   - @Resource
56   - private MesMdProductBomService productBomService;
57   -
58 47 @Resource
59 48 private MesMdItemBatchConfigService itemBatchConfigService;
60   -
61 49 @Resource
62 50 private MesWmBarcodeService barcodeService;
  51 + @Resource
  52 + private MesProTaskService taskService;
63 53  
64 54 @Override
65 55 @Transactional(rollbackFor = Exception.class)
... ... @@ -68,12 +58,12 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
68 58 validateWorkOrderCodeUnique(null, createReqVO.getCode());
69 59 // 1.2 校验产品存在
70 60 itemService.validateItemExists(createReqVO.getProductId());
71   - // 1.3 校验批次配置:如果产品有 clientFlag=true,则 clientId 必填
  61 + // 1.3 校验批次配置
72 62 validateBatchConfig(createReqVO.getProductId(), createReqVO.getClientId());
73 63  
74 64 // 2.1 设置默认值
75 65 if (createReqVO.getParentId() == null) {
76   - createReqVO.setParentId(0L);
  66 + createReqVO.setParentId(MesProWorkOrderDO.PARENT_ID_NULL);
77 67 }
78 68 // 2.2 插入工单
79 69 MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class);
... ... @@ -83,7 +73,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
83 73 workOrderMapper.insert(workOrder);
84 74  
85 75 // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM
86   - generateWorkOrderBom(workOrder.getId(), createReqVO.getProductId(), createReqVO.getQuantity());
  76 + workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false);
87 77  
88 78 // 4. 自动生成条码
89 79 barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKORDER.getValue(),
... ... @@ -101,13 +91,11 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
101 91 // 1.3 校验批次配置
102 92 validateBatchConfig(updateReqVO.getProductId(), updateReqVO.getClientId());
103 93  
104   - // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM
  94 + // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM(updated=true 会先清理旧数据)
105 95 boolean productChanged = ObjUtil.notEqual(oldWorkOrder.getProductId(), updateReqVO.getProductId());
106 96 boolean quantityChanged = oldWorkOrder.getQuantity().compareTo(updateReqVO.getQuantity()) != 0;
107 97 if (productChanged || quantityChanged) {
108   - // 删除旧 BOM 并重新生成
109   - workOrderBomMapper.deleteByWorkOrderId(updateReqVO.getId());
110   - generateWorkOrderBom(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getQuantity());
  98 + workOrderBomService.generateWorkOrderBom(updateReqVO.getId(), updateReqVO, true);
111 99 }
112 100  
113 101 // 3. 更新
... ... @@ -127,7 +115,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
127 115  
128 116 // 2. 删除工单 + BOM
129 117 workOrderMapper.deleteById(id);
130   - workOrderBomMapper.deleteByWorkOrderId(id);
  118 + workOrderBomService.deleteWorkOrderBomByWorkOrderId(id);
131 119 }
132 120  
133 121 @Override
... ... @@ -168,45 +156,52 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
168 156  
169 157 @Override
170 158 public void confirmWorkOrder(Long id) {
171   - // 1. 校验存在
  159 + // 1.1 校验存在
172 160 MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
173   - // 2. 只有草稿状态才能确认
174   - if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) {
  161 + // 1.2 只有草稿状态才能确认
  162 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) {
175 163 throw exception(PRO_WORK_ORDER_NOT_PREPARE);
176 164 }
177   - // 3. 更新状态为已确认
  165 +
  166 + // 2. 更新状态为已确认
178 167 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
179 168 .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus()));
180 169 }
181 170  
182 171 @Override
  172 + @Transactional(rollbackFor = Exception.class)
183 173 public void finishWorkOrder(Long id) {
184 174 // 1. 校验存在 + 只有已确认状态才能完成
185 175 MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
186   - if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
  176 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
187 177 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
188 178 }
189 179  
190   - // 2. 更新状态为已完成
  180 + // 2. 级联完成所有关联任务
  181 + taskService.finishTaskByOrderId(id);
  182 +
  183 + // 3. 更新工单状态为已完成
191 184 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
192 185 .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus())
193 186 .setFinishDate(LocalDateTime.now()));
194   - // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态
195 187 }
196 188  
197 189 @Override
  190 + @Transactional(rollbackFor = Exception.class)
198 191 public void cancelWorkOrder(Long id) {
199 192 // 1. 校验存在 + 只有已确认状态才能取消
200 193 MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
201   - if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
  194 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
202 195 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
203 196 }
204 197  
205   - // 2. 更新状态为已取消
  198 + // 2. 级联取消所有关联任务
  199 + taskService.cancelTaskByOrderId(id);
  200 +
  201 + // 3. 更新工单状态为已取消
206 202 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
207 203 .setStatus(MesProWorkOrderStatusEnum.CANCELED.getStatus())
208 204 .setCancelDate(LocalDateTime.now()));
209   - // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态
210 205 }
211 206  
212 207 // ==================== 校验方法 ====================
... ... @@ -225,6 +220,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
225 220 }
226 221  
227 222 private void validateBatchConfig(Long productId, Long clientId) {
  223 + // 如果产品有 clientFlag=true,则 clientId 必填
228 224 MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(productId);
229 225 if (batchConfig != null && Boolean.TRUE.equals(batchConfig.getClientFlag()) && clientId == null) {
230 226 // 产品要求批次管理中必须填写客户
... ... @@ -237,28 +233,4 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
237 233 return workOrderMapper.selectList();
238 234 }
239 235  
240   - // ==================== BOM 自动生成 ====================
241   -
242   - /**
243   - * 根据产品 BOM 自动生成工单 BOM 行
244   - *
245   - * @param workOrderId 工单编号
246   - * @param productId 产品编号
247   - * @param quantity 工单生产数量
248   - */
249   - private void generateWorkOrderBom(Long workOrderId, Long productId, BigDecimal quantity) {
250   - List<MesMdProductBomDO> productBomList = productBomService.getProductBomListByItemId(productId);
251   - if (CollUtil.isEmpty(productBomList)) {
252   - return;
253   - }
254   - for (MesMdProductBomDO productBom : productBomList) {
255   - MesMdItemDO bomItem = itemService.validateItemExists(productBom.getBomItemId());
256   - workOrderBomMapper.insert(new MesProWorkOrderBomDO()
257   - .setWorkOrderId(workOrderId)
258   - .setItemId(productBom.getBomItemId())
259   - .setQuantity(quantity.multiply(productBom.getQuantity()))
260   - .setUnitMeasureId(bomItem.getUnitMeasureId()));
261   - }
262   - }
263   -
264 236 }
... ...