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 package cn.iocoder.yudao.module.mes.dal.dataobject.pro.task; 1 package cn.iocoder.yudao.module.mes.dal.dataobject.pro.task;
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;
4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; 5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; 6 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
6 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; 7 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO; 8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
  11 +import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
10 import com.baomidou.mybatisplus.annotation.KeySequence; 12 import com.baomidou.mybatisplus.annotation.KeySequence;
11 import com.baomidou.mybatisplus.annotation.TableId; 13 import com.baomidou.mybatisplus.annotation.TableId;
12 import com.baomidou.mybatisplus.annotation.TableName; 14 import com.baomidou.mybatisplus.annotation.TableName;
@@ -79,6 +81,7 @@ public class MesProTaskDO extends BaseDO { @@ -79,6 +81,7 @@ public class MesProTaskDO extends BaseDO {
79 * 关联 {@link MesMdUnitMeasureDO#getId()} 81 * 关联 {@link MesMdUnitMeasureDO#getId()}
80 */ 82 */
81 private Long unitMeasureId; 83 private Long unitMeasureId;
  84 +
82 /** 85 /**
83 * 排产数量 86 * 排产数量
84 */ 87 */
@@ -99,8 +102,11 @@ public class MesProTaskDO extends BaseDO { @@ -99,8 +102,11 @@ public class MesProTaskDO extends BaseDO {
99 * 调整数量 102 * 调整数量
100 */ 103 */
101 private BigDecimal changedQuantity; 104 private BigDecimal changedQuantity;
  105 +
102 /** 106 /**
103 * 客户编号 107 * 客户编号
  108 + *
  109 + * 关联 {@link MesMdClientDO#getId()}
104 */ 110 */
105 private Long clientId; 111 private Long clientId;
106 /** 112 /**
@@ -127,8 +133,11 @@ public class MesProTaskDO extends BaseDO { @@ -127,8 +133,11 @@ public class MesProTaskDO extends BaseDO {
127 * 取消日期 133 * 取消日期
128 */ 134 */
129 private LocalDateTime cancelDate; 135 private LocalDateTime cancelDate;
  136 +
130 /** 137 /**
131 * 任务状态 138 * 任务状态
  139 + *
  140 + * 枚举 {@link MesProTaskStatusEnum}
132 */ 141 */
133 private Integer status; 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,6 +32,11 @@ import java.time.LocalDateTime;
32 public class MesProWorkOrderDO extends BaseDO { 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 @TableId 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,4 +90,18 @@ public interface MesProTaskService {
90 return convertMap(getTaskList(ids), MesProTaskDO::getId); 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 package cn.iocoder.yudao.module.mes.service.pro.task; 1 package cn.iocoder.yudao.module.mes.service.pro.task;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO;
6 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO; 7 import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveReqVO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; 8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
8 import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper; 9 import cn.iocoder.yudao.module.mes.dal.mysql.pro.task.MesProTaskMapper;
  10 +import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
9 import jakarta.annotation.Resource; 11 import jakarta.annotation.Resource;
10 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
12 14
  15 +import java.time.LocalDateTime;
13 import java.util.Collection; 16 import java.util.Collection;
14 import java.util.List; 17 import java.util.List;
15 18
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_TASK_NOT_EXISTS; 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,7 +79,38 @@ public class MesProTaskServiceImpl implements MesProTaskService {
75 79
76 @Override 80 @Override
77 public List<MesProTaskDO> getTaskList(Collection<Long> ids) { 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 package cn.iocoder.yudao.module.mes.service.pro.workorder; 1 package cn.iocoder.yudao.module.mes.service.pro.workorder;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
4 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; 5 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO;
5 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO;
6 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; 7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
@@ -68,4 +69,15 @@ public interface MesProWorkOrderBomService { @@ -68,4 +69,15 @@ public interface MesProWorkOrderBomService {
68 */ 69 */
69 void deleteWorkOrderBomByWorkOrderId(Long workOrderId); 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 package cn.iocoder.yudao.module.mes.service.pro.workorder; 1 package cn.iocoder.yudao.module.mes.service.pro.workorder;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 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.pro.workorder.vo.MesProWorkOrderSaveReqVO;
5 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO;
6 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; 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 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; 12 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
8 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderBomMapper; 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 import jakarta.annotation.Resource; 16 import jakarta.annotation.Resource;
10 import org.springframework.context.annotation.Lazy; 17 import org.springframework.context.annotation.Lazy;
11 import org.springframework.stereotype.Service; 18 import org.springframework.stereotype.Service;
12 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
13 20
14 -import java.util.List; 21 +import java.util.*;
15 22
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORK_ORDER_BOM_NOT_EXISTS; 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,11 +39,17 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
31 @Resource 39 @Resource
32 @Lazy // 延迟加载,避免循环依赖 40 @Lazy // 延迟加载,避免循环依赖
33 private MesProWorkOrderService workOrderService; 41 private MesProWorkOrderService workOrderService;
  42 + @Resource
  43 + private MesMdItemService itemService;
  44 + @Resource
  45 + private MesMdProductBomService productBomService;
34 46
35 @Override 47 @Override
36 public Long createWorkOrderBom(MesProWorkOrderBomSaveReqVO createReqVO) { 48 public Long createWorkOrderBom(MesProWorkOrderBomSaveReqVO createReqVO) {
37 // 校验工单存在 49 // 校验工单存在
38 workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); 50 workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
  51 +
  52 + // 插入数据
39 MesProWorkOrderBomDO workOrderBom = BeanUtils.toBean(createReqVO, MesProWorkOrderBomDO.class); 53 MesProWorkOrderBomDO workOrderBom = BeanUtils.toBean(createReqVO, MesProWorkOrderBomDO.class);
40 workOrderBomMapper.insert(workOrderBom); 54 workOrderBomMapper.insert(workOrderBom);
41 return workOrderBom.getId(); 55 return workOrderBom.getId();
@@ -45,7 +59,8 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService @@ -45,7 +59,8 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
45 public void updateWorkOrderBom(MesProWorkOrderBomSaveReqVO updateReqVO) { 59 public void updateWorkOrderBom(MesProWorkOrderBomSaveReqVO updateReqVO) {
46 // 校验存在 60 // 校验存在
47 validateWorkOrderBomExists(updateReqVO.getId()); 61 validateWorkOrderBomExists(updateReqVO.getId());
48 - // 更新 62 +
  63 + // 更新数据
49 MesProWorkOrderBomDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderBomDO.class); 64 MesProWorkOrderBomDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderBomDO.class);
50 workOrderBomMapper.updateById(updateObj); 65 workOrderBomMapper.updateById(updateObj);
51 } 66 }
@@ -54,6 +69,7 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService @@ -54,6 +69,7 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
54 public void deleteWorkOrderBom(Long id) { 69 public void deleteWorkOrderBom(Long id) {
55 // 校验存在 70 // 校验存在
56 validateWorkOrderBomExists(id); 71 validateWorkOrderBomExists(id);
  72 +
57 // 删除 73 // 删除
58 workOrderBomMapper.deleteById(id); 74 workOrderBomMapper.deleteById(id);
59 } 75 }
@@ -84,4 +100,35 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService @@ -84,4 +100,35 @@ public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService
84 workOrderBomMapper.deleteByWorkOrderId(workOrderId); 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 \ No newline at end of file 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,24 +7,19 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; 7 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO;
8 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO; 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 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; 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 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper;
16 import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; 12 import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum;
17 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; 13 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
18 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; 14 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService;
19 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; 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 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; 17 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
22 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
23 import org.springframework.stereotype.Service; 19 import org.springframework.stereotype.Service;
24 import org.springframework.transaction.annotation.Transactional; 20 import org.springframework.transaction.annotation.Transactional;
25 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
26 22
27 -import java.math.BigDecimal;  
28 import java.time.LocalDateTime; 23 import java.time.LocalDateTime;
29 import java.util.Collection; 24 import java.util.Collection;
30 import java.util.Collections; 25 import java.util.Collections;
@@ -45,21 +40,16 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -45,21 +40,16 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
45 @Resource 40 @Resource
46 private MesProWorkOrderMapper workOrderMapper; 41 private MesProWorkOrderMapper workOrderMapper;
47 42
48 - // TODO @AI:不应该直接这么调用,调用对应的 service  
49 @Resource 43 @Resource
50 - private MesProWorkOrderBomMapper workOrderBomMapper;  
51 - 44 + private MesProWorkOrderBomService workOrderBomService;
52 @Resource 45 @Resource
53 private MesMdItemService itemService; 46 private MesMdItemService itemService;
54 -  
55 - @Resource  
56 - private MesMdProductBomService productBomService;  
57 -  
58 @Resource 47 @Resource
59 private MesMdItemBatchConfigService itemBatchConfigService; 48 private MesMdItemBatchConfigService itemBatchConfigService;
60 -  
61 @Resource 49 @Resource
62 private MesWmBarcodeService barcodeService; 50 private MesWmBarcodeService barcodeService;
  51 + @Resource
  52 + private MesProTaskService taskService;
63 53
64 @Override 54 @Override
65 @Transactional(rollbackFor = Exception.class) 55 @Transactional(rollbackFor = Exception.class)
@@ -68,12 +58,12 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -68,12 +58,12 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
68 validateWorkOrderCodeUnique(null, createReqVO.getCode()); 58 validateWorkOrderCodeUnique(null, createReqVO.getCode());
69 // 1.2 校验产品存在 59 // 1.2 校验产品存在
70 itemService.validateItemExists(createReqVO.getProductId()); 60 itemService.validateItemExists(createReqVO.getProductId());
71 - // 1.3 校验批次配置:如果产品有 clientFlag=true,则 clientId 必填 61 + // 1.3 校验批次配置
72 validateBatchConfig(createReqVO.getProductId(), createReqVO.getClientId()); 62 validateBatchConfig(createReqVO.getProductId(), createReqVO.getClientId());
73 63
74 // 2.1 设置默认值 64 // 2.1 设置默认值
75 if (createReqVO.getParentId() == null) { 65 if (createReqVO.getParentId() == null) {
76 - createReqVO.setParentId(0L); 66 + createReqVO.setParentId(MesProWorkOrderDO.PARENT_ID_NULL);
77 } 67 }
78 // 2.2 插入工单 68 // 2.2 插入工单
79 MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class); 69 MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class);
@@ -83,7 +73,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -83,7 +73,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
83 workOrderMapper.insert(workOrder); 73 workOrderMapper.insert(workOrder);
84 74
85 // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM 75 // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM
86 - generateWorkOrderBom(workOrder.getId(), createReqVO.getProductId(), createReqVO.getQuantity()); 76 + workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false);
87 77
88 // 4. 自动生成条码 78 // 4. 自动生成条码
89 barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKORDER.getValue(), 79 barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKORDER.getValue(),
@@ -101,13 +91,11 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -101,13 +91,11 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
101 // 1.3 校验批次配置 91 // 1.3 校验批次配置
102 validateBatchConfig(updateReqVO.getProductId(), updateReqVO.getClientId()); 92 validateBatchConfig(updateReqVO.getProductId(), updateReqVO.getClientId());
103 93
104 - // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM 94 + // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM(updated=true 会先清理旧数据)
105 boolean productChanged = ObjUtil.notEqual(oldWorkOrder.getProductId(), updateReqVO.getProductId()); 95 boolean productChanged = ObjUtil.notEqual(oldWorkOrder.getProductId(), updateReqVO.getProductId());
106 boolean quantityChanged = oldWorkOrder.getQuantity().compareTo(updateReqVO.getQuantity()) != 0; 96 boolean quantityChanged = oldWorkOrder.getQuantity().compareTo(updateReqVO.getQuantity()) != 0;
107 if (productChanged || quantityChanged) { 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 // 3. 更新 101 // 3. 更新
@@ -127,7 +115,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -127,7 +115,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
127 115
128 // 2. 删除工单 + BOM 116 // 2. 删除工单 + BOM
129 workOrderMapper.deleteById(id); 117 workOrderMapper.deleteById(id);
130 - workOrderBomMapper.deleteByWorkOrderId(id); 118 + workOrderBomService.deleteWorkOrderBomByWorkOrderId(id);
131 } 119 }
132 120
133 @Override 121 @Override
@@ -168,45 +156,52 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -168,45 +156,52 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
168 156
169 @Override 157 @Override
170 public void confirmWorkOrder(Long id) { 158 public void confirmWorkOrder(Long id) {
171 - // 1. 校验存在 159 + // 1.1 校验存在
172 MesProWorkOrderDO workOrder = validateWorkOrderExists(id); 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 throw exception(PRO_WORK_ORDER_NOT_PREPARE); 163 throw exception(PRO_WORK_ORDER_NOT_PREPARE);
176 } 164 }
177 - // 3. 更新状态为已确认 165 +
  166 + // 2. 更新状态为已确认
178 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) 167 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
179 .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus())); 168 .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus()));
180 } 169 }
181 170
182 @Override 171 @Override
  172 + @Transactional(rollbackFor = Exception.class)
