From 3edf8c4fc07f9784e2d04ee7a98692bb457749eb Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 26 十月 2026 16:28:10 +0800
Subject: [PATCH] feat(mes): 新增工艺路线完整导入功能并优化相关验证

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductServiceImpl.java |   76 ++++++++++++++++++++++++++++++++++++-
 1 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductServiceImpl.java
index d5089de..b879221 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductServiceImpl.java
@@ -4,7 +4,17 @@
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.product.MesProRouteProductSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.route.MesProRouteProductMapper;
+import cn.iocoder.yudao.module.mes.enums.md.MesMdItemTypeEnum;
+import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
+import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
+import cn.iocoder.yudao.module.mdm.enums.MdmItemTypeEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -12,6 +22,9 @@
 import org.springframework.validation.annotation.Validated;
 
 import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -34,13 +47,25 @@
     @Resource
     @Lazy
     private MesProRouteProductBomService routeProductBomService;
+    @Resource
+    private MesMdItemService itemService;
+    @Resource
+    private MesMdItemTypeService itemTypeService;
+    @Resource
+    private MesWmWarehouseAreaService warehouseAreaService;
+    @Resource
+    private MdmItemApi mdmItemApi;
 
     @Override
     public Long createRouteProduct(MesProRouteProductSaveReqVO createReqVO) {
         // 1.0 宸插惎鐢ㄧ殑宸ヨ壓璺嚎锛屼笉鍏佽鎿嶄綔
         routeService.validateRouteNotEnable(createReqVO.getRouteId());
-        // 1.1 鏍¢獙浜у搧鍞竴鎬э紙涓�涓骇鍝佸彧鑳藉叧鑱斾竴鏉″伐鑹鸿矾绾匡級
+        // 1.1 鏍¢獙浜у搧瀛樺湪銆佸惎鐢ㄤ笖绫诲瀷姝g‘
+        validateProductItem(createReqVO.getItemId());
+        // 1.2 鏍¢獙浜у搧鍞竴鎬э紙涓�涓骇鍝佸彧鑳藉叧鑱斾竴鏉″伐鑹鸿矾绾匡級
         validateItemUnique(null, createReqVO.getItemId());
+        warehouseAreaService.validateWarehouseAreaExists(createReqVO.getWarehouseId(),
+                createReqVO.getLocationId(), createReqVO.getAreaId());
 
         // 2. 鎻掑叆
         MesProRouteProductDO routeProduct = BeanUtils.toBean(createReqVO, MesProRouteProductDO.class);
@@ -53,9 +78,16 @@
         // 1.0 宸插惎鐢ㄧ殑宸ヨ壓璺嚎锛屼笉鍏佽鎿嶄綔
         routeService.validateRouteNotEnable(updateReqVO.getRouteId());
         // 1.1 鏍¢獙瀛樺湪
-        validateRouteProductExists(updateReqVO.getId());
-        // 1.2 鏍¢獙浜у搧鍞竴鎬�
+        MesProRouteProductDO existing = routeProductMapper.selectById(updateReqVO.getId());
+        validateRouteProductExists(existing);
+        // 鍘嗗彶璺嚎浜у搧鍙兘閲囩敤鏃у垎绫伙紱鍙慨鏀逛粨浣嶇瓑閰嶇疆鏃朵笉閲嶆柊鎷︽埅鍘熸湁鐗╂枡銆�
+        if (ObjUtil.notEqual(existing.getItemId(), updateReqVO.getItemId())) {
+            validateProductItem(updateReqVO.getItemId());
+        }
+        // 1.3 鏍¢獙浜у搧鍞竴鎬�
         validateItemUnique(updateReqVO.getId(), updateReqVO.getItemId());
+        warehouseAreaService.validateWarehouseAreaExists(updateReqVO.getWarehouseId(),
+                updateReqVO.getLocationId(), updateReqVO.getAreaId());
 
         // 2. 鏇存柊
         MesProRouteProductDO updateObj = BeanUtils.toBean(updateReqVO, MesProRouteProductDO.class);
@@ -89,6 +121,44 @@
         }
     }
 
+    private void validateProductItem(Long itemId) {
+        MesMdItemDO item = itemService.validateItemExistsAndEnable(itemId);
+        Long typeId = item.getItemTypeId();
+        Set<Long> visited = new HashSet<>();
+        while (typeId != null && !MesMdItemTypeDO.PARENT_ID_ROOT.equals(typeId) && visited.add(typeId)) {
+            MesMdItemTypeDO itemType = itemTypeService.getItemType(typeId);
+            if (itemType == null) {
+                break;
+            }
+            // 鍏煎鏃у垎绫伙細鍙兘鏈缃� PRODUCT 鏍囪瘑锛屼篃鏈噰鐢� FG/SF 缂栫爜銆�
+            if (MesMdItemTypeEnum.isProduct(itemType.getItemOrProduct())
+                    || "FG".equalsIgnoreCase(itemType.getCode())
+                    || "SF".equalsIgnoreCase(itemType.getCode())
+                    || isProductCategoryName(itemType.getName())) {
+                return;
+            }
+            typeId = itemType.getParentId();
+        }
+        // MES 鍏煎鍒嗙被鍙兘浠嶆爣璁颁负 ITEM锛涗互 MDM 鐗╂枡涓绘暟鎹殑鎴愬搧/鍗婃垚鍝佺被鍨嬪厹搴曘��
+        CommonResult<MdmItemRespDTO> mdmResult = mdmItemApi.getItemByCode(item.getCode());
+        if (mdmResult != null && mdmResult.isSuccess() && mdmResult.getData() != null) {
+            MdmItemRespDTO mdmItem = mdmResult.getData();
+            Integer mdmType = mdmItem.getItemType();
+            // 鍘嗗彶鍚屾鏇惧皢鍒嗙被 ID 鍐欏叆 itemType锛涗笌 categoryId 鐩稿悓鐨勫�间笉鑳藉綋浣滅被鍨嬫灇涓俱��
+            if (!Objects.equals(mdmItem.getCategoryId(), mdmType == null ? null : mdmType.longValue())
+                    && (MdmItemTypeEnum.PRODUCT.getType().equals(mdmType)
+                    || MdmItemTypeEnum.SEMI_FINISHED.getType().equals(mdmType))) {
+                return;
+            }
+        }
+        throw exception(PRO_ROUTE_PRODUCT_ITEM_TYPE_INVALID, item.getName());
+    }
+
+    private boolean isProductCategoryName(String name) {
+        return name != null && (name.contains("鍗婃垚鍝�") || name.contains("浜ф垚鍝�")
+                || (name.contains("鎴愬搧") && !name.contains("闈炴垚鍝�")));
+    }
+
     private void validateItemUnique(Long id, Long itemId) {
         MesProRouteProductDO existing = routeProductMapper.selectByItemId(itemId);
         if (existing == null) {

--
Gitblit v1.9.3