Commit dfa61b7d7e9d8dbb3c2bc3aa68d31d1ff29b0c24

Authored by YunaiV
1 parent 92a5a2bd

✨ feat(wm): 添加物料消耗记录及相关服务实现

Showing 15 changed files with 449 additions and 40 deletions
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/api/config/ConfigApi.java
@@ -7,6 +7,7 @@ package cn.iocoder.yudao.module.infra.api.config; @@ -7,6 +7,7 @@ package cn.iocoder.yudao.module.infra.api.config;
7 */ 7 */
8 public interface ConfigApi { 8 public interface ConfigApi {
9 9
  10 +
10 /** 11 /**
11 * 根据参数键查询参数值 12 * 根据参数键查询参数值
12 * 13 *
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApi.java
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
11 */ 11 */
12 public interface WebSocketSenderApi { 12 public interface WebSocketSenderApi {
13 13
  14 +
14 /** 15 /**
15 * 发送消息给指定用户 16 * 发送消息给指定用户
16 * 17 *
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java
@@ -48,6 +48,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPOR @@ -48,6 +48,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPOR
48 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 48 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
50 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; 50 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  51 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
51 52
52 @Tag(name = "管理后台 - MES 生产报工") 53 @Tag(name = "管理后台 - MES 生产报工")
53 @RestController 54 @RestController
@@ -156,7 +157,7 @@ public class MesProFeedbackController { @@ -156,7 +157,7 @@ public class MesProFeedbackController {
156 @Parameter(name = "id", description = "编号", required = true) 157 @Parameter(name = "id", description = "编号", required = true)
157 @PreAuthorize("@ss.hasPermission('mes:pro-feedback:approve')") 158 @PreAuthorize("@ss.hasPermission('mes:pro-feedback:approve')")
158 public CommonResult<Boolean> approveFeedback(@RequestParam("id") Long id) { 159 public CommonResult<Boolean> approveFeedback(@RequestParam("id") Long id) {
159 - return success(feedbackService.approveFeedback(id)); 160 + return success(feedbackService.approveFeedback(id, getLoginUserId()));
160 } 161 }
161 162
162 // ==================== 拼接 VO ==================== 163 // ==================== 拼接 VO ====================
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemconsume/MesWmItemConsumeDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
  9 +import com.baomidou.mybatisplus.annotation.KeySequence;
  10 +import com.baomidou.mybatisplus.annotation.TableId;
  11 +import com.baomidou.mybatisplus.annotation.TableName;
  12 +import lombok.*;
  13 +
  14 +import java.time.LocalDateTime;
  15 +
  16 +/**
  17 + * MES 物料消耗记录 DO
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@TableName("mes_wm_item_consume")
  22 +@KeySequence("mes_wm_item_consume_seq")
  23 +@Data
  24 +@EqualsAndHashCode(callSuper = true)
  25 +@ToString(callSuper = true)
  26 +@Builder
  27 +@NoArgsConstructor
  28 +@AllArgsConstructor
  29 +public class MesWmItemConsumeDO extends BaseDO {
  30 +
  31 + /**
  32 + * 编号
  33 + */
  34 + @TableId
  35 + private Long id;
  36 + /**
  37 + * 生产工单编号
  38 + *
  39 + * 关联 {@link MesProWorkOrderDO#getId()}
  40 + */
  41 + private Long workOrderId;
  42 + /**
  43 + * 生产任务编号
  44 + *
  45 + * 关联 {@link MesProTaskDO#getId()}
  46 + */
  47 + private Long taskId;
  48 + /**
  49 + * 工作站编号
  50 + *
  51 + * 关联 {@link MesMdWorkstationDO#getId()}
  52 + */
  53 + private Long workstationId;
  54 + /**
  55 + * 工序编号
  56 + *
  57 + * 关联 {@link MesProProcessDO#getId()}
  58 + */
  59 + private Long processId;
  60 + /**
  61 + * 报工记录编号
  62 + *
  63 + * 关联 {@link MesProFeedbackDO#getId()}
  64 + */
  65 + private Long feedbackId;
  66 + /**
  67 + * 消耗日期
  68 + */
  69 + private LocalDateTime consumeDate;
  70 + // DONE @AI:搞个独立的枚举类;
  71 + /**
  72 + * 状态
  73 + *
  74 + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmItemConsumeStatusEnum}
  75 + */
  76 + private Integer status;
  77 + /**
  78 + * 备注
  79 + */
  80 + private String remark;
  81 +
  82 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemconsume/MesWmItemConsumeLineDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import lombok.*;
  9 +
  10 +import java.math.BigDecimal;
  11 +
  12 +/**
  13 + * MES 物料消耗记录行 DO
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@TableName("mes_wm_item_consume_line")
  18 +@KeySequence("mes_wm_item_consume_line_seq")
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +@Builder
  23 +@NoArgsConstructor
  24 +@AllArgsConstructor
  25 +public class MesWmItemConsumeLineDO extends BaseDO {
  26 +
  27 + /**
  28 + * 编号
  29 + */
  30 + @TableId
  31 + private Long id;
  32 + /**
  33 + * 消耗记录编号
  34 + *
  35 + * 关联 {@link MesWmItemConsumeDO#getId()}
  36 + */
  37 + private Long consumeId;
  38 + /**
  39 + * 物料编号
  40 + *
  41 + * 关联 {@link MesMdItemDO#getId()}
  42 + */
  43 + private Long itemId;
  44 + /**
  45 + * 消耗数量
  46 + */
  47 + private BigDecimal quantity;
  48 + /**
  49 + * 批次编号
  50 + *
  51 + * 关联 {@link cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO#getId()}
  52 + */
  53 + private Long batchId;
  54 + /**
  55 + * 批次号
  56 + *
  57 + * 冗余 {@link cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO#getCode()}
  58 + */
  59 + private String batchCode;
  60 + /**
  61 + * 备注
  62 + */
  63 + private String remark;
  64 +
  65 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/itemconsume/MesWmItemConsumeLineMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * MES 物料消耗记录行 Mapper
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@Mapper
  15 +public interface MesWmItemConsumeLineMapper extends BaseMapperX<MesWmItemConsumeLineDO> {
  16 +
  17 + default List<MesWmItemConsumeLineDO> selectListByConsumeId(Long consumeId) {
  18 + return selectList(MesWmItemConsumeLineDO::getConsumeId, consumeId);
  19 + }
  20 +
  21 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/itemconsume/MesWmItemConsumeMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +/**
  8 + * MES 物料消耗记录 Mapper
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Mapper
  13 +public interface MesWmItemConsumeMapper extends BaseMapperX<MesWmItemConsumeDO> {
  14 +
  15 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -250,6 +250,7 @@ public interface ErrorCodeConstants { @@ -250,6 +250,7 @@ public interface ErrorCodeConstants {
250 ErrorCode PRO_FEEDBACK_TASK_OR_ORDER_FINISHED = new ErrorCode(1_040_506_009, "当前生产任务或工单已完成,不能继续报工"); 250 ErrorCode PRO_FEEDBACK_TASK_OR_ORDER_FINISHED = new ErrorCode(1_040_506_009, "当前生产任务或工单已完成,不能继续报工");
251 ErrorCode PRO_FEEDBACK_QUANTITY_MUST_POSITIVE = new ErrorCode(1_040_506_010, "报工数量必须大于 0"); 251 ErrorCode PRO_FEEDBACK_QUANTITY_MUST_POSITIVE = new ErrorCode(1_040_506_010, "报工数量必须大于 0");
252 ErrorCode PRO_FEEDBACK_QUALIFIED_UNQUALIFIED_REQUIRED = new ErrorCode(1_040_506_011, "请输入合格品和不良品数量,且合计须大于 0"); 252 ErrorCode PRO_FEEDBACK_QUALIFIED_UNQUALIFIED_REQUIRED = new ErrorCode(1_040_506_011, "请输入合格品和不良品数量,且合计须大于 0");
  253 + ErrorCode PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS = new ErrorCode(1_040_506_012, "当前报工单未完成检验(待检数量:{}),无法执行报工");
253 254
254 // ========== MES 生产管理-生产流转卡(1-040-507-000) ========== 255 // ========== MES 生产管理-生产流转卡(1-040-507-000) ==========
255 ErrorCode PRO_CARD_NOT_EXISTS = new ErrorCode(1_040_507_000, "生产流转卡不存在"); 256 ErrorCode PRO_CARD_NOT_EXISTS = new ErrorCode(1_040_507_000, "生产流转卡不存在");
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmItemConsumeStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.wm;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Getter;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * MES 物料消耗记录状态枚举
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Getter
  16 +@AllArgsConstructor
  17 +public enum MesWmItemConsumeStatusEnum implements ArrayValuable<Integer> {
  18 +
  19 + /**
  20 + * 草稿
  21 + */
  22 + PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
  23 + /**
  24 + * 已完成
  25 + */
  26 + FINISHED(MesOrderStatusConstants.FINISHED, "已完成");
  27 +
  28 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmItemConsumeStatusEnum::getStatus).toArray(Integer[]::new);
  29 +
  30 + /**
  31 + * 状态值
  32 + */
  33 + private final Integer status;
  34 + /**
  35 + * 状态名
  36 + */
  37 + private final String name;
  38 +
  39 + @Override
  40 + public Integer[] array() {
  41 + return ARRAYS;
  42 + }
  43 +
  44 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
@@ -68,10 +68,11 @@ public interface MesProFeedbackService { @@ -68,10 +68,11 @@ public interface MesProFeedbackService {
68 /** 68 /**
69 * 审批报工(审批中 -> 已完成 或 待检验) 69 * 审批报工(审批中 -> 已完成 或 待检验)
70 * 70 *
71 - * @param id 编号 71 + * @param id 编号
  72 + * @param userId 当前操作用户编号
72 * @return true=已完成, false=待检验 73 * @return true=已完成, false=待检验
73 */ 74 */
74 - boolean approveFeedback(Long id); 75 + boolean approveFeedback(Long id, Long userId);
75 76
76 } 77 }
77 78
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
1 package cn.iocoder.yudao.module.mes.service.pro.feedback; 1 package cn.iocoder.yudao.module.mes.service.pro.feedback;
2 2
3 -import cn.hutool.core.util.BooleanUtil;  
4 import cn.hutool.core.util.ObjUtil; 3 import cn.hutool.core.util.ObjUtil;
5 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -9,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedba @@ -9,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedba
9 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO;
10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
11 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO;
12 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; 12 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
13 import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper; 13 import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
14 import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum; 14 import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationServic @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationServic
16 import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService; 16 import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
17 import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; 17 import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
18 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; 18 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
  19 +import cn.iocoder.yudao.module.mes.service.wm.itemconsume.MesWmItemConsumeService;
19 import jakarta.annotation.Resource; 20 import jakarta.annotation.Resource;
20 import org.springframework.context.annotation.Lazy; 21 import org.springframework.context.annotation.Lazy;
21 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
@@ -54,6 +55,9 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { @@ -54,6 +55,9 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
54 @Lazy // 避免循环依赖 55 @Lazy // 避免循环依赖
55 private MesProTaskService taskService; 56 private MesProTaskService taskService;
56 57
  58 + @Resource
  59 + private MesWmItemConsumeService itemConsumeService;
  60 +
57 @Override 61 @Override
58 public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) { 62 public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) {
59 // 1. 校验 63 // 1. 校验
@@ -121,43 +125,55 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { @@ -121,43 +125,55 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
121 .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus())); 125 .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus()));
122 } 126 }
123 127
124 - // DONE @AI:改成 boolean:true 表示已完成;false 表示待检验,前端需提示"报工成功,请等待质量检验完成!"  
125 @Override 128 @Override
126 @Transactional(rollbackFor = Exception.class) 129 @Transactional(rollbackFor = Exception.class)
127 - public boolean approveFeedback(Long id) {  
128 - // TODO @AI: 逻辑需要继续跟进;  
129 - // 1.1 校验存在 + 审批中状态 130 + public boolean approveFeedback(Long id, Long userId) {
  131 + // 1.1.a 校验存在 + 审批中状态
130 MesProFeedbackDO feedback = validateFeedbackStatusApproving(id); 132 MesProFeedbackDO feedback = validateFeedbackStatusApproving(id);
131 - // 1.2 校验报工数量 > 0 133 + // 1.1.b 校验报工数量 > 0
132 if (feedback.getFeedbackQuantity() == null 134 if (feedback.getFeedbackQuantity() == null
133 || feedback.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) { 135 || feedback.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) {
134 throw exception(PRO_FEEDBACK_QUANTITY_MUST_POSITIVE); 136 throw exception(PRO_FEEDBACK_QUANTITY_MUST_POSITIVE);
135 } 137 }
136 - // 1.3 校验任务未完成 138 + // 1.2.a 校验任务未完成
137 taskService.validateTaskNotFinished(feedback.getTaskId()); 139 taskService.validateTaskNotFinished(feedback.getTaskId());
138 - // 1.4 仍有待检数量时不能执行 140 + // 1.2.b 仍有待检数量时不能执行
139 if (feedback.getUncheckQuantity() != null 141 if (feedback.getUncheckQuantity() != null
140 && feedback.getUncheckQuantity().compareTo(BigDecimal.ZERO) > 0) { 142 && feedback.getUncheckQuantity().compareTo(BigDecimal.ZERO) > 0) {
141 - throw exception(PRO_FEEDBACK_NOT_APPROVING); // TODO @芋艿:新增一个专用错误码,例如 PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS 143 + throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity());
142 } 144 }
143 145
144 - // 2.1 查询工序的 checkFlag,决定目标状态  
145 - boolean checkFlag = getCheckFlag(feedback.getRouteId(), feedback.getProcessId());  
146 - Integer targetStatus = checkFlag  
147 - ? MesProFeedbackStatusEnum.UNCHECK.getStatus() // 需要检验 → 待检验  
148 - : MesProFeedbackStatusEnum.FINISHED.getStatus(); // 无需检验 → 已完成  
149 - // 2.2 更新状态 + 审核人  
150 - feedbackMapper.updateById(new MesProFeedbackDO().setId(id)  
151 - .setStatus(targetStatus)  
152 - .setApproveUserId(getLoginUserId()));  
153 -  
154 - // 3. 如果不需要检验(直接完成),执行后续操作  
155 - if (BooleanUtil.isFalse(checkFlag)) {  
156 - // TODO @芋艿:WM 物料消耗(WmItemConsumeService)未迁移,此处需补充物料消耗逻辑  
157 - // TODO @芋艿:WM 产品产出(WmProductProduceService)未迁移,此处需补充产品产出逻辑  
158 - // TODO @芋艿:updateProTaskAndWorkorder 待 pro_task 服务迁移后补充级联更新任务/工单的已生产数量 146 + // 2. 物料消耗:根据工序 BOM 生成消耗记录
  147 + MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback);
  148 + if (itemConsume != null) {
  149 + itemConsumeService.finishItemConsume(itemConsume.getId());
  150 + }
  151 +
  152 + // 3. 查询工序的 keyFlag + checkFlag
  153 + MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId(
  154 + feedback.getRouteId(), feedback.getProcessId());
  155 + boolean keyFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getKeyFlag());
  156 + boolean checkFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getCheckFlag());
  157 +
  158 + // 4. 情况一:关键工序 + 需要检验 → 待检验状态(等质检完成后入库)
  159 + if (keyFlag && checkFlag) {
  160 + feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
  161 + .setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus())
  162 + .setApproveUserId(userId));
  163 + // TODO @芋艿:WM 产品产出(WmProductProduceService)待补充 generateProductProduce(质量状态=待检验)
  164 + return false;
  165 + }
  166 +
  167 + // 4.1 情况二:关键工序 + 无需检验 → 直接完成
  168 + if (keyFlag) {
  169 + // TODO @芋艿:WM 产品产出(WmProductProduceService)待补充 generateProductProduce + executeProductProduce
  170 + // TODO @芋艿:updateProTaskAndWorkorder 待补充级联更新任务/工单的已生产数量
159 } 171 }
160 - return BooleanUtil.isFalse(checkFlag); // true=已完成, false=待检验 172 + // 4.2 更新状态为已完成 + 审核人
  173 + feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
  174 + .setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus())
  175 + .setApproveUserId(userId));
  176 + return true; // 已完成
