From 476d70b2f294f36a9dbd8d0c3cf5d1b75ba34c66 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 24 八月 2026 09:12:29 +0800
Subject: [PATCH] feat(mes): 新增包装袋型管理和托盘自动生成功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 157 insertions(+), 13 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
index 3ac2f9d..8966276 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/bagcode/MesProBagCodeServiceImpl.java
@@ -6,14 +6,22 @@
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceItemRespVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeReplaceDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeReplaceMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
 import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
@@ -24,7 +32,9 @@
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -43,15 +53,19 @@
     private MesProBagCodeMapper bagCodeMapper;
     @Resource
     private MesProBatchMapper batchMapper;
+    @Resource
+    private MesProBagCodeReplaceMapper replaceMapper;
+    @Resource
+    private MesProPalletMapper palletMapper;
 
     @Resource
     private MesProPalletService palletService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String generateBagCodes(MesProBagCodeGenerateReqVO generateReqVO) {
+    public MesProBagCodeGenerateRespVO generateBagCodes(MesProBagCodeGenerateReqVO generateReqVO) {
         // 1. 鏍¢獙鎵规瀛樺湪涓斿浜庣敓浜т腑鐘舵��
-        MesProBatchDO batch = batchMapper.selectById(generateReqVO.getBatchId());
+        MesProBatchDO batch = batchMapper.selectByIdForUpdate(generateReqVO.getBatchId());
         if (batch == null) {
             throw exception(PRO_BATCH_NOT_EXISTS);
         }
@@ -85,7 +99,121 @@
         batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
                 .setBagQuantity((batch.getBagQuantity() == null ? 0 : batch.getBagQuantity())
                         + generateReqVO.getCount()));
-        return uuid;
+        return new MesProBagCodeGenerateRespVO()
+                .setUuid(uuid)
+                .setAutoPallets(palletService.autoCreatePallets(batch.getId()));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public MesProBagCodeReplaceRespVO replaceBagCodes(MesProBagCodeReplaceReqVO replaceReqVO) {
+        MesProBatchDO batch = batchMapper.selectByIdForUpdate(replaceReqVO.getBatchId());
+        if (batch == null) {
+            throw exception(PRO_BATCH_NOT_EXISTS);
+        }
+        if (!MesProBatchStatusEnum.PRODUCING.getStatus().equals(batch.getStatus())
+                && !MesProBatchStatusEnum.FINISHED.getStatus().equals(batch.getStatus())) {
+            throw exception(PRO_BAG_CODE_REPLACE_BATCH_STATUS_INVALID);
+        }
+
+        List<Long> oldIds = replaceReqVO.getOldIds().stream()
+                .distinct().sorted().toList();
+        List<MesProBagCodeDO> oldBagCodes = bagCodeMapper.selectListByIdsForUpdate(oldIds);
+        if (oldBagCodes.size() != oldIds.size()) {
+            throw exception(PRO_BAG_CODE_NOT_EXISTS);
+        }
+        for (MesProBagCodeDO oldBagCode : oldBagCodes) {
+            if (!batch.getId().equals(oldBagCode.getBatchId())) {
+                throw exception(PRO_BAG_CODE_REPLACE_BATCH_MISMATCH);
+            }
+            if (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(oldBagCode.getStatus())
+                    && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(oldBagCode.getStatus())) {
+                throw exception(PRO_BAG_CODE_REPLACE_STATUS_INVALID);
+            }
+            if (replaceMapper.selectByOldBagCodeId(oldBagCode.getId()) != null) {
+                throw exception(PRO_BAG_CODE_REPLACE_ALREADY_REPLACED);
+            }
+        }
+
+        Map<Long, MesProPalletDO> palletMap = new LinkedHashMap<>();
+        oldBagCodes.stream().map(MesProBagCodeDO::getPalletId).filter(id -> id != null)
+                .distinct().sorted().forEach(palletId -> {
+                    MesProPalletDO pallet = palletMapper.selectByIdForUpdate(palletId);
+                    if (pallet == null || !MesProPalletStatusEnum.IN_USE.getStatus().equals(pallet.getStatus())) {
+                        throw exception(PRO_BAG_CODE_REPLACE_PALLET_INVALID);
+                    }
+                    palletMap.put(palletId, pallet);
+                });
+
+        String replaceUuid = IdUtil.fastSimpleUUID();
+        LocalDateTime replaceTime = LocalDateTime.now();
+        int startNo = bagCodeMapper.selectMaxBagNo(batch.getId()) + 1;
+        List<MesProBagCodeDO> newBagCodes = new ArrayList<>(oldBagCodes.size());
+        List<MesProBagCodeReplaceDO> replacements = new ArrayList<>(oldBagCodes.size());
+        List<MesProBagCodeReplaceItemRespVO> items = new ArrayList<>(oldBagCodes.size());
+        for (int i = 0; i < oldBagCodes.size(); i++) {
+            MesProBagCodeDO oldBagCode = oldBagCodes.get(i);
+            if (bagCodeMapper.cancelById(oldBagCode.getId(), oldBagCode.getStatus(),
+                    MesProBagCodeStatusEnum.CANCELED.getStatus(), replaceTime, replaceReqVO.getReason()) != 1) {
+                throw exception(PRO_BAG_CODE_REPLACE_STATUS_INVALID);
+            }
+            int newBagNo = startNo + i;
+            MesProPalletDO pallet = oldBagCode.getPalletId() == null ? null : palletMap.get(oldBagCode.getPalletId());
+            MesProBagCodeDO newBagCode = new MesProBagCodeDO()
+                    .setUuid(replaceUuid)
+                    .setCode(batch.getCode() + "-" + StrUtil.padPre(String.valueOf(newBagNo), 4, '0'))
+                    .setBagNo(newBagNo)
+                    .setBatchId(batch.getId())
+                    .setBatchCode(batch.getCode())
+                    .setPalletId(pallet == null ? null : pallet.getId())
+                    .setPalletCode(pallet == null ? null : pallet.getCode())
+                    .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus())
+                    .setRemark(replaceReqVO.getReason());
+            newBagCodes.add(newBagCode);
+
+            replacements.add(new MesProBagCodeReplaceDO()
+                    .setReplaceUuid(replaceUuid)
+                    .setBatchId(batch.getId())
+                    .setBatchCode(batch.getCode())
+                    .setOldBagCodeId(oldBagCode.getId())
+                    .setOldCode(oldBagCode.getCode())
+                    .setOldBagNo(oldBagCode.getBagNo())
+                    .setOldStatus(oldBagCode.getStatus())
+                    .setOldPalletId(oldBagCode.getPalletId())
+                    .setOldPalletCode(oldBagCode.getPalletCode())
+                    .setNewCode(newBagCode.getCode())
+                    .setNewBagNo(newBagNo)
+                    .setReason(replaceReqVO.getReason())
+                    .setReplaceTime(replaceTime));
+            items.add(new MesProBagCodeReplaceItemRespVO()
+                    .setOldBagCodeId(oldBagCode.getId())
+                    .setOldCode(oldBagCode.getCode())
+                    .setOldBagNo(oldBagCode.getBagNo())
+                    .setOldStatus(oldBagCode.getStatus())
+                    .setOldPalletId(oldBagCode.getPalletId())
+                    .setOldPalletCode(oldBagCode.getPalletCode())
+                    .setNewCode(newBagCode.getCode())
+                    .setNewBagNo(newBagNo)
+                    .setNewPalletId(newBagCode.getPalletId())
+                    .setNewPalletCode(newBagCode.getPalletCode())
+                    .setReason(replaceReqVO.getReason())
+                    .setReplaceTime(replaceTime));
+        }
+        bagCodeMapper.insertBatch(newBagCodes);
+        for (int i = 0; i < replacements.size(); i++) {
+            replacements.get(i).setNewBagCodeId(newBagCodes.get(i).getId());
+            items.get(i).setNewBagCodeId(newBagCodes.get(i).getId());
+        }
+        replaceMapper.insertBatch(replacements);
+        batchMapper.updateById(new MesProBatchDO().setId(batch.getId())
+                .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId())));
+
+        return new MesProBagCodeReplaceRespVO()
+                .setReplaceUuid(replaceUuid)
+                .setBatchId(batch.getId())
+                .setBatchCode(batch.getCode())
+                .setCount(newBagCodes.size())
+                .setItems(items);
     }
 
     @Override
