Commit 65a97a693b84e649fc2731ed5db7592ef924c2a9

Authored by YunaiV
1 parent 5c577696

✨ feat(mes): 重构报工审批逻辑,更新相关字段和接口

优化报工审批功能,修改了相关的请求和响应对象,移除不必要的字段,新增任务信息的自动填充逻辑。调整了控制器中的方法名称和权限校验,确保审批流程的清晰和一致性。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/MesProFeedbackController.java
... ... @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
17 17 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
18 18 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
19 19 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
  20 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
20 21 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
21 22 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
22 23 import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
... ... @@ -25,6 +26,7 @@ import cn.iocoder.yudao.module.mes.service.pro.feedback.MesProFeedbackService;
25 26 import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
26 27 import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
27 28 import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteService;
  29 +import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
28 30 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
29 31 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
30 32 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
... ... @@ -69,6 +71,8 @@ public class MesProFeedbackController {
69 71 private MesMdUnitMeasureService unitMeasureService;
70 72 @Resource
71 73 private MesProRouteProcessService routeProcessService;
  74 + @Resource
  75 + private MesProTaskService taskService;
72 76  
73 77 @Resource
74 78 private AdminUserApi adminUserApi;
... ... @@ -147,22 +151,12 @@ public class MesProFeedbackController {
147 151 return success(true);
148 152 }
149 153  
150   - @PutMapping("/finish")
151   - @Operation(summary = "执行报工")
  154 + @PutMapping("/approve")
  155 + @Operation(summary = "审批报工")
152 156 @Parameter(name = "id", description = "编号", required = true)
153   - @PreAuthorize("@ss.hasPermission('mes:pro-feedback:finish')")
154   - public CommonResult<Boolean> finishFeedback(@RequestParam("id") Long id) {
155   - feedbackService.finishFeedback(id);
156   - return success(true);
157   - }
158   -
159   - @PutMapping("/cancel")
160   - @Operation(summary = "取消报工")
161   - @Parameter(name = "id", description = "编号", required = true)
162   - @PreAuthorize("@ss.hasPermission('mes:pro-feedback:update')")
163   - public CommonResult<Boolean> cancelFeedback(@RequestParam("id") Long id) {
164   - feedbackService.cancelFeedback(id);
165   - return success(true);
  157 + @PreAuthorize("@ss.hasPermission('mes:pro-feedback:approve')")
  158 + public CommonResult<Integer> approveFeedback(@RequestParam("id") Long id) {
  159 + return success(feedbackService.approveFeedback(id));
166 160 }
167 161  
168 162 // ==================== 拼接 VO ====================
... ... @@ -171,24 +165,27 @@ public class MesProFeedbackController {
171 165 if (CollUtil.isEmpty(list)) {
172 166 return Collections.emptyList();
173 167 }
174   - // 1.1 物料、计量单位
  168 + // 1.1 任务(获取 taskCode)
  169 + Map<Long, MesProTaskDO> taskMap = taskService.getTaskMap(
  170 + convertSet(list, MesProFeedbackDO::getTaskId));
  171 + // 1.2 物料(直接从 DO.itemId)、计量单位(从 item.unitMeasureId)
175 172 Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
176 173 convertSet(list, MesProFeedbackDO::getItemId));
177 174 Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
178   - convertSet(list, MesProFeedbackDO::getUnitMeasureId));
179   - // 1.2 工单
  175 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  176 + // 1.3 工单
180 177 Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap(
181 178 convertSet(list, MesProFeedbackDO::getWorkOrderId));
182   - // 1.3 工作站
  179 + // 1.4 工作站
183 180 Map<Long, MesMdWorkstationDO> workstationMap = workstationService.getWorkstationMap(
184 181 convertSet(list, MesProFeedbackDO::getWorkstationId));
185   - // 1.4 工艺路线
  182 + // 1.5 工艺路线
186 183 Set<Long> routeIds = convertSet(list, MesProFeedbackDO::getRouteId);
187 184 Map<Long, MesProRouteDO> routeMap = routeService.getRouteMap(routeIds);
188   - // 1.5 工序
  185 + // 1.6 工序
189 186 Map<Long, MesProProcessDO> processMap = processService.getProcessMap(
190 187 new ArrayList<>(convertSet(list, MesProFeedbackDO::getProcessId)));
191   - // 1.6 工序的 checkFlag:批量查询后直接构建 routeId -> processId -> checkFlag 的双层 Map
  188 + // 1.7 工序的 checkFlag:批量查询后直接构建 routeId -> processId -> checkFlag 的双层 Map
192 189 List<MesProRouteProcessDO> allRouteProcesses = routeProcessService.getRouteProcessListByRouteIds(routeIds);
193 190 Map<Long, Map<Long, Boolean>> routeProcessCheckFlagMap = new HashMap<>();
194 191 for (MesProRouteProcessDO rp : allRouteProcesses) {
... ... @@ -196,7 +193,7 @@ public class MesProFeedbackController {
196 193 .computeIfAbsent(rp.getRouteId(), k -> new HashMap<>())
197 194 .put(rp.getProcessId(), Boolean.TRUE.equals(rp.getCheckFlag()));
198 195 }
199   - // 1.7 报工人/审核人
  196 + // 1.8 报工人/审核人
200 197 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
201 198 convertSetByFlatMap(list, feedback ->
202 199 Stream.of(feedback.getFeedbackUserId(), feedback.getApproveUserId())));
... ... @@ -218,13 +215,17 @@ public class MesProFeedbackController {
218 215 // 工单
219 216 findAndThen(workOrderMap, vo.getWorkOrderId(), wo ->
220 217 vo.setWorkOrderCode(wo.getCode()).setWorkOrderName(wo.getName()));
221   - // TODO @芋艿:task code 待 pro_task 服务迁移后补充
222   - // TODO @AI:貌似已经支持,可以跟进下
223   - // 物料、计量单位
224   - findAndThen(itemMap, vo.getItemId(), item ->
225   - vo.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification()));
226   - findAndThen(unitMeasureMap, vo.getUnitMeasureId(), unit ->
227   - vo.setUnitMeasureName(unit.getName()));
  218 + // 任务
  219 + findAndThen(taskMap, vo.getTaskId(), task ->
  220 + vo.setTaskCode(task.getCode()));
  221 + // 物料 → 单位
  222 + findAndThen(itemMap, vo.getItemId(), item -> {
  223 + // TODO @AI:specification 全称
  224 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification())
  225 + .setUnitMeasureId(item.getUnitMeasureId());
  226 + findAndThen(unitMeasureMap, item.getUnitMeasureId(), unit ->
  227 + vo.setUnitMeasureName(unit.getName()));
  228 + });
