From 87733eb3623593da247c051593d64b8ff9e1d3a4 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 06 十一月 2026 19:00:39 +0800
Subject: [PATCH] feat(crm,mes): 扩展客户字段与重构批次号生成逻辑

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java |  159 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 147 insertions(+), 12 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
index f9412cc..56d99e1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.mes.service.pro.scan;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventCreateReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventPageReqVO;
@@ -17,6 +19,7 @@
 import cn.iocoder.yudao.module.mes.enums.MesProScanEventStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.framework.qrcode.MesTraceCodeUtils;
 import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
@@ -30,9 +33,11 @@
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
@@ -61,13 +66,15 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public MesProScanEventDO createInbound(MesProScanEventCreateReqVO req) {
+        // 杩芥函浜岀淮鐮佸唴瀹规槸銆岃拷婧綉鍧�?code=鐮佸�笺�嶏紝鎵爜鏋篃鍙兘鐩翠紶鏁存缃戝潃锛屽厛缁熶竴鎻愬彇鐮佸��
+        String scanCode = MesTraceCodeUtils.extractCode(req.getBagCode());
         String scanType = (req.getScanType() == null || req.getScanType().isBlank()) ? SCAN_TYPE_BAG : req.getScanType();
         if (!List.of(SCAN_TYPE_BAG, SCAN_TYPE_PALLET, SCAN_TYPE_BATCH).contains(scanType)) {
             throw new ServiceException(400, "涓嶆敮鎸佺殑鎵爜绫诲瀷");
         }
         MesProScanEventDO existing = eventMapper.selectByEventIdForUpdate(req.getEventId());
         if (existing != null) {
-            boolean contentMatch = req.getBagCode().equals(existing.getBagCode())
+            boolean contentMatch = scanCode.equals(existing.getBagCode())
                     && Objects.equals(req.getDeviceCode(), existing.getDeviceCode())
                     && Objects.equals(req.getLineCode(), existing.getLineCode())
                     && Objects.equals(scanType, existing.getScanType())
@@ -82,7 +89,7 @@
             return existing;
         }
         MesProScanEventDO event = new MesProScanEventDO();
-        event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setScanType(scanType)
+        event.setEventId(req.getEventId()).setBagCode(scanCode).setScanType(scanType)
                 .setQuantity(req.getQuantity()).setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode())
                 .setRemark(req.getRemark()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId())
                 .setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now());
@@ -96,7 +103,7 @@
         Long bagCodeId = null;
         String bagCode = null;
         if (SCAN_TYPE_PALLET.equals(scanType)) {
-            MesProPalletDO pallet = palletMapper.selectByScanCodeForUpdate(req.getBagCode());
+            MesProPalletDO pallet = palletMapper.selectByScanCodeForUpdate(scanCode);
             if (pallet == null) return failed(event, "MES_SCAN_PALLET_NOT_EXISTS", "鎵樼洏鐮佷笉瀛樺湪");
             if (MesProPalletStatusEnum.CANCELED.getStatus().equals(pallet.getStatus()))
                 return failed(event, "MES_SCAN_PALLET_CANCELED", "鎵樼洏宸蹭綔搴燂紝涓嶅彲鍏ュ簱");
@@ -105,19 +112,24 @@
             if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
             batchId = batch.getId();
             targetId = pallet.getId();
+            event.setPalletId(pallet.getId())
+                    .setPalletCode(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()));
             quantity = BigDecimal.valueOf(bagCodeMapper.selectPendingInboundCountByPalletId(pallet.getId()));
         } else if (SCAN_TYPE_BATCH.equals(scanType)) {
-            batch = batchMapper.selectByScanCodeForUpdate(req.getBagCode());
+            batch = batchMapper.selectByScanCodeForUpdate(scanCode);
             if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
             batchId = batch.getId();
             targetId = batch.getId();
             quantity = BigDecimal.valueOf(bagCodeMapper.selectPendingInboundCountByBatchId(batch.getId()));
         } else {
-            MesProBagCodeDO bag = bagCodeMapper.selectByScanCodeForUpdate(req.getBagCode());
+            MesProBagCodeDO bag = bagCodeMapper.selectByScanCodeForUpdate(scanCode);
             if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "琚嬬爜涓嶅瓨鍦�");
             if (MesProBagCodeStatusEnum.CANCELED.getStatus().equals(bag.getStatus()))
                 return failed(event, "MES_SCAN_BAG_CANCELED", "琚嬬爜宸蹭綔搴燂紝涓嶅彲鍏ュ簱");
             event.setBagCodeId(bag.getId());
+            if (bag.getPalletId() != null) {
+                event.setPalletId(bag.getPalletId()).setPalletCode(bag.getPalletCode());
+            }
             bagCodeId = bag.getId();
             // 搴撳瓨娴佹按淇濇寔鍘熻拷婧爜涓鸿鑼冪爜锛屼笟鍔$爜浠呯敤浜庢煡鎵惧悓涓�琚嬶紝閬垮厤鍙岀爜鎷嗘垚涓や唤搴撳瓨銆�
             bagCode = bag.getCode();
