From ac2e2b5af3726ee64dc37c3ebf26989a0346f22a Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期六, 07 十一月 2026 19:16:05 +0800
Subject: [PATCH] feat(feedback): 优化报工审批流程并增加报工人校验

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java |  215 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 161 insertions(+), 54 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
index 2f47fee..843615d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
@@ -8,6 +8,7 @@
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
@@ -17,10 +18,12 @@
 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper;
 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
 import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
-import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
@@ -34,7 +37,6 @@
 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrSaveReqVO;
 import cn.iocoder.yudao.module.mes.service.qc.ncr.MesQcNcrService;
-import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
@@ -49,6 +51,7 @@
 import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcImportExcelVO;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcImportRespVO;
@@ -87,6 +90,11 @@
     private MesQcIpqcMapper ipqcMapper;
 
     @Resource
+    private MesWmProductProduceLineMapper produceLineMapper;
+    @Resource
+    private MesProFeedbackMapper feedbackMapper;
+
+    @Resource
     private MesQcTemplateItemService templateItemService;
     @Resource
     private MesQcIpqcLineService ipqcLineService;
@@ -119,10 +127,6 @@
     private MesQcIndicatorResultService indicatorResultService;
     @Resource
     @Lazy
-    private MesWmProductProduceLineService productProduceLineService;
-
-    @Resource
-    @Lazy
     private MesQcNcrService ncrService;
 
     @Resource
@@ -135,23 +139,69 @@
         SaveDataContext ctx = validateIpqcSaveData(createReqVO);
         // 1.2 鏍¢獙宸ュ崟瀛樺湪
         MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