228 229 // 报工人、审核人
229 230 findAndThen(userMap, vo.getFeedbackUserId(), user ->
230 231 vo.setFeedbackUserNickname(user.getNickname()));
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java
... ... @@ -110,10 +110,6 @@ public class MesProFeedbackRespVO {
110 110 @Schema(description = "过期日期")
111 111 private LocalDateTime expireDate;
112 112  
113   - @Schema(description = "批次号", example = "B20250315001")
114   - @ExcelProperty("批次号")
115   - private String batchCode;
116   -
117 113 @Schema(description = "排产数量", example = "5000.00")
118 114 @ExcelProperty("排产数量")
119 115 private BigDecimal scheduledQuantity;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java
... ... @@ -22,9 +22,6 @@ public class MesProFeedbackSaveReqVO {
22 22 @NotNull(message = "报工类型不能为空")
23 23 private Integer type;
24 24  
25   - @Schema(description = "报工途径", example = "PC")
26   - private String channel;
27   -
28 25 @Schema(description = "工作站编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
29 26 @NotNull(message = "工作站不能为空")
30 27 private Long workstationId;
... ... @@ -45,20 +42,9 @@ public class MesProFeedbackSaveReqVO {
45 42 @NotNull(message = "生产任务不能为空")
46 43 private Long taskId;
47 44  
48   - @Schema(description = "产品物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "75")
49   - @NotNull(message = "产品物料不能为空")
50   - private Long itemId;
51   -
52   - @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202")
53   - @NotNull(message = "单位不能为空")
54   - private Long unitMeasureId;
55   -
56 45 @Schema(description = "过期日期")
57 46 private LocalDateTime expireDate;
58 47  
59   - @Schema(description = "批次号", example = "B20250315001")
60   - private String batchCode;
61   -
62 48 @Schema(description = "排产数量", example = "5000.00")
63 49 private BigDecimal scheduledQuantity;
64 50  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
5   -import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
6 5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
7 6 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
8 7 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
... ... @@ -47,6 +46,7 @@ public class MesProFeedbackDO extends BaseDO {
47 46 * 枚举 {@link MesProFeedbackTypeEnum}
48 47 */
49 48 private Integer type;
  49 + // TODO @芋艿:这个字段,暂时没使用到;
50 50 /**
51 51 * 报工途径
52 52 *
... ... @@ -87,26 +87,16 @@ public class MesProFeedbackDO extends BaseDO {
87 87 */
88 88 private Long taskId;
89 89 /**
90   - * 产品物料编号
  90 + * 产品物料编号(冗余自任务)
91 91 *
92 92 * 关联 {@link MesMdItemDO#getId()}
93 93 */
94 94 private Long itemId;
95 95 /**
96   - * 单位编号
97   - *
98   - * 关联 {@link MesMdUnitMeasureDO#getId()}
99   - */
100   - private Long unitMeasureId;
101   - /**
102 96 * 过期日期
103 97 */
104 98 private LocalDateTime expireDate;
105 99 /**
106   - * 批次号
107   - */
108   - private String batchCode;
109   - /**
110 100 * 排产数量
111 101 */
112 102 private BigDecimal scheduledQuantity;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProFeedbackStatusEnum.java
... ... @@ -14,7 +14,6 @@ import java.util.Arrays;
14 14 * 2. 草稿 → 提交 → 审批中(APPROVING)
15 15 * 3. 审批中 → 驳回 → 草稿(PREPARE)
16 16 * 4. 审批中 → 执行 → 待检验(UNCHECK)或已完成(FINISHED),取决于工序 checkFlag
17   - * 5. 草稿/审批中 → 取消 → 已取消(CANCELED)
18 17 *
19 18 * @author 芋道源码
20 19 */
... ... @@ -22,11 +21,15 @@ import java.util.Arrays;
22 21 @AllArgsConstructor
23 22 public enum MesProFeedbackStatusEnum implements ArrayValuable<Integer> {
24 23  
  24 + // TODO @AI:数据库的字典,需要迁移;
  25 +
  26 + // TODO @AI:对齐下 /Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesOrderStatusConstants.java
  27 +
  28 + // TODO @AI:整体注释,变量注释,对齐 /Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProTaskStatusEnum.java
25 29 PREPARE(0, "草稿"),
26 30 APPROVING(1, "审批中"),
27 31 UNCHECK(2, "待检验"),
28   - FINISHED(3, "已完成"),
29   - CANCELED(4, "已取消");
  32 + FINISHED(3, "已完成");
30 33  
31 34 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProFeedbackStatusEnum::getStatus).toArray(Integer[]::new);
32 35  
... ... @@ -45,3 +48,4 @@ public enum MesProFeedbackStatusEnum implements ArrayValuable&lt;Integer&gt; {
45 48 }
46 49  
47 50 }
  51 +
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
... ... @@ -66,17 +66,12 @@ public interface MesProFeedbackService {
66 66 void rejectFeedback(Long id);
67 67  
68 68 /**
69   - * 执行报工(审批中 → 已完成 或 待检验)
  69 + * 审批报工(审批中 -> 已完成 或 待检验)
70 70 *
71 71 * @param id 编号
  72 + * @return 审批后的状态
72 73 */
73   - void finishFeedback(Long id);
74   -
75   - /**
76   - * 取消报工
77   - *
78   - * @param id 编号
79   - */
80   - void cancelFeedback(Long id);
  74 + Integer approveFeedback(Long id);
81 75  
82 76 }
  77 +
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
... ... @@ -5,11 +5,11 @@ import cn.hutool.core.util.ObjUtil;
5 5 import cn.hutool.core.util.ObjectUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8   -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
9 8 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackPageReqVO;
10 9 import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO;
11 10 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
12 11 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
13 13 import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
14 14 import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
15 15 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
... ... @@ -57,11 +57,12 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
57 57 @Override
58 58 public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) {
59 59 // 1. 校验
60   - validateFeedbackData(createReqVO);
  60 + MesProTaskDO task = validateFeedbackData(createReqVO);
61 61  
62   - // 2. 插入
  62 + // 2. 插入(自动填充 itemId)
63 63 MesProFeedbackDO feedback = BeanUtils.toBean(createReqVO, MesProFeedbackDO.class)
64   - .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus());
  64 + .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus())
  65 + .setItemId(task.getItemId());
65 66 feedbackMapper.insert(feedback);
66 67 return feedback.getId();
67 68 }
... ... @@ -71,10 +72,11 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
71 72 // 1.1 校验存在 + 草稿状态
72 73 validateFeedbackStatusPrepare(updateReqVO.getId());
73 74 // 1.2 校验业务数据
74   - validateFeedbackData(updateReqVO);
  75 + MesProTaskDO task = validateFeedbackData(updateReqVO);
75 76  
76   - // 2. 更新
77   - MesProFeedbackDO updateObj = BeanUtils.toBean(updateReqVO, MesProFeedbackDO.class);
  77 + // 2. 更新(自动填充 itemId)
  78 + MesProFeedbackDO updateObj = BeanUtils.toBean(updateReqVO, MesProFeedbackDO.class)
  79 + .setItemId(task.getItemId());
78 80 feedbackMapper.updateById(updateObj);
79 81 }
80 82  
... ... @@ -119,11 +121,25 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
119 121 .setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus()));
120 122 }
121 123  
  124 + // TODO @AI:要不改成 boolean:看是不是 finish;如果非 finish 说明要前端提示“报工成功,请等待质量检验完成!”