@@ -117,10 +245,13 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void bindPallet(MesProBagCodeBindReqVO bindReqVO) {
-        // 1. 鏍¢獙鎵樼洏瀛樺湪
-        MesProPalletDO pallet = palletService.validatePalletExists(bindReqVO.getPalletId());
-        // 2. 鏍¢獙琚嬬爜
-        List<MesProBagCodeDO> bagCodes = validateBagCodesForBind(bindReqVO.getIds(), pallet);
+        // 1. 閿佸畾鎵樼洏锛岄伩鍏嶄笌鑷姩褰掗泦骞跺彂淇敼琚嬫暟
+        MesProPalletDO pallet = palletMapper.selectByIdForUpdate(bindReqVO.getPalletId());
+        if (pallet == null) {
+            throw exception(PRO_PALLET_NOT_EXISTS);
+        }
+        // 2. 閿佸畾骞舵牎楠岃鐮�
+        List<MesProBagCodeDO> bagCodes = validateBagCodesForBind(bindReqVO.getIds(), pallet, true);
         // 3. 鏍¢獙涓嶈秴杩囨墭鐩樺彲瑁呰鏁�
         int currentCount = pallet.getBagCount() == null ? 0 : pallet.getBagCount();
         if (pallet.getCapacity() != null && pallet.getCapacity() > 0
@@ -135,10 +266,13 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void unbindPallet(MesProBagCodeBindReqVO bindReqVO) {
-        // 1. 鏍¢獙鎵樼洏瀛樺湪
-        MesProPalletDO pallet = palletService.validatePalletExists(bindReqVO.getPalletId());
-        // 2. 鏍¢獙琚嬬爜鍧囩粦瀹氬湪褰撳墠鎵樼洏涓�
-        List<MesProBagCodeDO> bagCodes = bagCodeMapper.selectListByIds(bindReqVO.getIds());
+        // 1. 閿佸畾鎵樼洏锛岄伩鍏嶄笌鑷姩褰掗泦骞跺彂淇敼琚嬫暟
+        MesProPalletDO pallet = palletMapper.selectByIdForUpdate(bindReqVO.getPalletId());
+        if (pallet == null) {
+            throw exception(PRO_PALLET_NOT_EXISTS);
+        }
+        // 2. 閿佸畾骞舵牎楠岃鐮佸潎缁戝畾鍦ㄥ綋鍓嶆墭鐩樹笂
+        List<MesProBagCodeDO> bagCodes = bagCodeMapper.selectListByIdsForUpdate(bindReqVO.getIds());
         if (bagCodes.size() != bindReqVO.getIds().size()) {
             throw exception(PRO_BAG_CODE_NOT_EXISTS);
         }
@@ -180,6 +314,16 @@
     }
 
     @Override
+    public MesProBagCodeReplaceDO getReplacementByOldBagCodeId(Long oldBagCodeId) {
+        return replaceMapper.selectByOldBagCodeId(oldBagCodeId);
+    }
+
+    @Override
+    public MesProBagCodeReplaceDO getReplacementByNewBagCodeId(Long newBagCodeId) {
+        return replaceMapper.selectByNewBagCodeId(newBagCodeId);
+    }
+
+    @Override
     public PageResult<MesProBagCodeDO> getBagCodePage(MesProBagCodePageReqVO pageReqVO) {
         return bagCodeMapper.selectPage(pageReqVO);
     }
@@ -204,8 +348,8 @@
     /**
      * 鏍¢獙寰呯粦瀹氱殑琚嬬爜锛氬瓨鍦ㄣ�佷笌鎵樼洏鍚屾壒娆°�佹湭缁戝畾杩囨墭鐩樸�佺姸鎬佹湁鏁堬紙宸茬敓鎴�/宸插鍑哄嵃鍒凤級
      */
-    private List<MesProBagCodeDO> validateBagCodesForBind(List<Long> ids, MesProPalletDO pallet) {
-        List<MesProBagCodeDO> bagCodes = bagCodeMapper.selectListByIds(ids);
+    private List<MesProBagCodeDO> validateBagCodesForBind(List<Long> ids, MesProPalletDO pallet, boolean lock) {
+        List<MesProBagCodeDO> bagCodes = lock ? bagCodeMapper.selectListByIdsForUpdate(ids) : bagCodeMapper.selectListByIds(ids);
         if (bagCodes.size() != ids.size()) {
             throw exception(PRO_BAG_CODE_NOT_EXISTS);
         }

--
Gitblit v1.9.3