@@ -132,7 +144,9 @@
             return failed(event, "MES_SCAN_BATCH_CANCELED", "鐢熶骇鎵规宸蹭綔搴燂紝涓嶅彲鍏ュ簱");
         if (quantity.signum() <= 0)
             return failed(event, "MES_SCAN_NO_PENDING_BAGS", "娌℃湁寰呭叆搴撶殑鏈夋晥琚嬬爜锛岃鍕块噸澶嶅叆搴�");
-        event.setBatchId(batchId).setBatchCode(batch.getCode()).setItemId(batch.getItemId()).setQuantity(quantity);
+        // 鎵规鏈ˉ褰曟寮忔壒娆″彿鏃跺洖閫�涓存椂鎵规鐮侊紝淇濊瘉浠讳綍鎵爜绫诲瀷鐨勪簨浠堕兘甯﹀嚭鎵规鐮�
+        event.setBatchId(batchId).setBatchCode(StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()))
+                .setItemId(batch.getItemId()).setQuantity(quantity);
         MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE);
         if (warehouse == null) return failed(event, "MES_SCAN_WIP_WAREHOUSE_NOT_EXISTS", "WIP铏氭嫙浠撲笉瀛樺湪");
         event.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId());
@@ -167,8 +181,111 @@
             return event;
         } catch (Exception ex) {
             log.error("[createInbound] 搴撳瓨浜嬪姟澶勭悊澶辫触锛宔ventId={}, bagCode={}, batchId={}, itemId={}",
-                    req.getEventId(), req.getBagCode(), batchId, batch.getItemId(), ex);
+                    req.getEventId(), scanCode, batchId, batch.getItemId(), ex);
             throw ex;
+        }
+    }
+
+    /**
+     * 涓烘壂鐮佷簨浠惰ˉ鍏呮墭鐩樼爜锛氭墭鐩樼爜浜嬩欢鎸夋壂鎻忓唴瀹瑰弽鏌ユ墭鐩橈紝琚嬬爜浜嬩欢鍙栨墍灞炴墭鐩橈紱
+     * 鎵规浜嬩欢鏁存壒鍙兘璺ㄥ涓墭鐩橈紝涓嶅綊灞炲崟涓�鎵樼洏锛屼繚鎸佷负绌恒��
+     * <p>
+     * 鎵樼洏鐮佷笉钀藉簱锛岃鍙栨椂瀹炴椂鍙嶆煡锛屼繚璇佸巻鍙蹭簨浠朵篃鑳藉睍绀恒��
+     */
+    private void fillPalletInfo(List<MesProScanEventDO> events) {
+        if (CollUtil.isEmpty(events)) {
+            return;
+        }
+        // 1. 鎵樼洏鐮佷簨浠讹細鎵弿鍐呭鍙兘鏄笟鍔$爜銆佹寮忕爜鎴栦复鏃剁爜锛岀粺涓�鍙嶆煡
+        List<String> palletScanCodes = events.stream()
+                .filter(event -> SCAN_TYPE_PALLET.equals(event.getScanType()) && StrUtil.isNotBlank(event.getBagCode()))
+                .map(MesProScanEventDO::getBagCode).distinct().toList();
+        Map<String, MesProPalletDO> palletByScanCode = new HashMap<>();
+        if (CollUtil.isNotEmpty(palletScanCodes)) {
+            for (MesProPalletDO pallet : palletMapper.selectListByScanCodes(palletScanCodes)) {
+                if (StrUtil.isNotBlank(pallet.getBusinessCode())) {
+                    palletByScanCode.put(pallet.getBusinessCode(), pallet);
+                }
+                if (StrUtil.isNotBlank(pallet.getCode())) {
+                    palletByScanCode.put(pallet.getCode(), pallet);
+                }
+                if (StrUtil.isNotBlank(pallet.getTempCode())) {
+                    palletByScanCode.put(pallet.getTempCode(), pallet);
+                }
+            }
+        }
+        // 2. 琚嬬爜浜嬩欢锛氭寜琚嬬爜缂栧彿鎴栫爜鍊煎弽鏌ヨ鐮侊紝鍐嶅彇鎵�灞炴墭鐩�
+        List<Long> bagIds = events.stream()
+                .filter(event -> SCAN_TYPE_BAG.equals(event.getScanType()))
+                .map(MesProScanEventDO::getBagCodeId).filter(Objects::nonNull).distinct().toList();
+        List<String> bagScanCodes = events.stream()
+                .filter(event -> SCAN_TYPE_BAG.equals(event.getScanType()) && StrUtil.isNotBlank(event.getBagCode()))
+                .map(MesProScanEventDO::getBagCode).distinct().toList();
+        Map<Long, MesProBagCodeDO> bagById = new HashMap<>();
+        Map<String, MesProBagCodeDO> bagByScanCode = new HashMap<>();
+        if (CollUtil.isNotEmpty(bagIds)) {
+            for (MesProBagCodeDO bag : bagCodeMapper.selectBatchIds(bagIds)) {
+                bagById.put(bag.getId(), bag);
+            }
+        }
+        if (CollUtil.isNotEmpty(bagScanCodes)) {
+            for (MesProBagCodeDO bag : bagCodeMapper.selectListByScanCodes(bagScanCodes)) {
+                bagByScanCode.putIfAbsent(bag.getCode(), bag);
+                if (StrUtil.isNotBlank(bag.getBusinessCode())) {
+                    bagByScanCode.putIfAbsent(bag.getBusinessCode(), bag);
+                }
+            }
+        }
+        // 3. 琚嬬爜鍐椾綑鎵樼洏鐮佷负绌烘椂锛屽洖鏌ユ墭鐩樺彇姝e紡鐮�/涓存椂鐮�
+        Set<Long> missingPalletIds = new HashSet<>();
+        for (MesProBagCodeDO bag : bagById.values()) {
+            if (bag.getPalletId() != null && StrUtil.isBlank(bag.getPalletCode())) {
+                missingPalletIds.add(bag.getPalletId());
+            }
+        }
+        for (MesProBagCodeDO bag : bagByScanCode.values()) {
+            if (bag.getPalletId() != null && StrUtil.isBlank(bag.getPalletCode())) {
+                missingPalletIds.add(bag.getPalletId());
+            }
+        }
+        Map<Long, MesProPalletDO> palletById = new HashMap<>();
+        if (CollUtil.isNotEmpty(missingPalletIds)) {
+            for (MesProPalletDO pallet : palletMapper.selectBatchIds(missingPalletIds)) {
+                palletById.put(pallet.getId(), pallet);
+            }
+        }
+        for (MesProScanEventDO event : events) {
+            if (StrUtil.isNotBlank(event.getPalletCode())) {
+                continue;
+            }
+            if (SCAN_TYPE_PALLET.equals(event.getScanType())) {
+                MesProPalletDO pallet = palletByScanCode.get(event.getBagCode());
+                if (pallet != null) {
+                    event.setPalletId(pallet.getId())
+                            .setPalletCode(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()));
+                }
+            } else if (SCAN_TYPE_BAG.equals(event.getScanType())) {
+                MesProBagCodeDO bag = event.getBagCodeId() != null
+                        ? bagById.get(event.getBagCodeId()) : bagByScanCode.get(event.getBagCode());
+                if (bag == null || bag.getPalletId() == null) {
+                    continue;
+                }
+                event.setPalletId(bag.getPalletId());
+                if (StrUtil.isNotBlank(bag.getPalletCode())) {
+                    event.setPalletCode(bag.getPalletCode());
+                } else {
+                    MesProPalletDO pallet = palletById.get(bag.getPalletId());
+                    if (pallet != null) {
+                        event.setPalletCode(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()));
+                    }
+                }
+            }
+        }
+    }
+
+    private void fillPalletInfo(MesProScanEventDO event) {
+        if (event != null) {
+            fillPalletInfo(List.of(event));
         }
     }
 