122 125 @Override
123 126 @Transactional(rollbackFor = Exception.class)
124   - public void finishFeedback(Long id) {
125   - // 1. 校验存在 + 审批中状态
  127 + public Integer approveFeedback(Long id) {
  128 + // TODO @AI: 逻辑需要继续跟进;
  129 + // 1.1 校验存在 + 审批中状态
126 130 MesProFeedbackDO feedback = validateFeedbackStatusApproving(id);
  131 + // 1.2 校验报工数量 > 0
  132 + if (feedback.getFeedbackQuantity() == null
  133 + || feedback.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) {
  134 + throw exception(PRO_FEEDBACK_QUANTITY_MUST_POSITIVE);
  135 + }
  136 + // 1.3 校验任务未完成
  137 + taskService.validateTaskNotFinished(feedback.getTaskId());
  138 + // 1.4 仍有待检数量时不能执行
  139 + if (feedback.getUncheckQuantity() != null
  140 + && feedback.getUncheckQuantity().compareTo(BigDecimal.ZERO) > 0) {
  141 + throw exception(PRO_FEEDBACK_NOT_APPROVING); // TODO @芋艿:新增一个专用错误码,例如 PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS
  142 + }
127 143  
128 144 // 2.1 查询工序的 checkFlag,决定目标状态
129 145 boolean checkFlag = getCheckFlag(feedback.getRouteId(), feedback.getProcessId());
... ... @@ -141,22 +157,7 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
141 157 // TODO @芋艿:WM 产品产出(WmProductProduceService)未迁移,此处需补充产品产出逻辑
142 158 // TODO @芋艿:updateProTaskAndWorkorder 待 pro_task 服务迁移后补充级联更新任务/工单的已生产数量
143 159 }
144   - }
145   -
146   - @Override
147   - public void cancelFeedback(Long id) {
148   - // 1.1 校验存在
149   - MesProFeedbackDO feedback = validateFeedbackExists(id);
150   - // 1.2 只有草稿或审批中可以取消(已完成、已取消不可操作)
151   - if (ObjectUtils.equalsAny(feedback.getStatus(),
152   - MesProFeedbackStatusEnum.FINISHED.getStatus(),
153   - MesProFeedbackStatusEnum.CANCELED.getStatus())) {
154   - throw exception(PRO_FEEDBACK_STATUS_ERROR);
155   - }
156   -
157   - // 2. 更新状态为已取消
158   - feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
159   - .setStatus(MesProFeedbackStatusEnum.CANCELED.getStatus()));
  160 + return targetStatus;
160 161 }
161 162  
162 163 // ==================== 校验方法 ====================
... ... @@ -189,8 +190,9 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
189 190 * 校验报工单的业务数据(创建 & 修改共用)
190 191 *
191 192 * @param reqVO 报工请求
  193 + * @return 关联的生产任务
192 194 */
193   - private void validateFeedbackData(MesProFeedbackSaveReqVO reqVO) {
  195 + private MesProTaskDO validateFeedbackData(MesProFeedbackSaveReqVO reqVO) {
194 196 // 1. 校验工作站存在
195 197 workstationService.validateWorkstationExists(reqVO.getWorkstationId());
196 198  
... ... @@ -220,8 +222,8 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
220 222 // 3. 校验工单已确认
221 223 workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
222 224  
223   - // 4. 校验任务存在且未终态(已完成/已取消)
224   - taskService.validateTaskNotFinished(reqVO.getTaskId());
  225 + // 4. 校验任务存在且未终态(已完成/已取消),并返回任务用于冗余 itemId
  226 + return taskService.validateTaskNotFinished(reqVO.getTaskId());
225 227 }
226 228  
227 229 /**
... ...