183 public void finishWorkOrder(Long id) { 173 public void finishWorkOrder(Long id) {
184 // 1. 校验存在 + 只有已确认状态才能完成 174 // 1. 校验存在 + 只有已确认状态才能完成
185 MesProWorkOrderDO workOrder = validateWorkOrderExists(id); 175 MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
186 - if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { 176 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
187 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); 177 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
188 } 178 }
189 179
190 - // 2. 更新状态为已完成 180 + // 2. 级联完成所有关联任务
  181 + taskService.finishTaskByOrderId(id);
  182 +
  183 + // 3. 更新工单状态为已完成
191 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) 184 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
192 .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus()) 185 .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus())
193 .setFinishDate(LocalDateTime.now())); 186 .setFinishDate(LocalDateTime.now()));
194 - // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态  
195 } 187 }
196 188
197 @Override 189 @Override
  190 + @Transactional(rollbackFor = Exception.class)
198 public void cancelWorkOrder(Long id) { 191 public void cancelWorkOrder(Long id) {
199 // 1. 校验存在 + 只有已确认状态才能取消 192 // 1. 校验存在 + 只有已确认状态才能取消
200 MesProWorkOrderDO workOrder = validateWorkOrderExists(id); 193 MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
201 - if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { 194 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) {
202 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); 195 throw exception(PRO_WORK_ORDER_NOT_CONFIRMED);
203 } 196 }
204 197
205 - // 2. 更新状态为已取消 198 + // 2. 级联取消所有关联任务
  199 + taskService.cancelTaskByOrderId(id);
  200 +
  201 + // 3. 更新工单状态为已取消