-        // 1.3 纭畾妫�楠岀墿鏂欙細鏈変换鍔℃椂鍙栦换鍔$殑鐗╂枡锛屾棤浠诲姟鏃跺彇宸ュ崟鐨勪骇鍝�
-        Long itemId = (ctx.task() != null) ? ctx.task().getItemId() : workOrder.getProductId();
-        // 1.4 鏍规嵁鐗╂枡 + 妫�楠岀被鍨嬭嚜鍔ㄥ尮閰嶆ā鏉�
-        MesQcTemplateItemDO templateItem = templateItemService.getRequiredTemplateByItemIdAndType(
-                itemId, MesQcTypeEnum.IPQC.getType());
-        Long templateId = templateItem.getTemplateId();
-        // 1.5 鑾峰彇鏉ユ簮鍗曟嵁缂栧彿
-        String sourceDocCode = validateAndGetSourceDocCode(
+        // 1.3 鑾峰彇鏉ユ簮鍗曟嵁缂栧彿锛屽苟纭畾鏈妫�楠岀殑鐗╂枡涓庡伐搴�
+        //     鎶ュ伐鏉ユ簮锛氫竴涓姤宸ュ彲鑳戒骇鍑哄涓墿鏂欙紝姣忎釜浜у嚭琛屽悇鑷楠岋紝鐗╂枡鍙栦骇鍑鸿銆佸伐搴忓彇鎶ュ伐宸ュ簭
+        //     鍏跺畠鏉ユ簮锛氭湁浠诲姟鏃跺彇浠诲姟鐨勭墿鏂欙紝鏃犱换鍔℃椂鍙栧伐鍗曠殑浜у搧
+        SourceDocInfo sourceDoc = validateAndGetSourceDoc(
                 createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId());
+        Long itemId;
+        Long processId;
+        if (Objects.equals(createReqVO.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) {
+            MesProFeedbackDO feedback = feedbackService.validateFeedbackExists(createReqVO.getSourceDocId());
+            if (!Objects.equals(feedback.getWorkOrderId(), createReqVO.getWorkOrderId())
+                    || !Objects.equals(feedback.getTaskId(), createReqVO.getTaskId())) {
+                throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
+            }
+            if (!ipqcMapper.selectBySourceLineForUpdate(MesBizTypeConstants.PRO_FEEDBACK,
+                    createReqVO.getSourceLineId()).isEmpty()) {
+                throw exception(QC_IPQC_SOURCE_ALREADY_LINKED);
+            }
+            if (sourceDoc.line() == null || sourceDoc.line().getItemId() == null) {
+                throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
+            }
+            itemId = sourceDoc.line().getItemId();
+            processId = feedback.getProcessId();
+        } else {
+            itemId = (ctx.task() != null) ? ctx.task().getItemId() : workOrder.getProductId();
+            processId = getProcessId(itemId, ctx.workstation().getProcessId());
+        }
+        // 1.4 鏍规嵁鐗╂枡 + 妫�楠岀被鍨嬭嚜鍔ㄥ尮閰嶆ā鏉匡紙缂哄け鏃剁粰鍑虹墿鏂欑淮搴︾殑鏄庣‘鎻愮ず锛�
+        MesQcTemplateItemDO templateItem;
+        try {
+            templateItem = templateItemService.getRequiredTemplateByItemIdAndType(
+                    itemId, MesQcTypeEnum.IPQC.getType());
+        } catch (ServiceException e) {
+            if (!Objects.equals(e.getCode(), QC_NO_TEMPLATE.getCode())) {
+                throw e;
+            }
+            throw exception(QC_IPQC_NO_TEMPLATE_FOR_ITEM, getItemInfo(itemId));
+        }
+        Long templateId = templateItem.getTemplateId();
+        String sourceDocCode = sourceDoc.code();
 
         // 2. 鎻掑叆涓昏〃
         MesQcIpqcDO ipqc = BeanUtils.toBean(createReqVO, MesQcIpqcDO.class)
                 .setItemId(itemId)
-                .setProcessId(getProcessId(itemId, ctx.workstation().getProcessId()))
+                .setProcessId(processId)
                 .setTemplateId(templateId)
                 .setSourceDocCode(sourceDocCode)
                 .setStatus(MesQcStatusEnum.DRAFT.getStatus());
+        // 宸ュ簾/鏂欏簾/鍏朵粬搴熷搧銆佹娴嬩汉鍛樸�佹娴嬫棩鏈熸湭濉啓鏃朵娇鐢ㄩ粯璁ゅ�硷紝涓嶅奖鍝嶆祦绋�
+        if (ipqc.getLaborScrapQuantity() == null) {
+            ipqc.setLaborScrapQuantity(BigDecimal.ZERO);
+        }
+        if (ipqc.getMaterialScrapQuantity() == null) {
+            ipqc.setMaterialScrapQuantity(BigDecimal.ZERO);
+        }
+        if (ipqc.getOtherScrapQuantity() == null) {
+            ipqc.setOtherScrapQuantity(BigDecimal.ZERO);
+        }
+        if (ipqc.getInspectorUserId() == null) {
+            ipqc.setInspectorUserId(getLoginUserId());
+        }
+        if (ipqc.getInspectDate() == null) {
+            ipqc.setInspectDate(LocalDateTime.now());
+        }
         ipqcMapper.insert(ipqc);
 
         // 3. 浠庢ā鏉挎寚鏍囪嚜鍔ㄧ敓鎴愭楠岃
@@ -160,20 +210,32 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateIpqc(MesQcIpqcSaveReqVO updateReqVO) {
         // 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
-        validateIpqcStatusPrepare(updateReqVO.getId());
+        validateIpqcStatusPrepareForUpdate(updateReqVO.getId());
         // 1.2 鏍¢獙鏁版嵁
         SaveDataContext ctx = validateIpqcSaveData(updateReqVO);
 
         // 2. 鏇存柊涓昏〃
         MesQcIpqcDO existIpqc = validateIpqcExists(updateReqVO.getId());
+        if (Objects.equals(existIpqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)
+                && (!Objects.equals(existIpqc.getTaskId(), updateReqVO.getTaskId())
+                    || !Objects.equals(existIpqc.getWorkOrderId(), updateReqVO.getWorkOrderId())
+                    || !Objects.equals(existIpqc.getWorkstationId(), updateReqVO.getWorkstationId()))) {
+            throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
+        }
         MesQcIpqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIpqcDO.class);
         updateObj.setSourceDocType(null).setSourceDocId(null).setSourceLineId(null); // 涓嶅厑璁镐慨鏀规潵婧愬崟鎹�
         updateObj.setTemplateId(null); // 涓嶅厑璁镐慨鏀规ā鏉�
         updateObj.setItemId(null); // 涓嶅厑璁镐慨鏀圭墿鏂�
         updateObj.setWorkOrderId(null); // 涓嶅厑璁镐慨鏀瑰伐鍗�
-        updateObj.setProcessId(getProcessId(existIpqc.getItemId(), ctx.workstation().getProcessId()));
+        // 鎶ュ伐鏉ユ簮鐨勫伐搴忓凡鍦ㄥ垱寤烘椂鎸夋姤宸ュ伐搴忕‘瀹氾紝鏇存柊鏃朵繚鎸佷笉鍙橈紝閬垮厤琚矾绾挎帹瀵兼垚绌哄��
+        if (Objects.equals(existIpqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) {
+            updateObj.setProcessId(existIpqc.getProcessId());
+        } else {
+            updateObj.setProcessId(getProcessId(existIpqc.getItemId(), ctx.workstation().getProcessId()));
+        }
         ipqcMapper.updateById(updateObj);
     }
 
@@ -182,7 +244,10 @@
         validateIpqcCodeUnique(reqVO.getId(), reqVO.getCode());
         // 鏍¢獙宸ヤ綅銆佹娴嬩汉鍛樺瓨鍦�
         MesMdWorkstationDO workstation = workstationService.validateWorkstationExists(reqVO.getWorkstationId());
-        adminUserApi.validateUser(reqVO.getInspectorUserId());
+        // 鏍¢獙妫�娴嬩汉鍛樺瓨鍦紙闈炲繀濉紝鏈~鍐欐椂鐢卞垱寤洪�昏緫榛樿褰撳墠鐧诲綍浜猴級
+        if (reqVO.getInspectorUserId() != null) {
+            adminUserApi.validateUser(reqVO.getInspectorUserId());
+        }
         // 鏍¢獙宸ュ崟瀛樺湪
         MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
         if (reqVO.getProcessId() != null && ObjUtil.notEqual(workstation.getProcessId(), reqVO.getProcessId())) {
@@ -194,8 +259,9 @@
             task = taskService.validateTaskNotFinished(reqVO.getTaskId());
             validateTaskRelation(task, workstation, workOrder, reqVO);
         } else {
-            // 鏃犱换鍔℃椂锛宨temId 浠嶉渶涓庡伐鍗曚骇鍝佷竴鑷�
-            if (reqVO.getItemId() != null && ObjUtil.notEqual(reqVO.getItemId(), workOrder.getProductId())) {
+            // 鏃犱换鍔℃椂锛宨temId 浠嶉渶涓庡伐鍗曚骇鍝佷竴鑷达紙鎶ュ伐鏉ユ簮鐨勮仈浜у嚭鐗╂枡浠ヤ骇鍑烘槑缁嗚涓哄噯锛屼笉鍦ㄦ鏍¢獙锛�
+            if (!Objects.equals(reqVO.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)
+                    && reqVO.getItemId() != null && ObjUtil.notEqual(reqVO.getItemId(), workOrder.getProductId())) {
                 throw exception(PRO_WORK_ORDER_PRODUCT_MISMATCH);
             }
         }
@@ -215,7 +281,9 @@
             throw exception(PRO_TASK_ROUTE_PROCESS_MISMATCH);
         }
         // 鏍¢獙妫�楠岀墿鏂欎笌浠诲姟鐗╂枡涓�鑷达紙鏈変换鍔℃椂锛孖PQC 妫�楠岀殑鐗╂枡搴斾笌浠诲姟鍔犲伐鐨勭墿鏂欎竴鑷达級
-        if (reqVO.getItemId() != null && ObjUtil.notEqual(reqVO.getItemId(), task.getItemId())) {
+        // 鎶ュ伐鏉ユ簮鍏佽妫�楠岃仈浜у嚭鐗╂枡锛岀墿鏂欎互浜у嚭鏄庣粏琛屼负鍑嗭紝姝ゅ涓嶅弬涓庢牎楠�
+        if (!Objects.equals(reqVO.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)
+                && reqVO.getItemId() != null && ObjUtil.notEqual(reqVO.getItemId(), task.getItemId())) {
             throw exception(PRO_TASK_ITEM_MISMATCH);
         }
     }
@@ -224,13 +292,36 @@
     @Transactional(rollbackFor = Exception.class)
     public void finishIpqc(Long id) {
         // 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
-        MesQcIpqcDO ipqc = validateIpqcStatusPrepare(id);
+        MesQcIpqcDO ipqc = validateIpqcStatusPrepareForUpdate(id);
         // 1.2 鏍¢獙妫�娴嬬粨璁哄繀濉�
         if (ipqc.getCheckResult() == null) {
             throw exception(QC_IPQC_CHECK_RESULT_EMPTY);
         }
         // 1.3 鏍¢獙鑷冲皯瀛樺湪涓�鏉℃娴嬬粨鏋�
         indicatorResultService.validateIndicatorResultExistsByQcIdAndType(id, MesQcTypeEnum.IPQC.getType());
+
+        BigDecimal check = ipqc.getCheckQuantity();
+        BigDecimal qualified = ipqc.getQualifiedQuantity();
+        BigDecimal unqualified = ipqc.getUnqualifiedQuantity();
+        if (check == null || qualified == null || unqualified == null || check.signum() <= 0
+                || qualified.signum() < 0 || unqualified.signum() < 0
+                || check.compareTo(qualified.add(unqualified)) != 0) {
+            throw exception(QC_IPQC_QUANTITY_INVALID);
+        }
+        BigDecimal labor = ObjectUtil.defaultIfNull(ipqc.getLaborScrapQuantity(), BigDecimal.ZERO);
+        BigDecimal material = ObjectUtil.defaultIfNull(ipqc.getMaterialScrapQuantity(), BigDecimal.ZERO);
+        BigDecimal other = ObjectUtil.defaultIfNull(ipqc.getOtherScrapQuantity(), BigDecimal.ZERO);
+        if (labor.signum() < 0 || material.signum() < 0 || other.signum() < 0
+                || labor.add(material).add(other).compareTo(unqualified) > 0) {
+            throw exception(QC_IPQC_SCRAP_QUANTITY_INVALID);
+        }
+        if (Objects.equals(ipqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) {
+            if (ipqc.getSourceDocId() == null || ipqc.getSourceLineId() == null) throw exception(QC_IPQC_SOURCE_INCOMPLETE);
+            MesWmProductProduceLineDO line = produceLineMapper.selectByIdForUpdate(ipqc.getSourceLineId());
+            if (line == null || !Objects.equals(line.getFeedbackId(), ipqc.getSourceDocId())) throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
+            if (!Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())) throw exception(QC_IPQC_SOURCE_LINE_NOT_PENDING);
+            if (line.getQuantity() == null || check.compareTo(line.getQuantity()) != 0) throw exception(QC_IPQC_SOURCE_QUANTITY_INVALID);
+        }
 
         // 2. 鏇存柊鐘舵�佷负宸插畬鎴�
         ipqcMapper.updateById(new MesQcIpqcDO()
@@ -276,22 +367,11 @@
         Long sourceDocId = ipqc.getSourceDocId();
         Long sourceLineId = ipqc.getSourceLineId();
 
-        // 濡傛灉 IPQC 鍗曟病鏈夎缃潵婧愶紝灏濊瘯閫氳繃 taskId 鏌ユ壘鍏宠仈鐨勫緟妫�楠屾姤宸�
-        if (sourceDocId == null && ipqc.getTaskId() != null) {
-            MesProFeedbackDO feedback = feedbackService.getFeedbackListByTaskId(ipqc.getTaskId()).stream()
-                    .filter(f -> MesProFeedbackStatusEnum.UNCHECK.getStatus().equals(f.getStatus()))
-                    .findFirst().orElse(null);
-            if (feedback != null) {
-                sourceDocId = feedback.getId();
-                log.info("[writeBackSourceDoc] IPQC({}) 鏈缃潵婧愬崟鎹紝閫氳繃 taskId({}) 鎵惧埌寰呮楠屾姤宸�({})",
-                        ipqc.getId(), ipqc.getTaskId(), feedback.getId());
-            }
-        }
-
-        if (sourceDocId == null) {
-            log.warn("[writeBackSourceDoc] IPQC({}) 鏃犳硶纭畾鏉ユ簮鎶ュ伐锛岃烦杩囧洖鍐�", ipqc.getId());
+        if (ipqc.getSourceDocType() == null && sourceDocId == null && sourceLineId == null) {
             return;
         }
+        if (!Objects.equals(ipqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)
+                || sourceDocId == null || sourceLineId == null) throw exception(QC_IPQC_SOURCE_INCOMPLETE);
 
         // 2. 鍥炲啓鎶ュ伐
         feedbackService.updateProFeedbackWhenIpqcFinish(sourceDocId, sourceLineId,
@@ -306,7 +386,7 @@
     @Transactional(rollbackFor = Exception.class)
     public void deleteIpqc(Long id) {
         // 1. 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
-        validateIpqcStatusPrepare(id);
+        validateIpqcStatusPrepareForUpdate(id);
 
         // 2.1 鍒犻櫎涓昏〃
         ipqcMapper.deleteById(id);
@@ -325,18 +405,25 @@
         return ipqc;
     }
 
-    /**
-     * 鏍¢獙杩囩▼妫�楠屽崟瀛樺湪涓斾负鑽夌鐘舵��
-     *
-     * @param id 杩囩▼妫�楠屽崟 ID
-     * @return 杩囩▼妫�楠屽崟
-     */
-    private MesQcIpqcDO validateIpqcStatusPrepare(Long id) {
-        MesQcIpqcDO ipqc = validateIpqcExists(id);
-        if (ObjUtil.notEqual(ipqc.getStatus(), MesQcStatusEnum.DRAFT.getStatus())) {
-            throw exception(QC_IPQC_NOT_PREPARE);
+    private MesQcIpqcDO validateIpqcStatusPrepareForUpdate(Long id) {
+        // 涓庢姤宸ュ洖璋冧竴鑷达細鎶ュ伐 鈫� 浜у嚭琛� 鈫� 妫�楠屽崟锛岄伩鍏嶇浉浜掔瓑寰呫��
+        MesQcIpqcDO snapshot = validateIpqcExists(id);
+        if (Objects.equals(snapshot.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)
+                && snapshot.getSourceDocId() != null && snapshot.getSourceLineId() != null) {
+            lockFeedback(snapshot.getSourceDocId());
+            produceLineMapper.selectByIdForUpdate(snapshot.getSourceLineId());
         }
+        MesQcIpqcDO ipqc = ipqcMapper.selectByIdForUpdate(id);
+        if (ipqc == null) throw exception(QC_IPQC_NOT_EXISTS);
+        if (ObjUtil.notEqual(ipqc.getStatus(), MesQcStatusEnum.DRAFT.getStatus())) throw exception(QC_IPQC_NOT_PREPARE);
         return ipqc;
+    }
+
+    private MesProFeedbackDO lockFeedback(Long id) {
+        MesProFeedbackDO feedback = feedbackMapper.selectOne(new LambdaQueryWrapperX<MesProFeedbackDO>()
+                .eq(MesProFeedbackDO::getId, id).last("FOR UPDATE"));
+        if (feedback == null) throw exception(PRO_FEEDBACK_NOT_EXISTS);
+        return feedback;
     }
 
     private void validateIpqcCodeUnique(Long id, String code) {
@@ -349,19 +436,28 @@
         }
     }
 
-    private String validateAndGetSourceDocCode(Integer sourceDocType, Long sourceDocId, Long sourceLineId) {
-        if (sourceDocType == null || sourceDocId == null) {
-            return null;
+    /**
+     * 鏉ユ簮鍗曟嵁鏍¢獙涓婁笅鏂�
+     *
+     * @param code 鏉ユ簮鍗曟嵁缂栧彿
+     * @param line 鎶ュ伐鏉ユ簮鏃跺搴旂殑浜у嚭鏄庣粏琛岋紝鍏跺畠鏉ユ簮涓� null
+     */
+    private record SourceDocInfo(String code, MesWmProductProduceLineDO line) {}
+
+    private SourceDocInfo validateAndGetSourceDoc(Integer sourceDocType, Long sourceDocId, Long sourceLineId) {
+        if (sourceDocType == null && sourceDocId == null && sourceLineId == null) {
+            return new SourceDocInfo(null, null);
         }
+        if (sourceDocType == null || sourceDocId == null || sourceLineId == null) throw exception(QC_IPQC_SOURCE_INCOMPLETE);
         if (Objects.equals(sourceDocType, MesBizTypeConstants.PRO_FEEDBACK)) {
-            MesProFeedbackDO feedback = feedbackService.validateFeedbackExists(sourceDocId);
+            MesProFeedbackDO feedback = lockFeedback(sourceDocId);
             // 鏍¢獙 sourceLineId 蹇呭~
             if (sourceLineId == null) {
                 throw exception(QC_IPQC_SOURCE_LINE_REQUIRED);
             }
             // 鏍¢獙 sourceLineId 瀛樺湪锛屼笖灞炰簬璇ユ姤宸ョ殑浜у嚭琛�
-            MesWmProductProduceLineDO targetLine = productProduceLineService
-                    .validateProductProduceLineExists(sourceLineId);
+            MesWmProductProduceLineDO targetLine = produceLineMapper.selectByIdForUpdate(sourceLineId);
+            if (targetLine == null) throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
             if (ObjUtil.notEqual(targetLine.getFeedbackId(), sourceDocId)) {
                 throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG);
             }
@@ -369,7 +465,7 @@
             if (ObjUtil.notEqual(targetLine.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())) {
                 throw exception(QC_IPQC_SOURCE_LINE_NOT_PENDING);
             }
-            return feedback.getCode();
+            return new SourceDocInfo(feedback.getCode(), targetLine);
         }
         // 鏈煡鏉ユ簮绫诲瀷搴旀姤閿欙紝鑰屼笉鏄潤榛樺拷鐣�
         throw exception(QC_IPQC_SOURCE_DOC_TYPE_UNKNOWN);
@@ -525,4 +621,15 @@
                 + String.format("%03d", seq.incrementAndGet());
     }
 
+    private String getItemInfo(Long itemId) {
+        if (itemId == null) {
+            return "鏈煡鐗╂枡";
+        }
+        MesMdItemDO item = itemService.getItem(itemId);
+        if (item != null) {
+            return item.getCode() + "-" + item.getName();
+        }
+        return "鐗╂枡ID:" + itemId;
+    }
+
 }

--
Gitblit v1.9.3