From eee03bbfea8b15d1a56ab63bd09a35c6c861c4cb Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 09 十一月 2026 13:01:08 +0800
Subject: [PATCH] feat(mes): 不合格品处置联动入库与生产订单

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ncr/MesQcNcrServiceImpl.java |  303 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 294 insertions(+), 9 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ncr/MesQcNcrServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ncr/MesQcNcrServiceImpl.java
index 1b9f291..3f3bb69 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ncr/MesQcNcrServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ncr/MesQcNcrServiceImpl.java
@@ -1,22 +1,49 @@
 package cn.iocoder.yudao.module.mes.service.qc.ncr;
 
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrDisposeReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrDisposeRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.qc.ncr.vo.MesQcNcrSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.miscreceipt.vo.MesWmMiscReceiptSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.miscreceipt.vo.line.MesWmMiscReceiptLineSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ncr.MesQcNcrDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ncr.MesQcNcrMapper;
+import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderTypeEnum;
 import cn.iocoder.yudao.module.mes.enums.qc.MesNcrDispositionEnum;
 import cn.iocoder.yudao.module.mes.enums.qc.MesNcrStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscReceiptTypeEnum;
+import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
+import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
 import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
 import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService;
 import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
 import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService;
+import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
+import cn.iocoder.yudao.module.mes.service.wm.miscreceipt.MesWmMiscReceiptLineService;
+import cn.iocoder.yudao.module.mes.service.wm.miscreceipt.MesWmMiscReceiptService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
 import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
@@ -24,6 +51,7 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Map;
@@ -82,6 +110,42 @@
     @Resource
     @Lazy
     private MesQcRqcService rqcService;