@@ -179,13 +296,31 @@
         return event;
     }
 
-    @Override public MesProScanEventDO getByEventId(String eventId) { return eventMapper.selectOne(MesProScanEventDO::getEventId, eventId); }
-    @Override public PageResult<MesProScanEventDO> getPage(MesProScanEventPageReqVO reqVO) { return eventMapper.selectPage(reqVO); }
-    @Override public MesProScanEventDO getLatest(String deviceCode) { return eventMapper.selectLatest(deviceCode); }
-    @Override public List<MesProScanEventDO> getByBatchId(Long batchId) { return eventMapper.selectListByBatchId(batchId); }
+    @Override public MesProScanEventDO getByEventId(String eventId) {
+        MesProScanEventDO event = eventMapper.selectOne(MesProScanEventDO::getEventId, eventId);
+        fillPalletInfo(event);
+        return event;
+    }
+    @Override public PageResult<MesProScanEventDO> getPage(MesProScanEventPageReqVO reqVO) {
+        PageResult<MesProScanEventDO> page = eventMapper.selectPage(reqVO);
+        fillPalletInfo(page.getList());
+        return page;
+    }
+    @Override public MesProScanEventDO getLatest(String deviceCode) {
+        MesProScanEventDO event = eventMapper.selectLatest(deviceCode);
+        fillPalletInfo(event);
+        return event;
+    }
+    @Override public List<MesProScanEventDO> getByBatchId(Long batchId) {
+        List<MesProScanEventDO> events = eventMapper.selectListByBatchId(batchId);
+        fillPalletInfo(events);
+        return events;
+    }
     @Override public Map<String, Object> getDashboard() {
         Map<String, Object> result = new HashMap<>();
-        result.put("latest", eventMapper.selectLatest(null));
+        MesProScanEventDO latest = eventMapper.selectLatest(null);
+        fillPalletInfo(latest);
+        result.put("latest", latest);
         result.put("total", eventMapper.selectCount(null));
         result.put("success", eventMapper.selectCount(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesProScanEventDO>().eq(MesProScanEventDO::getStatus, MesProScanEventStatusEnum.SUCCESS)));
         result.put("failed", eventMapper.selectCount(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesProScanEventDO>().eq(MesProScanEventDO::getStatus, MesProScanEventStatusEnum.FAILED)));

--
Gitblit v1.9.3