206 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) 202 workOrderMapper.updateById(new MesProWorkOrderDO().setId(id)
207 .setStatus(MesProWorkOrderStatusEnum.CANCELED.getStatus()) 203 .setStatus(MesProWorkOrderStatusEnum.CANCELED.getStatus())
208 .setCancelDate(LocalDateTime.now())); 204 .setCancelDate(LocalDateTime.now()));
209 - // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态  
210 } 205 }
211 206
212 // ==================== 校验方法 ==================== 207 // ==================== 校验方法 ====================
@@ -225,6 +220,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -225,6 +220,7 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
225 } 220 }
226 221
227 private void validateBatchConfig(Long productId, Long clientId) { 222 private void validateBatchConfig(Long productId, Long clientId) {
  223 + // 如果产品有 clientFlag=true,则 clientId 必填
228 MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(productId); 224 MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(productId);
229 if (batchConfig != null && Boolean.TRUE.equals(batchConfig.getClientFlag()) && clientId == null) { 225 if (batchConfig != null && Boolean.TRUE.equals(batchConfig.getClientFlag()) && clientId == null) {
230 // 产品要求批次管理中必须填写客户 226 // 产品要求批次管理中必须填写客户
@@ -237,28 +233,4 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { @@ -237,28 +233,4 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
237 return workOrderMapper.selectList(); 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 }