+
+    @Resource
+    @Lazy
+    private MesWmMiscReceiptService miscReceiptService;
+    @Resource
+    @Lazy
+    private MesWmMiscReceiptLineService miscReceiptLineService;
+    @Resource
+    @Lazy
+    private MesWmWarehouseService warehouseService;
+    @Resource
+    @Lazy
+    private MesWmWarehouseLocationService warehouseLocationService;
+    @Resource
+    @Lazy
+    private MesWmWarehouseAreaService warehouseAreaService;
+    @Resource
+    @Lazy
+    private MesWmBatchService batchService;
+    @Resource
+    @Lazy
+    private MesProWorkOrderService workOrderService;
+    @Resource
+    @Lazy
+    private MesMdmItemService mdmItemService;
+    @Resource
+    @Lazy
+    private MesMdItemService mesItemService;
+    @Resource
+    @Lazy
+    private MesMdAutoCodeRecordService autoCodeRecordService;
+
+    /**
+     * 鏉傞」鍏ュ簱鍗曟潵婧愬崟鎹被鍨嬶細涓嶅悎鏍煎搧澶勭悊鍗�
+     */
+    private static final String MISC_RECEIPT_SOURCE_TYPE_NCR = "QC_NCR";
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -150,24 +214,245 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void disposeNcr(Long id, Integer disposition, Long handlerUserId, String handleResult) {
+    public MesQcNcrDisposeRespVO disposeNcr(MesQcNcrDisposeReqVO disposeReqVO) {
         // 1. 鏍¢獙瀛樺湪 + 宸茶瘎瀹★紙瀹℃壒閫氳繃锛夌姸鎬�
-        MesQcNcrDO ncr = validateNcrExists(id);
+        MesQcNcrDO ncr = validateNcrExists(disposeReqVO.getId());
         if (!MesNcrStatusEnum.REVIEWED.getStatus().equals(ncr.getStatus())) {
             throw exception(QC_NCR_DISPOSE_STATUS_INVALID, ncr.getCode(), resolveStatusName(ncr.getStatus()));
         }
         // 2. 澶勭疆鏂瑰紡蹇呭~锛屼笖蹇呴』鏄悎娉曟灇涓惧��
-        validateDisposition(disposition);
+        validateDisposition(disposeReqVO.getDisposition());
+        // 3. 涓嶅悎鏍兼暟閲忓繀椤诲ぇ浜� 0锛屽惁鍒欐棤娉曠敓鎴愬叆搴撳崟 / 鐢熶骇璁㈠崟
+        if (ncr.getUnqualifiedQuantity() == null
+                || ncr.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+            throw exception(QC_NCR_DISPOSE_QUANTITY_INVALID, ncr.getUnqualifiedQuantity());
+        }
 
-        // 3. 鏇存柊澶勭疆淇℃伅锛堝缃柟寮忎互鏈澶勭疆閫夋嫨涓哄噯骞惰惤搴擄級
-        // TODO: WM 妯″潡闆嗘垚 鈥� 澶勭疆涓洪��璐ф椂瑙﹀彂渚涘簲鍟嗛��璐э紝澶勭疆涓烘姤搴熸椂瑙﹀彂鏉傞」鍑哄簱
+        // 4. 鎸夊缃柟寮忚仈鍔ㄧ敓鎴愪笟鍔″崟鎹�
+        MesQcNcrDisposeRespVO respVO;
+        if (Objects.equals(MesNcrDispositionEnum.CONCESSION.getType(), disposeReqVO.getDisposition())
+                || Objects.equals(MesNcrDispositionEnum.SCRAP.getType(), disposeReqVO.getDisposition())) {
+            // 璁╂鏀捐 / 鎶ュ簾锛氱敓鎴愭潅椤瑰叆搴撳崟骞惰嚜鍔ㄥ畬鎴愬叆搴�
+            respVO = createMiscReceiptForDispose(ncr, disposeReqVO);
+        } else {
+            // 杩斿伐 / 杩斾慨锛氱敓鎴愯嚜琛岀敓浜х被鍨嬬殑鐢熶骇璁㈠崟
+            respVO = createReworkWorkOrderForDispose(ncr, disposeReqVO);
+        }
+
+        // 5. 鏇存柊澶勭疆淇℃伅锛堝缃柟寮忎互鏈澶勭疆閫夋嫨涓哄噯骞惰惤搴擄級
         ncrMapper.updateById(new MesQcNcrDO()
-                .setId(id)
-                .setDisposition(disposition)
-                .setHandlerUserId(handlerUserId)
+                .setId(ncr.getId())
+                .setDisposition(disposeReqVO.getDisposition())
+                .setHandlerUserId(disposeReqVO.getHandlerUserId())
                 .setHandleDate(LocalDateTime.now())
-                .setHandleResult(handleResult)
+                .setHandleResult(disposeReqVO.getHandleResult())
                 .setStatus(MesNcrStatusEnum.DISPOSED.getStatus()));
+        return respVO;
+    }
+
+    /**
+     * 璁╂鏀捐 / 鎶ュ簾锛氱敓鎴愭潅椤瑰叆搴撳崟锛岃嚜鍔ㄦ彁浜ゅ苟瀹屾垚鍏ュ簱
+     */
+    private MesQcNcrDisposeRespVO createMiscReceiptForDispose(MesQcNcrDO ncr, MesQcNcrDisposeReqVO reqVO) {
+        boolean scrap = Objects.equals(MesNcrDispositionEnum.SCRAP.getType(), reqVO.getDisposition());
+        String dispositionName = scrap ? MesNcrDispositionEnum.SCRAP.getName() : MesNcrDispositionEnum.CONCESSION.getName();
+        MesWmMiscReceiptTypeEnum receiptType = scrap
+                ? MesWmMiscReceiptTypeEnum.SCRAP : MesWmMiscReceiptTypeEnum.CONCESSION;
+
+        // 4.1 鏍¢獙鍏ュ簱浠撳簱 / 搴撳尯 / 搴撲綅
+        MesMdmItemDO item = mdmItemService.validateItemExists(ncr.getItemId());
+        if (reqVO.getWarehouseId() == null || reqVO.getLocationId() == null || reqVO.getAreaId() == null) {
+            throw new ServiceException(QC_NCR_DISPOSE_STORAGE_REQUIRED.getCode(),
+                    String.format("澶勭疆鏂瑰紡[%s]闇�瑕佸叆搴撳埌鎸囧畾搴撲綅锛氬綋鍓嶄粨搴揫%s]銆佸簱鍖篬%s]銆佸簱浣峓%s]鏈�夊叏锛�"
+                                    + "璇峰洖鍒板缃脊绐楄ˉ閫夌己澶遍」鍚庨噸鏂版彁浜�",
+                            dispositionName, resolveWarehouseName(reqVO.getWarehouseId()),
+                            resolveLocationName(reqVO.getLocationId()), resolveAreaName(reqVO.getAreaId())));
+        }
+        try {
+            warehouseAreaService.validateWarehouseAreaExists(
+                    reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId());
+        } catch (ServiceException ex) {
+            throw new ServiceException(QC_NCR_DISPOSE_STORAGE_DISABLED.getCode(),
+                    String.format("澶勭疆鏂瑰紡[%s]鎵�閫夊叆搴撳簱浣嶆牎楠屽け璐ワ細浠撳簱[%s]銆佸簱鍖篬%s]銆佸簱浣峓%s]銆傚師鍥狅細%s锛�"
+                                    + "璇峰洖鍒板缃脊绐楅噸鏂伴�夋嫨浠撳簱/搴撳尯/搴撲綅",
+                            dispositionName, resolveWarehouseName(reqVO.getWarehouseId()),
+                            resolveLocationName(reqVO.getLocationId()), resolveAreaName(reqVO.getAreaId()),
+                            ex.getMessage()));
+        }
+
+        // 4.2 鎵规绠$悊鐨勭墿鏂欙細鎵规鍙峰繀濉紝涓嶅瓨鍦ㄦ椂鑷姩鍒涘缓鎵规
+        String batchCode = StrUtil.trimToNull(reqVO.getBatchCode());
+        if (Boolean.TRUE.equals(item.getIsBatchManaged())) {
+            if (batchCode == null) {
+                throw new ServiceException(QC_NCR_DISPOSE_BATCH_REQUIRED.getCode(),
+                        String.format("鐗╂枡[%s]鍚敤浜嗘壒娆$鐞嗭紝澶勭疆鏂瑰紡[%s]鍏ュ簱鏃跺繀椤诲~鍐欐壒娆″彿锛�"
+                                + "璇峰湪澶勭疆寮圭獥鐨刐鎵规鍙穄涓~鍐欏悗閲嶈瘯", buildItemLabel(item), dispositionName));
+            }
+            MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO();
+            batchReqVO.setItemId(ncr.getItemId());
+            batchReqVO.setBatchCode(batchCode);
+            batchReqVO.setReceiptDate(LocalDateTime.now());
+            try {
+                batchService.getOrGenerateBatchCode(batchReqVO);
+            } catch (ServiceException ex) {
+                throw new ServiceException(ex.getCode(),
+                        String.format("涓虹墿鏂橻%s]鍑嗗鎵规[%s]澶辫触锛�%s锛涜琛ュ厖鎵规淇℃伅鍚庨噸鏂板缃�",
+                                buildItemLabel(item), batchCode, ex.getMessage()));
+            }
+        }
+
+        // 4.3 鍒涘缓鏉傞」鍏ュ簱鍗�
+        String receiptCode = autoCodeRecordService.generateAutoCode(
+                MesMdAutoCodeRuleCodeEnum.WM_MISC_RECEIPT_CODE.getCode());
+        String receiptName = String.format("%s鍏ュ簱鍗�-%s", dispositionName, ncr.getCode());
+        MesWmMiscReceiptSaveReqVO receiptReqVO = new MesWmMiscReceiptSaveReqVO();
+        receiptReqVO.setCode(receiptCode);
+        receiptReqVO.setName(receiptName);
+        receiptReqVO.setType(receiptType.getType());
+        receiptReqVO.setSourceDocType(MISC_RECEIPT_SOURCE_TYPE_NCR);
+        receiptReqVO.setSourceDocId(ncr.getId());
+        receiptReqVO.setSourceDocCode(ncr.getCode());
+        receiptReqVO.setReceiptDate(LocalDateTime.now());
+        receiptReqVO.setRemark(String.format("鐢变笉鍚堟牸鍝佸鐞嗗崟[%s]澶勭疆涓篬%s]鑷姩鐢熸垚骞跺畬鎴愬叆搴�",
+                ncr.getCode(), dispositionName));
+        Long receiptId = miscReceiptService.createMiscReceipt(receiptReqVO);
+
+        // 4.4 鍒涘缓鍏ュ簱琛岋紙鍚岀墿鏂� / 涓嶅悎鏍兼暟閲� / 鐩爣搴撲綅 / 鎵规鍙凤級
+        MesWmMiscReceiptLineSaveReqVO lineReqVO = new MesWmMiscReceiptLineSaveReqVO();
+        lineReqVO.setReceiptId(receiptId);
+        lineReqVO.setItemId(ncr.getItemId());
+        lineReqVO.setQuantity(ncr.getUnqualifiedQuantity());
+        lineReqVO.setBatchCode(batchCode);
+        lineReqVO.setWarehouseId(reqVO.getWarehouseId());
+        lineReqVO.setLocationId(reqVO.getLocationId());
+        lineReqVO.setAreaId(reqVO.getAreaId());
+        lineReqVO.setRemark(String.format("鏉ユ簮涓嶅悎鏍煎搧澶勭悊鍗昜%s]", ncr.getCode()));
+        miscReceiptLineService.createMiscReceiptLine(lineReqVO);
+
+        // 4.5 鑷姩鎻愪氦骞跺畬鎴愬叆搴擄紙澧炲姞搴撳瓨 + 璁板綍娴佹按锛�
+        miscReceiptService.submitMiscReceipt(receiptId);
+        miscReceiptService.finishMiscReceipt(receiptId);
+
+        MesQcNcrDisposeRespVO respVO = new MesQcNcrDisposeRespVO();
+        respVO.setDisposition(reqVO.getDisposition());
+        respVO.setDocType("MISC_RECEIPT");
+        respVO.setDocId(receiptId);
+        respVO.setDocCode(receiptCode);
+        respVO.setDocName(receiptName);
+        respVO.setMessage(String.format("宸茬敓鎴�%s骞跺畬鎴愬叆搴擄紝鍏ュ簱鍗曞彿[%s]", receiptName, receiptCode));
+        return respVO;
+    }
+
+    /**
+     * 杩斿伐 / 杩斾慨锛氱敓鎴愯嚜琛岀敓浜х被鍨嬬殑鐢熶骇璁㈠崟锛堣崏绋挎�侊紝BOM/鏉$爜鑷姩鐢熸垚锛屽伐鑹鸿矾绾夸汉宸ヨˉ鍏咃級
+     */
+    private MesQcNcrDisposeRespVO createReworkWorkOrderForDispose(MesQcNcrDO ncr, MesQcNcrDisposeReqVO reqVO) {
+        boolean rework = Objects.equals(MesNcrDispositionEnum.REWORK.getType(), reqVO.getDisposition());
+        String dispositionName = rework ? MesNcrDispositionEnum.REWORK.getName() : MesNcrDispositionEnum.REPAIR.getName();
+
+        // 鐢熶骇璁㈠崟鐨勪骇鍝佹槸 MES 浜у搧涓绘暟鎹紙mes_md_item锛夛紝NCR 瀛樼殑鏄� MDM 鐗╂枡锛坢dm_item锛夛紝闇�鍏堟槧灏�
+        MesMdItemDO product = mesItemService.getItemByMdmItemId(ncr.getItemId());
+        if (product == null) {
+            // 鍏煎鍘嗗彶鏁版嵁锛歁ES 浜у搧涓� MDM 鐗╂枡涓婚敭涓�鑷存椂鐩存帴鎸変富閿彇
+            product = mesItemService.getItem(ncr.getItemId());
+        }
+        if (product == null) {
+            MesMdmItemDO mdmItem = mdmItemService.getItem(ncr.getItemId());
+            throw new ServiceException(QC_NCR_DISPOSE_PRODUCT_NOT_EXISTS.getCode(),
+                    String.format("鐗╂枡[%s]鍦� MES 浜у搧涓绘暟鎹腑涓嶅瓨鍦紙MDM 鐗╂枡 ID=%s锛夛紝鏃犳硶鐢熸垚杩斿伐/杩斾慨鐢熶骇璁㈠崟锛�"
+                                    + "璇峰厛鍦╗鐗╂枡浜у搧]涓淮鎶よ浜у搧鍚庡啀澶勭疆",
+                            mdmItem != null ? buildItemLabel(mdmItem) : "鏈煡鐗╂枡", ncr.getItemId()));
+        }
+
+        String workOrderCode = autoCodeRecordService.generateAutoCode(
+                MesMdAutoCodeRuleCodeEnum.PRO_WORK_ORDER_CODE.getCode());
+        String workOrderName = String.format("%s鍗�-%s", dispositionName, ncr.getCode());
+        MesProWorkOrderSaveReqVO workOrderReqVO = new MesProWorkOrderSaveReqVO();
+        workOrderReqVO.setCode(workOrderCode);
+        workOrderReqVO.setName(workOrderName);
+        workOrderReqVO.setType(MesProWorkOrderTypeEnum.SELF.getType());
+        workOrderReqVO.setOrderSourceType(MesProWorkOrderSourceTypeEnum.STORE.getType());
+        workOrderReqVO.setOrderSourceCode(ncr.getCode());
+        workOrderReqVO.setProductId(product.getId());
+        workOrderReqVO.setQuantity(ncr.getUnqualifiedQuantity());
+        workOrderReqVO.setRequestDate(LocalDateTime.now());
+        workOrderReqVO.setRemark(String.format("鐢变笉鍚堟牸鍝佸鐞嗗崟[%s]澶勭疆涓篬%s]鑷姩鐢熸垚锛岃琛ュ厖宸ヨ壓璺嚎鍚庝笅杈�",
+                ncr.getCode(), dispositionName));
+        // 鍑鸿揣妫�楠屾潵婧愮殑 NCR锛氬甫涓婂鎴凤紝婊¤冻浜у搧鎵规閰嶇疆锛坈lientFlag锛夊瀹㈡埛蹇呭~鐨勮姹�
+        Long clientId = resolveSourceClientId(ncr);
+        if (clientId != null) {
+            workOrderReqVO.setClientId(clientId);
+        }
+        Long workOrderId = workOrderService.createWorkOrder(workOrderReqVO);
+
+        MesQcNcrDisposeRespVO respVO = new MesQcNcrDisposeRespVO();
+        respVO.setDisposition(reqVO.getDisposition());
+        respVO.setDocType("WORK_ORDER");
+        respVO.setDocId(workOrderId);
+        respVO.setDocCode(workOrderCode);
+        respVO.setDocName(workOrderName);
+        respVO.setMessage(String.format("宸茬敓鎴�%s[%s]锛岃鍒扮敓浜ц鍗曚腑琛ュ厖宸ヨ壓璺嚎鍚庝笅杈�", workOrderName, workOrderCode));
+        return respVO;
+    }
+
+    /**
+     * 鍙栨潵婧愭楠屽崟涓婄殑瀹㈡埛锛氫粎鍑鸿揣妫�楠岋紙OQC锛夊甫鏈夊鎴蜂俊鎭�
+     */
+    private Long resolveSourceClientId(MesQcNcrDO ncr) {
+        if (!Objects.equals(MesQcTypeEnum.OQC.getType(), ncr.getQcType()) || ncr.getQcId() == null) {
+            return null;
+        }
+        MesQcOqcDO oqc = oqcService.getOqc(ncr.getQcId());
+        return oqc != null ? oqc.getClientId() : null;
+    }
+
+    /**
+     * 鐗╂枡灞曠ず锛氱紪鐮� + 鍚嶇О
+     */
+    private String buildItemLabel(MesMdmItemDO item) {
+        if (item == null) {
+            return "鏈煡鐗╂枡";
+        }
+        String code = StrUtil.blankToDefault(item.getCode(), "");
+        String name = StrUtil.blankToDefault(item.getName(), "");
+        String label = (code + " " + name).trim();
+        return label.isEmpty() ? "ID=" + item.getId() : label;
+    }
+
+    /**
+     * 浠撳簱鍚嶇О锛岃В鏋愬け璐ュ洖閫�涓哄彲璇� ID
+     */
+    private String resolveWarehouseName(Long warehouseId) {
+        if (warehouseId == null) {
+            return "鏈�夋嫨";
+        }
+        MesWmWarehouseDO warehouse = warehouseService.getWarehouse(warehouseId);
+        return warehouse != null && StrUtil.isNotBlank(warehouse.getName())
+                ? warehouse.getName() : "ID=" + warehouseId;
+    }
+
+    /**
+     * 搴撳尯鍚嶇О锛岃В鏋愬け璐ュ洖閫�涓哄彲璇� ID
+     */
+    private String resolveLocationName(Long locationId) {
+        if (locationId == null) {
+            return "鏈�夋嫨";
+        }
+        MesWmWarehouseLocationDO location = warehouseLocationService.getWarehouseLocation(locationId);
+        return location != null && StrUtil.isNotBlank(location.getName())
+                ? location.getName() : "ID=" + locationId;
+    }
+
+    /**
+     * 搴撲綅鍚嶇О锛岃В鏋愬け璐ュ洖閫�涓哄彲璇� ID
+     */
+    private String resolveAreaName(Long areaId) {
+        if (areaId == null) {
+            return "鏈�夋嫨";
+        }
+        MesWmWarehouseAreaDO area = warehouseAreaService.getWarehouseArea(areaId);
+        return area != null && StrUtil.isNotBlank(area.getName())
+                ? area.getName() : "ID=" + areaId;
     }
 
     @Override

--
Gitblit v1.9.3