From 795bc269ba9acfae74620059c4ed64bd121aa288 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 22 十月 2026 12:23:00 +0800
Subject: [PATCH] feat(mdm): 打通智能体物料导入端到端链路
---
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java | 244 +++++++++++++++++++++++++++++-------------------
1 files changed, 148 insertions(+), 96 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 e1c5a82..e266489 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
@@ -3,6 +3,7 @@
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;
@@ -32,10 +33,13 @@
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;
@@ -73,6 +77,9 @@
@Resource
private MesMdItemTypeApi mesMdItemTypeApi;
+
+ @Resource
+ private PlatformTransactionManager transactionManager;
@Override
@@ -129,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
@@ -433,7 +440,6 @@
}
@Override
- @Transactional(rollbackFor = Exception.class)
@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) {
@@ -445,111 +451,52 @@
.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());
- }
+ MdmItemImportContext context = buildImportContext(importList);
- // 2. 閬嶅巻瀵煎叆
+ // 2. 閬嶅巻瀵煎叆锛堟瘡琛屼竴涓嫭绔嬩簨鍔★細鍗曡澶辫触鍙洖婊氳琛岋紝涓嶅奖鍝嶅叾浣欒锛�
+ TransactionTemplate importTxTemplate = new TransactionTemplate(transactionManager);
for (MdmItemImportExcelVO importVO : importList) {
- // 2.1 鍩虹鏍¢獙
- if (StrUtil.isBlank(importVO.getCode()) || StrUtil.isBlank(importVO.getName())) {
- String failKey = StrUtil.isNotBlank(importVO.getName()) ? importVO.getName()
- : (StrUtil.isNotBlank(importVO.getCode()) ? importVO.getCode() : "锛堝悕绉板拰缂栫爜涓虹┖鐨勮锛�");
- respVO.getFailureList().put(failKey, "鐗╂枡缂栫爜鍜岀墿鏂欏悕绉颁笉鑳戒负绌�");
+ // 2.1~2.6 鏍¢獙蹇呭~椤广�佽В鏋愬垎绫讳笌鍗曚綅銆佺粍瑁� SaveReqVO
+ MdmItemRowResolution resolution = resolveImportRow(importVO, context);
+ if (!resolution.isSuccess()) {
+ respVO.getFailureList().put(buildFailKey(importVO), resolution.failureMessage());
continue;
}
- // 2.2 瑙f瀽鍒嗙被
- Long categoryId = null;
- if (StrUtil.isNotBlank(importVO.getCategoryCode())) {
- categoryId = categoryCodeIdMap.get(importVO.getCategoryCode());
- if (categoryId == null) {
- respVO.getFailureList().put(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "鐗╂枡鍒嗙被缂栫爜涓嶅瓨鍦細" + 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(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "璁¢噺鍗曚綅缂栫爜涓嶅瓨鍦細" + 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(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "杈呭崟浣�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(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "杈呭崟浣�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); // 榛樿鐗╂枡绫诲瀷锛氱墿鏂�
+ MdmItemSaveReqVO saveReqVO = resolution.saveReqVO();
// 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 {
- if (existByCode != null) {
- if (!Boolean.TRUE.equals(isUpdateSupport)) {
- respVO.getFailureList().put(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "鐗╂枡缂栫爜宸插瓨鍦�");
- continue;
+ importTxTemplate.executeWithoutResult(status -> {
+ try {
+ if (isUpdate) {
+ updateItem(saveReqVO);
+ } else {
+ createItem(saveReqVO);
+ }
+ } catch (Throwable t) {
+ rowError.set(t);
+ throw t;
}
- saveReqVO.setId(existByCode.getId());
- updateItem(saveReqVO);
- respVO.getUpdateList().add(importVO.getName());
- } else {
- createItem(saveReqVO);
- respVO.getCreateList().add(importVO.getName());
- }
+ });
+ // 鍙湁鏈浜嬪姟鎻愪氦鎴愬姛鎵嶈鍏ユ垚鍔熸竻鍗�
+ (isUpdate ? respVO.getUpdateList() : respVO.getCreateList()).add(importVO.getName());
} catch (Exception ex) {
// 鍗曟潯澶辫触锛岃褰曞苟缁х画
- String reason = ex instanceof cn.iocoder.yudao.framework.common.exception.ServiceException
- ? ((cn.iocoder.yudao.framework.common.exception.ServiceException) ex).getMessage()
- : ex.getMessage();
- respVO.getFailureList().put(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), reason == null ? "瀵煎叆澶辫触" : reason);
+ 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 鏂囨寮曠敤
@@ -557,4 +504,109 @@
return respVO;
}
+ @Override
+ public MdmItemImportContext buildImportContext(List<MdmItemImportExcelVO> importList) {
+ Map<String, Long> categoryCodeIdMap = new HashMap<>();
+ Map<String, String> categoryCodeNameMap = 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());
+ categoryCodeNameMap.put(categoryCode, categoryResult.getData().getName());
+ }
+ }
+ Map<String, Long> unitCodeIdMap = new HashMap<>();
+ Map<String, String> unitCodeNameMap = new HashMap<>();
+ for (MdmUnitMeasureDO unit : unitMeasureMapper.selectList()) {
+ unitCodeIdMap.put(unit.getCode(), unit.getId());
+ unitCodeNameMap.put(unit.getCode(), unit.getName());
+ }
+ return new MdmItemImportContext(categoryCodeIdMap, categoryCodeNameMap, unitCodeIdMap, unitCodeNameMap);
+ }
+
+ @Override
+ public MdmItemRowResolution resolveImportRow(MdmItemImportExcelVO importVO, MdmItemImportContext context) {
+ // 鍩虹鏍¢獙
+ if (StrUtil.isBlank(importVO.getCode()) || StrUtil.isBlank(importVO.getName())) {
+ return MdmItemRowResolution.failure("鐗╂枡缂栫爜鍜岀墿鏂欏悕绉颁笉鑳戒负绌�");
+ }
+ // 瑙f瀽鍒嗙被
+ Long categoryId = null;
+ if (StrUtil.isNotBlank(importVO.getCategoryCode())) {
+ categoryId = context.categoryCodeIdMap().get(importVO.getCategoryCode());
+ if (categoryId == null) {
+ return MdmItemRowResolution.failure("鐗╂枡鍒嗙被缂栫爜涓嶅瓨鍦細" + importVO.getCategoryCode());
+ }
+ }
+ // 瑙f瀽涓诲崟浣�
+ Long unitMeasureId = null;
+ if (StrUtil.isNotBlank(importVO.getUnitMeasureCode())) {
+ unitMeasureId = context.unitCodeIdMap().get(importVO.getUnitMeasureCode());
+ if (unitMeasureId == null) {
+ return MdmItemRowResolution.failure("璁¢噺鍗曚綅缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode());
+ }
+ }
+ // 瑙f瀽杈呭崟浣�1
+ Long unitMeasureId2 = null;
+ if (StrUtil.isNotBlank(importVO.getUnitMeasureCode2())) {
+ unitMeasureId2 = context.unitCodeIdMap().get(importVO.getUnitMeasureCode2());
+ if (unitMeasureId2 == null) {
+ return MdmItemRowResolution.failure("杈呭崟浣�1缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode2());
+ }
+ }
+ // 瑙f瀽杈呭崟浣�2
+ Long unitMeasureId3 = null;
+ if (StrUtil.isNotBlank(importVO.getUnitMeasureCode3())) {
+ unitMeasureId3 = context.unitCodeIdMap().get(importVO.getUnitMeasureCode3());
+ if (unitMeasureId3 == null) {
+ return MdmItemRowResolution.failure("杈呭崟浣�2缂栫爜涓嶅瓨鍦細" + importVO.getUnitMeasureCode3());
+ }
+ }
+
+ // 缁勮 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); // 榛樿鐗╂枡绫诲瀷锛氱墿鏂�
+ return MdmItemRowResolution.success(saveReqVO);
+ }
+
+ @Override
+ public List<MdmItemDO> getItemListByCode(String code) {
+ return itemMapper.selectListByCode(code);
+ }
+
+ /**
+ * 澶辫触娓呭崟鐨� 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