From 227eff61120aaca63e068035d745d86452e6499a Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期一, 17 八月 2026 09:35:12 +0800
Subject: [PATCH] feat(mes): 优化生产订单与排产任务列表显示,新增启停工及校验逻辑 1. 生产订单列表展示优化 (WorkOrder) - 新增「生产状态」列,全局注册 `ORDER_PRODUCTION_STATUS` 常量并绑定系统动态字典。 - 彻底重构「工序生产进度」单元格显示:弃用臃肿的 Steps 组件,改为极简横向布局(彩色状态圆点 + 进度百分比),解决表格行高被强行撑开及内容截断问题,支持横向滚动。 - 优化「完成进度」列宽及展示样式,将百分比数值外置同行显示,更加直观。 2. 排产任务列表改造 (Task) - 顶部表头重构,由单一标题重构为「全部 / 未完成 / 已完成」的 Tabs 标签页切换结构。 - 重写数据过滤逻辑,剥离写死的 status 查询,改为使用 `scheduleStatus` 字段动态响应 Tabs 切换 (0: 未完成, 1: 已完成)。 3. 工单业务逻辑增强与状态流转 - 落实「工单查询逻辑设计方案」,优化底层的工单条件检索逻辑。 - 实现「添加工单启停功能」与「停工状态」,支持工单在执行过程中的暂停与恢复业务流转。 - 强化容错与防呆设计:操作「完成订单」时增加前置校验 `handleCheckFinish`,若生产状态为未完成,强制弹出二次确认 Modal,避免误操作。 # 相关讨论/参考方案 # - 添加工单启停功能 # - 停工状态功能设计方案 # - 工单查询逻辑设计方案 # - 工单完成进度显示优化
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java | 365 +++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 304 insertions(+), 61 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
index e7148ee..d5401e9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -1,36 +1,55 @@
package cn.iocoder.yudao.module.mes.service.pro.feedback;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
-import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackPageReqVO;
-import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.*;
+import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackTypeEnum;
+import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProTaskStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
-import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
import cn.iocoder.yudao.module.mes.service.wm.itemconsume.MesWmItemConsumeService;
import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService;
import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceService;
+import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
+import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
+import cn.iocoder.yudao.module.mdm.api.item.MdmItemBatchConfigApi;
+import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemBatchConfigRespDTO;
+import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi;
+import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsRespDTO;
+import cn.iocoder.yudao.module.mes.api.event.ProductionFinishedEvent;
import jakarta.annotation.Resource;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -39,7 +58,7 @@
/**
* MES 鐢熶骇鎶ュ伐 Service 瀹炵幇绫�
*
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
*/
@Service
@Validated
@@ -53,7 +72,9 @@
@Resource
private MesProRouteProcessService routeProcessService;
@Resource
- private MesMdWorkstationService workstationService;
+ private MesProWorkOrderBomService workOrderBomService;
+ @Resource
+ private MesProWorkOrderProcessService workOrderProcessService;
@Resource
@Lazy // 閬垮厤寰幆渚濊禆
private MesProTaskService taskService;
@@ -63,6 +84,16 @@
private MesWmProductProduceService productProduceService;
@Resource
private MesWmProductProduceLineService produceLineService;
+ @Resource
+ private MesProMpsApi mpsApi;
+ @Resource
+ private MesMdAutoCodeRecordService autoCodeRecordService;
+ @Resource
+ private ApplicationEventPublisher eventPublisher;
+ @Resource
+ private MesMdmItemService mdmItemService;
+ @Resource
+ private MdmItemBatchConfigApi itemBatchConfigApi;
@Override
public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) {
@@ -105,6 +136,19 @@
}
@Override
+ public List<MesProFeedbackDO> getFeedbackListByTaskIds(Collection<Long> taskIds) {
+ if (CollUtil.isEmpty(taskIds)) {
+ return Collections.emptyList();
+ }
+ return feedbackMapper.selectListByTaskIds(taskIds);
+ }
+
+ @Override
+ public List<MesProFeedbackDO> getFeedbackListByTaskId(Long taskId) {
+ return feedbackMapper.selectListByTaskId(taskId);
+ }
+
+ @Override
public PageResult<MesProFeedbackDO> getFeedbackPage(MesProFeedbackPageReqVO pageReqVO) {
return feedbackMapper.selectPage(pageReqVO);
}
@@ -131,9 +175,9 @@
@Override
@Transactional(rollbackFor = Exception.class)
- public boolean approveFeedback(Long id) {
+ public boolean approveFeedback(MesProFeedbackApproveReqVO reqVO) {
// 1.1 鏍¢獙瀛樺湪 + 瀹℃壒涓姸鎬�
- MesProFeedbackDO feedback = validateFeedbackStatusApproving(id);
+ MesProFeedbackDO feedback = validateFeedbackStatusApproving(reqVO.getId());
// 1.2 鏍¢獙鎶ュ伐鏁伴噺 > 0
if (feedback.getFeedbackQuantity() == null
|| feedback.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) {
@@ -154,32 +198,54 @@
throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity());
}
- // 3. 鐗╂枡娑堣�楋細鏍规嵁宸ュ簭 BOM 鐢熸垚娑堣�楄褰曞苟鎵ц鎵e噺
- MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback);
- if (itemConsume != null) {
- itemConsumeService.finishItemConsume(itemConsume.getId());
- }
-
- // 4. 鍏抽敭宸ュ簭锛氱敓鎴愪骇鍑哄崟锛屽苟鏍规嵁鏄惁闇�瑕佹楠屽喅瀹氬叆搴撴柟寮�
- if (keyFlag) {
- // 4.1 闇�瑕佹楠岋細鐢熸垚浜у嚭鍗曪紙璐ㄩ噺鐘舵��=寰呮楠岋級锛屾洿鏂版姤宸ョ姸鎬佷负寰呮楠岋紝绛夎川妫�瀹屾垚鍥炶皟鍚庡啀鍏ュ簱
- if (checkFlag) {
- // 瀹屾垚鏃跺洖璋冭锛歁esQcIpqcServiceImpl#finishIpqc 鈫� splitPendingAndFinishProduce + completeFeedbackFromIpqc
- productProduceService.generateProductProduce(feedback, true);
- feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
- .setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus()));
- return false;
+ // 3. 鐗╂枡娑堣�楋細鍊掑啿宸ュ簭鎸� BOM 鑷姩鎵f枡锛涢潪鍊掑啿宸ュ簭璺宠繃锛堢墿鏂欒蛋鎵嬪伐棰嗘枡/鎶曟枡锛�
+ boolean backflushFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getBackflushFlag());
+ if (backflushFlag) {
+ // 3.1 鏍¢獙鍊掑啿宸ュ簭蹇呴』閰嶇疆 BOM 娑堣�楋紝閬垮厤闈欓粯涓嶆墸鏂�
+ List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderId(
+ feedback.getWorkOrderId());
+ if (CollUtil.isEmpty(boms)) {
+ throw exception(PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED);
}
- // 4.2 鏃犻渶妫�楠岋細鐢熸垚浜у嚭鍗曪紙鎸夊悎鏍�/涓嶅悎鏍兼媶琛岋級锛岀洿鎺ュ畬鎴愬叆搴擄紝骞舵洿鏂颁换鍔�/宸ュ崟鐨勫凡鐢熶骇鏁伴噺
- MesWmProductProduceDO produce = productProduceService.generateProductProduce(feedback, false);
- productProduceService.finishProductProduce(produce.getId());
- updateTaskAndWorkOrderByFeedback(feedback);
+ // 3.2 鐢熸垚娑堣�楄褰曞苟鎵ц鎵e噺锛圔OM 脳 鎶ュ伐鏁伴噺锛孎IFO 鎵g嚎杈瑰簱锛�
+ MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback);
+ if (itemConsume != null) {
+ itemConsumeService.finishItemConsume(itemConsume.getId());
+ }
}
- // 5. 闈炲叧閿伐搴� / 鍏抽敭闈炶川妫�宸ュ簭锛氱洿鎺ュ畬鎴愶紙娓呴浂 uncheckQuantity 闃叉 !key+check 鐣欒剰鏁版嵁锛�
- feedbackMapper.updateById(new MesProFeedbackDO().setId(id)
+ // 5. 鍏堟洿鏂版姤宸ョ姸鎬佷负宸插畬鎴愶紙纭繚 checkAndFinishMps 妫�鏌ユ椂褰撳墠鎶ュ伐宸叉爣璁板畬鎴愶級
+ feedbackMapper.updateById(new MesProFeedbackDO().setId(reqVO.getId())
.setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus())
.setUncheckQuantity(BigDecimal.ZERO));
+
+ // 6. 鏍规嵁鏄惁闇�瑕佹楠岋紝鍐冲畾浜у嚭鍜屽叆搴撴柟寮�
+ // 6.2 璋冩暣 鍙瀹℃壒鎴愬姛鐩存帴鏇存柊
+ // 鍏抽敭宸ュ簭锛氭洿鏂颁换鍔� + 宸ュ崟鐨勫凡鐢熶骇鏁伴噺锛涢潪鍏抽敭宸ュ簭锛氬彧鏇存柊浠诲姟鐨勫凡鐢熶骇鏁伴噺锛堝伐鍗曞彧鐪嬪叧閿伐搴忎骇鍑猴級
+ if (keyFlag) {
+ updateTaskAndWorkOrderByFeedback(feedback);
+ } else {
+ taskService.updateProducedQuantity(feedback.getTaskId(),
+ feedback.getFeedbackQuantity(),
+ ObjectUtil.defaultIfNull(feedback.getQualifiedQuantity(), BigDecimal.ZERO),
+ ObjectUtil.defaultIfNull(feedback.getUnqualifiedQuantity(), BigDecimal.ZERO));
+ checkAndPublishProductionFinished(feedback.getWorkOrderId());
+
+ }
+ if (checkFlag) {
+ // 6.1 闇�瑕佹楠岋細鐢熸垚浜у嚭鍗曪紙璐ㄩ噺鐘舵��=寰呮楠岋級锛屾洿鏂版姤宸ョ姸鎬佷负寰呮楠岋紝绛夎川妫�瀹屾垚鍥炶皟鍚庡啀鍏ュ簱
+ // 瀹屾垚鏃跺洖璋冭锛歁esQcIpqcServiceImpl#finishIpqc 鈫� splitPendingAndFinishProduce + updateProFeedbackWhenIpqcFinish
+ productProduceService.generateProductProduce(feedback, true, reqVO);
+ feedbackMapper.updateById(new MesProFeedbackDO().setId(reqVO.getId())
+ .setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus()));
+ return false;
+ } else {
+ // 6.2 鏃犻渶妫�楠岋細鐢熸垚浜у嚭鍗曪紙鎸夊悎鏍�/涓嶅悎鏍兼媶琛岋級锛岀洿鎺ュ畬鎴愬叆搴�
+ MesWmProductProduceDO produce = productProduceService.generateProductProduce(feedback, false, reqVO);
+ productProduceService.finishProductProduce(produce.getId());
+
+ }
+
return true; // 宸插畬鎴�
}
@@ -190,6 +256,7 @@
* <li>浣跨敤鎶ュ伐鏁伴噺锛坒eedbackQuantity锛夛紝绱姞浠诲姟鍜屽伐鍗曠殑宸茬敓浜ф暟閲�</li>
* <li>浣跨敤浜у嚭鍗曡鎸� qualityStatus 鑱氬悎鐨勫悎鏍煎搧/涓嶅悎鏍煎搧鏁伴噺锛岀疮鍔犱换鍔$殑鍚堟牸鍝�/涓嶅悎鏍煎搧鏁伴噺
* 锛堜笉鐩存帴鐢� feedback 涓婄殑鏁伴噺锛岀‘淇濊川妫�鍥炶皟鍦烘櫙涓嬫暟閲忔潵婧愭纭級</li>
+ * isPush 鏄惁鎺ㄩ�佺敓浜у畬鎴愪簨浠�
* </ul>
*
* @param feedback 鎶ュ伐鍗�
@@ -208,12 +275,44 @@
}
}
- // 2. 鏇存柊浠诲姟鐨勫凡鐢熶骇/鍚堟牸/涓嶅悎鏍兼暟閲�
+ // 2. 鏇存柊浠诲姟鐨勫凡鐢熶骇/鍚堟牸/涓嶅悎鏍兼暟閲�
taskService.updateProducedQuantity(feedback.getTaskId(),
feedback.getFeedbackQuantity(), qualifiedQty, unqualifiedQty);
- // 3. 鏇存柊宸ュ崟鐨勫凡鐢熶骇鏁伴噺
- workOrderService.updateProducedQuantity(feedback.getWorkOrderId(),
- feedback.getFeedbackQuantity());
+ // 3. 鏇存柊璁㈠崟鐨勫凡鐢熶骇鏁伴噺
+ // 鏂板閫昏緫锛氬彧鏈夊湪璇ョ瑪璁㈠崟鏈�鍚庝竴涓伐搴忔墠鏇存柊鐢熶骇璁㈠崟鐨勫凡鐢熶骇鏁伴噺
+ MesProWorkOrderProcessDO lastProcess = workOrderProcessService.getLastWorkOrderProcessByWorkOrderId(feedback.getWorkOrderId());
+ if (lastProcess != null && ObjUtil.equal(lastProcess.getProcessId(), feedback.getProcessId())) {
+ workOrderService.updateProducedQuantity(feedback.getWorkOrderId(),
+ feedback.getFeedbackQuantity());
+ // 4. 鏇存柊 MPS 鐨勫凡鐢熶骇鏁伴噺锛堝鏋滄槸閿�鍞鍗曟潵婧愶級
+ MesProMpsRespDTO mps = mpsApi.getMpsByWorkOrderId(feedback.getWorkOrderId());
+ if (mps != null) {
+ mpsApi.updateMpsProducedQuantity(mps.getId(), feedback.getFeedbackQuantity());
+ }
+ }
+
+
+ // 5. 妫�鏌ュ苟鍙戝竷鐢熶骇瀹屾垚浜嬩欢
+ checkAndPublishProductionFinished(feedback.getWorkOrderId());
+ }
+
+ /**
+ * 妫�鏌ュ苟鍙戝竷鐢熶骇瀹屾垚浜嬩欢
+ */
+ private void checkAndPublishProductionFinished(Long workOrderId) {
+ // 1. 鑾峰彇宸ュ崟鍏宠仈鐨� MPS
+ MesProMpsRespDTO mps = mpsApi.getMpsByWorkOrderId(workOrderId);
+ if (mps == null || mps.getSaleOrderId() == null) {
+ return; // 闈為攢鍞鍗曟潵婧愮殑宸ュ崟锛岃烦杩�
+ }
+
+ // 2. 妫�鏌ュ苟鑷姩瀹屾垚 MPS锛堝鏋滄弧瓒虫潯浠讹級
+ mpsApi.checkAndFinishMps(mps.getId());
+
+ // 3. 妫�鏌ラ攢鍞鍗曟墍鏈夌敓浜ф槸鍚﹀畬鎴�
+ if (mpsApi.checkSaleOrderProductionFinished(mps.getSaleOrderId())) {
+ eventPublisher.publishEvent(new ProductionFinishedEvent(mps.getSaleOrderId(), java.time.LocalDateTime.now()));
+ }
}
// ==================== 鏍¢獙鏂规硶 ====================
@@ -246,23 +345,35 @@
/**
* 鏍¢獙鎶ュ伐鍗曠殑涓氬姟鏁版嵁锛堝垱寤� & 淇敼鍏辩敤锛�
*
+ * <p>浠ョ敓浜т换鍔′负鏍稿績锛氬墠绔彧闇�浼� taskId锛寃orkOrderId銆乺outeId銆乸rocessId銆乮temId銆亀orkstationId
+ * 浠庝换鍔¤嚜鍔ㄥ~鍏咃紝鏃犻渶鍓嶇閲嶅浼犲叆銆�
+ *
* @param reqVO 鎶ュ伐璇锋眰
* @return 鍏宠仈鐨勭敓浜т换鍔�
*/
private MesProTaskDO validateFeedbackData(MesProFeedbackSaveReqVO reqVO) {
- // 1. 鏍¢獙宸ヤ綔绔欏瓨鍦�
- MesMdWorkstationDO workstation = workstationService.validateWorkstationExists(reqVO.getWorkstationId());
- if (ObjUtil.notEqual(workstation.getProcessId(), reqVO.getProcessId())) {
- throw exception(PRO_WORKSTATION_PROCESS_MISMATCH);
+ // 1. 鏍¢獙浠诲姟瀛樺湪涓旀湭缁堟��
+ MesProTaskDO task = taskService.validateTaskNotFinished(reqVO.getTaskId());
+
+ // 鏍¢獙鍋滃伐鐘舵�佷笉鑳芥姤宸�
+ if (!MesProTaskStatusEnum.canFeedback(task.getStatus())) {
+ throw exception(PRO_FEEDBACK_CANNOT_CREATE_WHEN_PAUSED);
}
- // 2.1 鏍¢獙宸ヨ壓璺嚎 + 宸ュ簭閰嶇疆鏈夋晥
+ // 2. 浠庝换鍔¤嚜鍔ㄥ~鍏呭叧鑱斿瓧娈碉紙鍓嶇鏃犻渶浼犲叆锛屽悗绔粺涓�浠庝换鍔¤幏鍙栵級
+ reqVO.setWorkOrderId(task.getWorkOrderId());
+ reqVO.setRouteId(task.getRouteId());
+ reqVO.setProcessId(task.getProcessId());
+ reqVO.setItemId(task.getItemId());
+ reqVO.setWorkstationId(task.getWorkstationId());
+
+ // 3. 鏍¢獙宸ヨ壓璺嚎 + 宸ュ簭閰嶇疆鏈夋晥
MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId(
- reqVO.getRouteId(), reqVO.getProcessId());
+ task.getRouteId(), task.getProcessId());
if (routeProcess == null) {
throw exception(PRO_FEEDBACK_ROUTE_PROCESS_INVALID);
}
- // 2.2 鏍¢獙鏁伴噺
+ // 4.1 鏍¢獙鏁伴噺
boolean checkFlag = Boolean.TRUE.equals(routeProcess.getCheckFlag());
if (checkFlag) {
// 闇�瑕佹楠岋細鍙渶濉姤宸ユ暟閲忥紝涓斿繀椤� > 0
@@ -279,33 +390,98 @@
}
}
- // 3. 鏍¢獙宸ュ崟宸茬‘璁�
- MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
- if (ObjUtil.notEqual(workOrder.getProductId(), reqVO.getItemId())) {
- throw exception(PRO_WORK_ORDER_PRODUCT_MISMATCH);
- }
-
- // 4. 鏍¢獙浠诲姟瀛樺湪涓旀湭缁堟�侊紙宸插畬鎴�/宸插彇娑堬級锛屽苟杩斿洖浠诲姟鐢ㄤ簬鍐椾綑 itemId
- MesProTaskDO task = taskService.validateTaskNotFinished(reqVO.getTaskId());
- validateTaskRelation(task, workstation, workOrder, reqVO);
return task;
}
- private void validateTaskRelation(MesProTaskDO task, MesMdWorkstationDO workstation,
- MesProWorkOrderDO workOrder, MesProFeedbackSaveReqVO reqVO) {
- if (ObjUtil.notEqual(task.getWorkOrderId(), workOrder.getId())) {
- throw exception(PRO_TASK_WORK_ORDER_MISMATCH);
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public MesProFeedbackQuickCreateRespVO quickCreateFeedback(MesProFeedbackQuickCreateReqVO reqVO) {
+ // 1. 鏍¢獙浠诲姟瀛樺湪涓旈潪缁堟��
+ MesProTaskDO task = taskService.validateTaskNotFinished(reqVO.getTaskId());
+
+ // 鏍¢獙鍋滃伐鐘舵�佷笉鑳芥姤宸�
+ if (!MesProTaskStatusEnum.canFeedback(task.getStatus())) {
+ throw exception(PRO_FEEDBACK_CANNOT_CREATE_WHEN_PAUSED);
}
- if (ObjUtil.notEqual(task.getWorkstationId(), workstation.getId())) {
- throw exception(PRO_TASK_WORKSTATION_MISMATCH);
+
+ // 2. 鏍¢獙宸ヨ壓璺嚎宸ュ簭閰嶇疆
+ MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId(
+ task.getRouteId(), task.getProcessId());
+ if (routeProcess == null) {
+ throw exception(PRO_FEEDBACK_ROUTE_PROCESS_INVALID);
}
- if (ObjUtil.notEqual(task.getRouteId(), reqVO.getRouteId())
- || ObjUtil.notEqual(task.getProcessId(), reqVO.getProcessId())) {
- throw exception(PRO_TASK_ROUTE_PROCESS_MISMATCH);
+ // 3. 鏍¢獙鏁伴噺
+ boolean checkFlag = Boolean.TRUE.equals(routeProcess.getCheckFlag());
+ if (checkFlag) {
+ if (reqVO.getFeedbackQuantity() == null
+ || reqVO.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+ throw exception(PRO_FEEDBACK_QUANTITY_MUST_POSITIVE);
+ }
+ } else {
+ BigDecimal qualified = ObjectUtil.defaultIfNull(reqVO.getQualifiedQuantity(), BigDecimal.ZERO);
+ BigDecimal unqualified = ObjectUtil.defaultIfNull(reqVO.getUnqualifiedQuantity(), BigDecimal.ZERO);
+ if (qualified.add(unqualified).compareTo(BigDecimal.ZERO) <= 0) {
+ throw exception(PRO_FEEDBACK_QUALIFIED_UNQUALIFIED_REQUIRED);
+ }
}
- if (ObjUtil.notEqual(task.getItemId(), reqVO.getItemId())) {
- throw exception(PRO_TASK_ITEM_MISMATCH);
+ // 4. 鏋勫缓鎶ュ伐DO
+ MesProFeedbackDO feedback = new MesProFeedbackDO()
+ .setCode(autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRO_FEEDBACK_CODE.getCode()))
+ .setType(MesProFeedbackTypeEnum.SELF.getType())
+ .setWorkstationId(task.getWorkstationId())
+ .setRouteId(task.getRouteId())
+ .setProcessId(task.getProcessId())
+ .setWorkOrderId(task.getWorkOrderId())
+ .setTaskId(reqVO.getTaskId())
+ .setItemId(task.getItemId())
+ .setFeedbackQuantity(reqVO.getFeedbackQuantity())
+ .setQualifiedQuantity(reqVO.getQualifiedQuantity())
+ .setUnqualifiedQuantity(reqVO.getUnqualifiedQuantity())
+ .setScheduledQuantity(task.getQuantity())
+ .setFeedbackTime(LocalDateTime.now())
+ .setStatus(MesProFeedbackStatusEnum.APPROVING.getStatus())
+ .setRemark(reqVO.getRemark());
+ feedbackMapper.insert(feedback);
+ // 5. 杩斿洖缁撴灉
+ MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(task.getWorkOrderId());
+ return new MesProFeedbackQuickCreateRespVO()
+ .setFeedbackId(feedback.getId())
+ .setTaskStatus(task.getStatus())
+ .setWorkOrderStatus(workOrder != null ? workOrder.getStatus() : null);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public MesProFeedbackBatchCreateRespVO batchCreateFeedback(MesProFeedbackBatchCreateReqVO reqVO) {
+ List<MesProFeedbackBatchCreateRespVO.BatchResult> results = new java.util.ArrayList<>();
+ int successCount = 0;
+ int failCount = 0;
+ for (Long taskId : reqVO.getTaskIds()) {
+ try {
+ MesProFeedbackQuickCreateReqVO singleReq = new MesProFeedbackQuickCreateReqVO();
+ singleReq.setTaskId(taskId);
+ singleReq.setFeedbackQuantity(reqVO.getFeedbackQuantity());
+ singleReq.setQualifiedQuantity(reqVO.getQualifiedQuantity());
+ singleReq.setUnqualifiedQuantity(reqVO.getUnqualifiedQuantity());
+ singleReq.setRemark(reqVO.getRemark());
+ MesProFeedbackQuickCreateRespVO resp = quickCreateFeedback(singleReq);
+ results.add(new MesProFeedbackBatchCreateRespVO.BatchResult()
+ .setTaskId(taskId)
+ .setSuccess(true)
+ .setFeedbackId(resp.getFeedbackId()));
+ successCount++;
+ } catch (Exception e) {
+ results.add(new MesProFeedbackBatchCreateRespVO.BatchResult()
+ .setTaskId(taskId)
+ .setSuccess(false)
+ .setErrorMsg(e.getMessage()));
+ failCount++;
+ }
}
+ return new MesProFeedbackBatchCreateRespVO()
+ .setSuccessCount(successCount)
+ .setFailCount(failCount)
+ .setResults(results);
}
@Override
@@ -334,7 +510,74 @@
// 4. 鏇存柊浠诲姟/宸ュ崟鐨勫凡鐢熶骇鏁伴噺
feedback.setQualifiedQuantity(qualifiedQty).setUnqualifiedQuantity(unqualifiedQty);
- updateTaskAndWorkOrderByFeedback(feedback);
+ //5.妫�鏌ュ苟鍙戝竷鐢熶骇瀹屾垚浜嬩欢
+ checkAndPublishProductionFinished(feedback.getWorkOrderId());
+ }
+
+ @Override
+ public MesProFeedbackBatchCheckRespVO checkBatchRequirements(Long feedbackId) {
+ MesProFeedbackDO feedback = validateFeedbackExists(feedbackId);
+ MesProFeedbackBatchCheckRespVO respVO = new MesProFeedbackBatchCheckRespVO();
+
+ // 1. 妫�鏌ョ墿鏂欐槸鍚﹀惎鐢ㄦ壒娆$鐞�
+ MesMdmItemDO item = mdmItemService.getItem(feedback.getItemId());
+ if (item == null || Boolean.FALSE.equals(item.getIsBatchManaged())) {
+ respVO.setNeedBatchInput(false);
+ respVO.setIsBatchManaged(false);
+ return respVO;
+ }
+ respVO.setIsBatchManaged(true);
+
+ // 2. 鑾峰彇鎵规閰嶇疆
+ MdmItemBatchConfigRespDTO config = itemBatchConfigApi.getItemBatchConfig(feedback.getItemId());
+ if (config == null) {
+ respVO.setNeedBatchInput(false);
+ return respVO;
+ }
+
+ // 3. 濉厖閰嶇疆鏍囧織
+ respVO.setProduceDateFlag(config.getProduceDateFlag());
+ respVO.setExpireDateFlag(config.getExpireDateFlag());
+ respVO.setReceiptDateFlag(config.getReceiptDateFlag());
+ respVO.setVendorFlag(config.getVendorFlag());
+ respVO.setClientFlag(config.getClientFlag());
+ respVO.setSalesOrderCodeFlag(config.getSalesOrderCodeFlag());
+ respVO.setPurchaseOrderCodeFlag(config.getPurchaseOrderCodeFlag());
+ respVO.setWorkOrderFlag(config.getWorkOrderFlag());
+ respVO.setTaskFlag(config.getTaskFlag());
+ respVO.setWorkstationFlag(config.getWorkstationFlag());
+ respVO.setToolFlag(config.getToolFlag());
+ respVO.setMoldFlag(config.getMoldFlag());
+ respVO.setLotNumberFlag(config.getLotNumberFlag());
+ respVO.setQualityStatusFlag(config.getQualityStatusFlag());
+
+ // 4. 鍒ゆ柇鍝簺瀛楁宸茶嚜鍔ㄥ~鍏咃紙鎶ュ伐鍜岀敓浜ц繃绋嬩腑蹇呯劧鏈夊�肩殑瀛楁锛�
+ List<String> autoFilled = new ArrayList<>();
+ // 鐢熶骇鏃ユ湡锛氬鎵规椂鑷姩鍙栧綋澶�
+ autoFilled.add("produceDate");
+ // 鐢熶骇宸ュ崟锛氫粠鎶ュ伐璁板綍鑾峰彇
+ autoFilled.add("workOrderId");
+ // 鐢熶骇浠诲姟锛氫粠鎶ュ伐璁板綍鑾峰彇
+ autoFilled.add("taskId");
+ // 宸ヤ綔绔欙細浠庢姤宸ヨ褰曡幏鍙�
+ autoFilled.add("workstationId");
+ respVO.setAutoFilledFields(autoFilled);
+
+ // 5. 鍒ゆ柇鏄惁闇�瑕佸脊绐楋細瀛樺湪蹇呭~浣嗘棤娉曡嚜鍔ㄥ~鍏呯殑瀛楁
+ boolean needBatchInput = false;
+ if (Boolean.TRUE.equals(config.getExpireDateFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getReceiptDateFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getVendorFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getClientFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getToolFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getMoldFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getLotNumberFlag())) needBatchInput = true;
+ if (Boolean.TRUE.equals(config.getQualityStatusFlag())) needBatchInput = true;
+ respVO.setNeedBatchInput(needBatchInput);
+
+ return respVO;
}
}
--
Gitblit v1.9.3