From 3fa88d03676ec8b62c80fc50636d2c8e973c0470 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 12 十月 2026 10:32:58 +0800
Subject: [PATCH] fix(mdm): 物料管理 导入失败展示修改及同步生产物料问题

---
 yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java |  213 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 207 insertions(+), 6 deletions(-)

diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
index 7154a10..cfbc790 100644
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
+++ b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
@@ -2,17 +2,24 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils;
+import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportExcelVO;
+import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportRespVO;
 import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
 import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
 import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
+import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO;
 import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
 import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
 import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemBatchConfigMapper;
 import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
+import cn.iocoder.yudao.module.mdm.dal.mysql.unit.MdmUnitMeasureMapper;
 import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
 import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
 import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
@@ -21,19 +28,24 @@
 import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO;
 import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.mzt.logapi.starter.annotation.LogRecord;
 import jakarta.annotation.Resource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionTemplate;
 import org.springframework.validation.annotation.Validated;
 
 import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.mdm.enums.LogRecordConstants.*;
 
 /**
  * MDM 鐗╂枡涓绘暟鎹� Service 瀹炵幇绫�
@@ -61,7 +73,13 @@
     private MdmItemBatchConfigMapper itemBatchConfigMapper;
 
     @Resource
+    private MdmUnitMeasureMapper unitMeasureMapper;
+
+    @Resource
     private MesMdItemTypeApi mesMdItemTypeApi;
+
+    @Resource
+    private PlatformTransactionManager transactionManager;
 
 
     @Override
@@ -77,9 +95,11 @@
         // 淇濆瓨鎵规閰嶇疆锛堝鏋滄湁锛�
         saveBatchConfig(item.getId(), createReqVO);
 
-        // 濮嬬粓鍚屾鍒� MES
-        createReqVO.setId(item.getId());
-        syncItemToMes(createReqVO);
+        // 鍕鹃�夊悓姝ユ椂锛屽悓姝ュ埌 MES
+        if (Boolean.TRUE.equals(createReqVO.getSyncMes())) {
+            createReqVO.setId(item.getId());
+            syncItemToMes(createReqVO);
+        }
         return item.getId();
     }
 
@@ -98,8 +118,12 @@
         // 淇濆瓨鎵规閰嶇疆锛堝鏋滄湁锛�
         saveBatchConfig(updateReqVO.getId(), updateReqVO);
 
-        // 濮嬬粓鍚屾鍒� MES
-        syncItemToMes(updateReqVO);
+        // 鏍规嵁鍚屾寮�鍏冲喅瀹氾細鎵撳紑鍒欏悓姝ュ埌 MES锛屽叧闂垯鍙栨秷鍚屾锛堜粠 MES 鍒犻櫎锛�
+        if (Boolean.TRUE.equals(updateReqVO.getSyncMes())) {
+            syncItemToMes(updateReqVO);
+        } else {
+            mesMdItemApi.deleteItem(updateReqVO.getId());
+        }
     }
 
     private void validateItemSaveData(MdmItemSaveReqVO reqVO) {
@@ -112,7 +136,7 @@
      *
      * MDM 鐨� unitMeasureId/categoryId 涓� MES 鐨� unitMeasureId/itemTypeId 鍒嗗睘涓ゅ涓绘暟鎹紝
      * 杩欓噷鍏堝湪 MDM 渚цВ鏋愬嚭 code锛屽啀浜ょ敱 MesMdItemApi 鍦� MES 渚цВ鏋愪负瀵瑰簲 id銆�
-     * 鍚屾澶辫触灏嗘姏鍑哄紓甯革紝瑙﹀彂澶栧眰 @Transactional 鏁翠綋鍥炴粴锛圡DM 鎿嶄綔涓�骞跺洖婊氾級銆�
+     * 鍚屾澶辫触灏嗘姏鍑哄紓甯革紝鍥炴粴鏈浜嬪姟锛堟湰琛岀殑 MDM 鎿嶄綔涓�骞跺洖婊氾紝涓嶅奖鍝嶅叾瀹冭锛夈��
      */
     private void syncItemToMes(MdmItemSaveReqVO reqVO) {
         // 瑙f瀽璁¢噺鍗曚綅 id -> code
@@ -183,6 +207,35 @@
         itemMapper.deleteById(id);
         // 鍚屾鍒犻櫎鍒� MES
         mesMdItemApi.deleteItem(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateItemSync(Long id, Boolean sync) {
+        // 鏍¢獙瀛樺湪
+        MdmItemDO item = validateItemExists(id);
+        if (Boolean.TRUE.equals(sync)) {
+            // 鍚屾鍒� MES锛氫粠 DB 璇诲彇瀹屾暣鐗╂枡鏁版嵁缁勮鍚庤蛋 syncItemToMes
+            MdmItemSaveReqVO reqVO = BeanUtils.toBean(item, MdmItemSaveReqVO.class);
+            // DO 瀛楁鍚嶄负 highValue锛屼笌 VO 鐨� isHighValue 涓嶈嚜鍔ㄥ尮閰嶏紝鎵嬪姩琛ラ綈
+            reqVO.setIsHighValue(item.getHighValue());
+            // 琛ラ綈鎵规灞炴�ч厤缃�
+            MdmItemBatchConfigDO config = itemBatchConfigMapper.selectOne(
+                    MdmItemBatchConfigDO::getItemId, id);
+            if (config != null) {
+                reqVO.setProduceDateFlag(config.getProduceDateFlag());
+                reqVO.setExpireDateFlag(config.getExpireDateFlag());
+                reqVO.setReceiptDateFlag(config.getReceiptDateFlag());
+                reqVO.setVendorFlag(config.getVendorFlag());
+                reqVO.setPurchaseOrderCodeFlag(config.getPurchaseOrderCodeFlag());
+                reqVO.setLotNumberFlag(config.getLotNumberFlag());
+                reqVO.setQualityStatusFlag(config.getQualityStatusFlag());
+            }
+            syncItemToMes(reqVO);
+        } else {
+            // 鍙栨秷鍚屾锛氫粠 MES 鍒犻櫎璇ョ墿鏂欙紙MES 鏃犳鐗╂枡鏃跺唴閮ㄤ负绌烘搷浣滐級
+            mesMdItemApi.deleteItem(id);
+        }
     }
 
     /**
@@ -386,4 +439,152 @@
         }
     }
 
+    @Override
+    @LogRecord(type = MDM_ITEM_TYPE, subType = MDM_ITEM_IMPORT_SUB_TYPE, bizNo = "0",
+            success = MDM_ITEM_IMPORT_SUCCESS)
+    public MdmItemImportRespVO importItemList(List<MdmItemImportExcelVO> importList, Boolean isUpdateSupport) {
+        if (CollUtil.isEmpty(importList)) {
+            throw exception(MDM_ITEM_IMPORT_LIST_IS_EMPTY);
+        }
+        MdmItemImportRespVO respVO = MdmItemImportRespVO.builder()
+                .createList(new ArrayList<>()).updateList(new ArrayList<>())
+                .failureList(new LinkedHashMap<>()).build();
+
+        // 1. 棰勭儹锛氬垎绫荤紪鐮� -> ID锛圡ES 鐗╂枡鍒嗙被锛屼笌鐗╂枡琛ㄥ崟涓嬫媺鏁版嵁婧愪竴鑷达級銆佸崟浣嶇紪鐮� -> ID
+        Map<String, Long> categoryCodeIdMap = new HashMap<>();
+        for (String categoryCode : importList.stream()
+                .map(MdmItemImportExcelVO::getCategoryCode).filter(StrUtil::isNotBlank).distinct().toList()) {
+            CommonResult<MesMdItemTypeRespDTO> categoryResult = mesMdItemTypeApi.getItemTypeByCode(categoryCode);
+            if (categoryResult != null && categoryResult.getData() != null) {
+                categoryCodeIdMap.put(categoryCode, categoryResult.getData().getId());
+            }
+        }
+        Map<String, Long> unitCodeIdMap = new HashMap<>();
+        for (MdmUnitMeasureDO unit : unitMeasureMapper.selectList()) {
+            unitCodeIdMap.put(unit.getCode(), unit.getId());
+        }
+
+        // 2. 閬嶅巻瀵煎叆锛堟瘡琛屼竴涓嫭绔嬩簨鍔★細鍗曡澶辫触鍙洖婊氳琛岋紝涓嶅奖鍝嶅叾浣欒锛�
+        TransactionTemplate importTxTemplate = new TransactionTemplate(transactionManager);
+        for (MdmItemImportExcelVO importVO : importList) {
+            // 2.1 鍩虹鏍¢獙
+            if (StrUtil.isBlank(importVO.getCode()) || StrUtil.isBlank(importVO.getName())) {
+                respVO.getFailureList().put(buildFailKey(importVO), "鐗╂枡缂栫爜鍜岀墿鏂欏悕绉颁笉鑳戒负绌�");
+                continue;
+            }
+            // 2.2 瑙f瀽鍒嗙被
+            Long categoryId = null;
+            if (StrUtil.isNotBlank(importVO.getCategoryCode())) {
+                categoryId = categoryCodeIdMap.get(importVO.getCategoryCode());
+                if (categoryId == null) {
+                    respVO.getFailureList().put(buildFailKey(importVO), "鐗╂枡鍒嗙被缂栫爜涓嶅瓨鍦細" + importVO.getCategoryCode());
+                    continue;
+                }
+            }
+            // 2.3 瑙f瀽涓诲崟浣�
+            Long unitMeasureId = null;
+            if (StrUtil.isNotBlank(importVO.getUnitMeasureCode())) {
+                unitMeasureId = unitCodeIdMap.get(importVO.getUnitMeasureCode());
+                if (unitMeasureId == null) {
+                    respVO.getFailureList().put(buildFailKey(importVO), "璁¢噺鍗曚綅缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode());
+                    continue;
+                }
+            }
+            // 2.4 瑙f瀽杈呭崟浣�1
+            Long unitMeasureId2 = null;
+            if (StrUtil.isNotBlank(importVO.getUnitMeasureCode2())) {
+                unitMeasureId2 = unitCodeIdMap.get(importVO.getUnitMeasureCode2());
+                if (unitMeasureId2 == null) {
+                    respVO.getFailureList().put(buildFailKey(importVO), "杈呭崟浣�1缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode2());
+                    continue;
+                }
+            }
+            // 2.5 瑙f瀽杈呭崟浣�2
+            Long unitMeasureId3 = null;
+            if (StrUtil.isNotBlank(importVO.getUnitMeasureCode3())) {
+                unitMeasureId3 = unitCodeIdMap.get(importVO.getUnitMeasureCode3());
+                if (unitMeasureId3 == null) {
+                    respVO.getFailureList().put(buildFailKey(importVO), "杈呭崟浣�2缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode3());
+                    continue;
+                }
+            }
+
+            // 2.6 缁勮 SaveReqVO锛堝鐢� create/update 閫昏緫锛�
+            MdmItemSaveReqVO saveReqVO = new MdmItemSaveReqVO();
+            saveReqVO.setCode(importVO.getCode());
+            saveReqVO.setName(importVO.getName());
+            saveReqVO.setBarCode(importVO.getBarCode());
+            saveReqVO.setSpecification(importVO.getSpecification());
+            saveReqVO.setCategoryId(categoryId);
+            saveReqVO.setUnitMeasureId(unitMeasureId);
+            saveReqVO.setUnitMeasureId2(unitMeasureId2);
+            saveReqVO.setUnitMeasureRate1(importVO.getUnitMeasureRate1());
+            saveReqVO.setUnitMeasureId3(unitMeasureId3);
+            saveReqVO.setUnitMeasureRate2(importVO.getUnitMeasureRate2());
+            saveReqVO.setPurchasePrice(importVO.getPurchasePrice());
+            saveReqVO.setSalesPrice(importVO.getSalesPrice());
+            saveReqVO.setCostPrice(importVO.getCostPrice());
+            saveReqVO.setSafetyStock(importVO.getSafetyStock());
+            saveReqVO.setMinStock(importVO.getMinStock());
+            saveReqVO.setMaxStock(importVO.getMaxStock());
+            saveReqVO.setIsBatchManaged(importVO.getIsBatchManaged());
+            saveReqVO.setExpiryDay(importVO.getExpiryDay());
+            saveReqVO.setStatus(importVO.getStatus() != null ? importVO.getStatus() : cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus());
+            saveReqVO.setSyncMes(importVO.getSyncMes() != null ? importVO.getSyncMes() : false);
+            saveReqVO.setRemark(importVO.getRemark());
+            saveReqVO.setItemType(1); // 榛樿鐗╂枡绫诲瀷锛氱墿鏂�
+
+            // 2.7 宸插瓨鍦紙鎸夌紪鐮佸垽鏂級
+            MdmItemDO existByCode = itemMapper.selectByCode(importVO.getCode());
+            if (existByCode != null && !Boolean.TRUE.equals(isUpdateSupport)) {
+                respVO.getFailureList().put(buildFailKey(importVO), "鐗╂枡缂栫爜宸插瓨鍦�");
+                continue;
+            }
+            if (existByCode != null) {
+                saveReqVO.setId(existByCode.getId());
+            }
+            boolean isUpdate = existByCode != null;
+            // 浜嬪姟鍐呭厛鐣欎綇鍘熷寮傚父锛氬悓姝ュ埌 MES 澶辫触鏃朵細鎶婁簨鍔℃爣璁颁负 rollback-only锛�
+            // 鎻愪氦闃舵鎶涘嚭鐨勫彧鏄缁熺殑 UnexpectedRollbackException锛岀湡瀹炲師鍥狅紙濡�"鐗╂枡鍚嶇О宸插瓨鍦�"锛変細涓�
+            AtomicReference<Throwable> rowError = new AtomicReference<>();
+            try {
+                importTxTemplate.executeWithoutResult(status -> {
+                    try {
+                        if (isUpdate) {
+                            updateItem(saveReqVO);
+                        } else {
+                            createItem(saveReqVO);
+                        }
+                    } catch (Throwable t) {
+                        rowError.set(t);
+                        throw t;
+                    }
+                });
+                // 鍙湁鏈浜嬪姟鎻愪氦鎴愬姛鎵嶈鍏ユ垚鍔熸竻鍗�
+                (isUpdate ? respVO.getUpdateList() : respVO.getCreateList()).add(importVO.getName());
+            } catch (Exception ex) {
+                // 鍗曟潯澶辫触锛岃褰曞苟缁х画
+                Throwable cause = rowError.get() != null ? rowError.get() : ex;
+                String reason = cause instanceof ServiceException ? ((ServiceException) cause).getMessage() : cause.getMessage();
+                respVO.getFailureList().put(buildFailKey(importVO), reason == null ? "瀵煎叆澶辫触" : reason);
+            }
+        }
+        // 璁板綍瀵煎叆缁撴灉姹囨�伙紝渚� @LogRecord 鐨� success 鏂囨寮曠敤
+        OperateLogUtils.putImportSummary(respVO.getCreateList(), respVO.getUpdateList(), respVO.getFailureList());
+        return respVO;
+    }
+
+    /**
+     * 澶辫触娓呭崟鐨� key锛氱敤銆岀紪鐮� 鍚嶇О銆嶏紝鑰屼笉鏄崟鐢ㄥ悕绉般��
+     * 鐗╂枡鍏佽鍚屽悕涓嶅悓缂栫爜鍚庯紝鍙寜鍚嶇О鍋� key 浼氳鍚屽悕琛屼簰鐩歌鐩栥�佸皯鎶ュけ璐ヨ锛�
+     * 鎷兼帴鍚庢棦鑳藉敮涓�鏍囪瘑銆佷篃鑳戒竴鐪肩湅鍑烘槸鍝釜鐗╂枡銆�
+     */
+    private static String buildFailKey(MdmItemImportExcelVO importVO) {
+        if (StrUtil.isNotBlank(importVO.getCode()) && StrUtil.isNotBlank(importVO.getName())) {
+            return importVO.getCode() + " " + importVO.getName();
+        }
+        return StrUtil.blankToDefault(importVO.getCode(),
+                StrUtil.blankToDefault(importVO.getName(), "锛堝悕绉板拰缂栫爜涓虹┖鐨勮锛�"));
+    }
+
 }
\ No newline at end of file

--
Gitblit v1.9.3