161 } 177 }
162 178
163 // ==================== 校验方法 ==================== 179 // ==================== 校验方法 ====================
@@ -226,16 +242,4 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { @@ -226,16 +242,4 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
226 return taskService.validateTaskNotFinished(reqVO.getTaskId()); 242 return taskService.validateTaskNotFinished(reqVO.getTaskId());
227 } 243 }
228 244
229 - /**  
230 - * 获取指定工艺路线中指定工序的 checkFlag  
231 - *  
232 - * @param routeId 工艺路线编号  
233 - * @param processId 工序编号  
234 - * @return 是否需要检验  
235 - */  
236 - private boolean getCheckFlag(Long routeId, Long processId) {  
237 - MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId(routeId, processId);  
238 - return routeProcess != null && Boolean.TRUE.equals(routeProcess.getCheckFlag());  
239 - }  
240 -  
241 } 245 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeLineService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * MES 物料消耗记录行 Service 接口
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public interface MesWmItemConsumeLineService {
  13 +
  14 + /**
  15 + * 批量创建消耗行
  16 + *
  17 + * @param lines 消耗行列表
  18 + */
  19 + void createItemConsumeLineBatch(List<MesWmItemConsumeLineDO> lines);
  20 +
  21 + /**
  22 + * 根据消耗记录编号查询消耗行
  23 + *
  24 + * @param consumeId 消耗记录编号
  25 + * @return 消耗行列表
  26 + */
  27 + List<MesWmItemConsumeLineDO> getItemConsumeLineListByConsumeId(Long consumeId);
  28 +
  29 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeLineServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO;
  4 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume.MesWmItemConsumeLineMapper;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 物料消耗记录行 Service 实现类
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Service
  17 +@Validated
  18 +public class MesWmItemConsumeLineServiceImpl implements MesWmItemConsumeLineService {
  19 +
  20 + @Resource
  21 + private MesWmItemConsumeLineMapper itemConsumeLineMapper;
  22 +
  23 + @Override
  24 + public void createItemConsumeLineBatch(List<MesWmItemConsumeLineDO> lines) {
  25 + itemConsumeLineMapper.insertBatch(lines);
  26 + }
  27 +
  28 + @Override
  29 + public List<MesWmItemConsumeLineDO> getItemConsumeLineListByConsumeId(Long consumeId) {
  30 + return itemConsumeLineMapper.selectListByConsumeId(consumeId);
  31 + }
  32 +
  33 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.itemconsume;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO;
  5 +
  6 +/**
  7 + * MES 物料消耗记录 Service 接口
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +public interface MesWmItemConsumeService {
  12 +
  13 + /**
  14 + * 根据报工单生成物料消耗记录
  15 + *
  16 + * 1. 查询当前工序的 BOM 物料配置
  17 + * 2. 生成消耗单头 + 行(消耗数量 = BOM 用料比例 × 报工数量)
  18 + *
  19 + * @param feedback 报工记录
  20 + * @return 生成的消耗记录,无 BOM 时返回 null
  21 + */
  22 + MesWmItemConsumeDO generateItemConsume(MesProFeedbackDO feedback);
  23 +
  24 + /**
  25 + * 完成物料消耗(库存扣减)
  26 + *
  27 + * 遍历消耗行,扣减线边库库存,更新消耗单状态为已完成
  28 + *
  29 + * @param consumeId 消耗记录编号
  30 + */
  31 + void finishItemConsume(Long consumeId);
  32 +
  33 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.itemconsume;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeLineDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemconsume.MesWmItemConsumeMapper;
  9 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmItemConsumeStatusEnum;
  10 +import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductBomService;
  11 +import jakarta.annotation.Resource;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.validation.annotation.Validated;
  14 +
  15 +import java.time.LocalDateTime;
  16 +import java.util.List;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  19 +
  20 +/**
  21 + * MES 物料消耗记录 Service 实现类
  22 + *
  23 + * 参考 KTG {@code WmItemConsumeServiceImpl#generateItemConsume}
  24 + *
  25 + * @author 芋道源码
  26 + */
  27 +@Service
  28 +@Validated
  29 +public class MesWmItemConsumeServiceImpl implements MesWmItemConsumeService {
  30 +
  31 + @Resource
  32 + private MesWmItemConsumeMapper itemConsumeMapper;
  33 + @Resource
  34 + private MesWmItemConsumeLineService itemConsumeLineService;
  35 + @Resource
  36 + private MesProRouteProductBomService routeProductBomService;
  37 +
  38 + // TODO @芋艿:待 MaterialStockService 补充 decreaseStock 后,注入并调用
  39 + // @Resource
  40 + // private MesWmMaterialStockService materialStockService;
  41 +
  42 + @Override
  43 + public MesWmItemConsumeDO generateItemConsume(MesProFeedbackDO feedback) {
  44 + // 1. 查询当前工序的 BOM 物料配置
  45 + List<MesProRouteProductBomDO> boms = routeProductBomService.getRouteProductBomList(
  46 + feedback.getRouteId(), feedback.getProcessId(), feedback.getItemId());
  47 + if (CollUtil.isEmpty(boms)) {
  48 + return null;
  49 + }
  50 +
  51 + // 2.1 生成消耗单头
  52 + MesWmItemConsumeDO consume = MesWmItemConsumeDO.builder()
  53 + .workOrderId(feedback.getWorkOrderId()).taskId(feedback.getTaskId())
  54 + .workstationId(feedback.getWorkstationId()).processId(feedback.getProcessId())
  55 + .feedbackId(feedback.getId()).consumeDate(LocalDateTime.now())
  56 + .status(MesWmItemConsumeStatusEnum.PREPARE.getStatus()).build();
  57 + itemConsumeMapper.insert(consume);
  58 + // 2.2 批量生成消耗行(消耗数量 = BOM 用料比例 × 报工数量)
  59 + List<MesWmItemConsumeLineDO> lines = convertList(boms, bom -> MesWmItemConsumeLineDO.builder()
  60 + .consumeId(consume.getId()).itemId(bom.getItemId())
  61 + .quantity(bom.getQuantity().multiply(feedback.getFeedbackQuantity())).build());
  62 + itemConsumeLineService.createItemConsumeLineBatch(lines);
  63 + return consume;
  64 + }
  65 +
  66 + @Override
  67 + public void finishItemConsume(Long consumeId) {
  68 + // TODO @芋艿:待 MaterialStockService 补充 decreaseStock 后实现库存扣减
  69 + // List<MesWmItemConsumeLineDO> lines = itemConsumeLineService.getItemConsumeLineListByConsumeId(consumeId);
  70 + // for (MesWmItemConsumeLineDO line : lines) {
  71 + // materialStockService.decreaseStock(line.getItemId(), ..., line.getQuantity());
  72 + // }
  73 + // 更新消耗单状态为已完成
  74 + itemConsumeMapper.updateById(MesWmItemConsumeDO.builder()
  75 + .id(consumeId).status(MesWmItemConsumeStatusEnum.FINISHED.getStatus()).build());
  76 + }
  77 +
  78 +}