From 620bb4712a31791231c4381581f0f60088f079fe Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 27 五月 2026 14:03:45 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_New_pro' into dev_宁夏_英泽防锈

---
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  165 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 151 insertions(+), 14 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index a9f76fd..0513bdc 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -23,6 +23,7 @@
 import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
 import com.ruoyi.production.pojo.ProductionProductMain;
 import com.ruoyi.production.service.ProductionBomStructureService;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
 import com.ruoyi.technology.mapper.TechnologyOperationMapper;
 import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
 import com.ruoyi.technology.mapper.TechnologyParamMapper;
@@ -223,9 +224,9 @@
             }
 
             BigDecimal demandedQuantity = lastProcessDemandedQuantity.multiply(defaultDecimal(structure.getUnitQuantity()));
-            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
-                continue;
-            }
+//            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
+//                continue;
+//            }
             ProductionBomStructure update = new ProductionBomStructure();
             update.setId(structure.getId());
             update.setDemandedQuantity(demandedQuantity);
@@ -262,7 +263,7 @@
                 .filter(item -> item != null && item.getId() != null)
                 .collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
         // Keep task plan quantities aligned with the same order BOM snapshot demand used during snapshot creation.
-        Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId);
+        Map<String, BigDecimal> demandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(structureList, rootProductModelId);
         for (ProductionOperationTask task : taskList) {
             if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
                 continue;
@@ -310,7 +311,7 @@
             if (matchedOperation == null) {
                 matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
             } else {
-                updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation);
+                updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation);
             }
             finalOperationList.add(matchedOperation);
         }
@@ -381,17 +382,32 @@
         Map<Long, ProductionBomStructure> structureById = structureList.stream()
                 .filter(item -> item != null && item.getId() != null)
                 .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
-        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
-        for (ProductionBomStructure bomStructure : structureList) {
-            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
-                continue;
+
+        // 鏋勫缓鐖�-瀛愭槧灏勫叧绯�
+        Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
+
+        // 浣跨敤鍚庡簭閬嶅巻鏋勫缓鎿嶄綔鍒楄〃锛堝厛瀛愬悗鐖讹紝纭繚宸ヨ壓璺嚎椤哄簭姝g‘锛�
+        // 浣跨敤娣卞害浣滀负鎺掑簭渚濇嵁鐨勮緟鍔╃粨鏋�
+        Map<String, ProductionBomStructure> operationMap = new LinkedHashMap<>();
+        Map<String, Integer> depthMap = new HashMap<>();
+        buildOperationListPostOrderWithDepth(null, treeMap, operationMap, depthMap, structureById, rootProductModelId, 1);
+
+        // 鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈�
+        List<Map.Entry<String, ProductionBomStructure>> sortedEntries = new ArrayList<>(operationMap.entrySet());
+        sortedEntries.sort((a, b) -> {
+            int depthCompare = Integer.compare(
+                    depthMap.getOrDefault(b.getKey(), 0),
+                    depthMap.getOrDefault(a.getKey(), 0));
+            if (depthCompare != 0) {
+                return depthCompare;
             }
-            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
-            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
-        }
+            return 0;
+        });
+
         List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
         int dragSort = 1;
-        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
+        for (Map.Entry<String, ProductionBomStructure> entry : sortedEntries) {
+            ProductionBomStructure bomStructure = entry.getValue();
             Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
             TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId());
             ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
@@ -405,6 +421,127 @@
             desiredOperationList.add(routingOperation);
         }
         return desiredOperationList;
+    }
+
+    private void buildOperationListPostOrderWithDepth(Long parentId,
+                                                      Map<Long, List<ProductionBomStructure>> treeMap,
+                                                      Map<String, ProductionBomStructure> operationMap,
+                                                      Map<String, Integer> depthMap,
+                                                      Map<Long, ProductionBomStructure> structureById,
+                                                      Long rootProductModelId,
+                                                      int currentDepth) {
+        List<ProductionBomStructure> children = treeMap.get(parentId);
+        if (children == null || children.isEmpty()) {
+            return;
+        }
+        for (ProductionBomStructure child : children) {
+            // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+            buildOperationListPostOrderWithDepth(child.getId(), treeMap, operationMap, depthMap, structureById, rootProductModelId, currentDepth + 1);
+
+            // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+            if (child.getTechnologyOperationId() != null) {
+                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+                String key = buildBomOperationDedupKey(child, outputProductModelId);
+                // 淇濈暀娣卞害鏈�澶х殑鎿嶄綔
+                Integer existingDepth = depthMap.get(key);
+                if (existingDepth == null || currentDepth > existingDepth) {
+                    operationMap.put(key, child);
+                    depthMap.put(key, currentDepth);
+                }
+            }
+        }
+    }
+
+    private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) {
+        Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>();
+        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+
+        // 鏋勫缓鐖�-瀛愭槧灏勫拰ID鏄犲皠
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null) continue;
+            Long parentId = structure.getParentId();
+            treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
+            if (structure.getId() != null) {
+                structureById.put(structure.getId(), structure);
+            }
+        }
+
+        // 璁$畻姣忎釜鑺傜偣鐨勬繁搴︼紙浠庢牴鑺傜偣鍒板綋鍓嶈妭鐐圭殑璺濈锛屾牴鑺傜偣娣卞害涓�1锛�
+        Map<Long, Integer> depthMap = new HashMap<>();
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null || structure.getId() == null) continue;
+            computeDepthFromRoot(structure.getId(), structureById, depthMap);
+        }
+
+        // 瀵规瘡涓埗鑺傜偣涓嬬殑瀛愯妭鐐规寜娣卞害鍊掑簭鎺掑簭锛堟渶娣卞眰鐨勪紭鍏堬級
+        for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) {
+            List<ProductionBomStructure> children = entry.getValue();
+            children.sort((a, b) -> {
+                // 浼樺厛鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈紙鏈�娣卞眰浼樺厛锛�
+                int depthCompare = Integer.compare(
+                        depthMap.getOrDefault(b.getId(), 0),
+                        depthMap.getOrDefault(a.getId(), 0));
+                if (depthCompare != 0) {
+                    return depthCompare;
+                }
+                // 娣卞害鐩稿悓鏃舵寜ID鎺掑簭淇濊瘉绋冲畾鎬�
+                return Long.compare(a.getId(), b.getId());
+            });
+        }
+
+        return treeMap;
+    }
+
+    /**
+     * 璁$畻鑺傜偣娣卞害锛堜粠鏍硅妭鐐瑰埌褰撳墠鑺傜偣鐨勮窛绂伙級
+     * 鏍硅妭鐐规繁搴︿负1锛屾瘡鍚戜笅涓�灞傛繁搴﹀姞1
+     */
+    private int computeDepthFromRoot(Long nodeId, Map<Long, ProductionBomStructure> structureById, Map<Long, Integer> depthMap) {
+        if (depthMap.containsKey(nodeId)) {
+            return depthMap.get(nodeId);
+        }
+
+        ProductionBomStructure structure = structureById.get(nodeId);
+        if (structure == null) {
+            depthMap.put(nodeId, 1);
+            return 1;
+        }
+
+        Long parentId = structure.getParentId();
+        if (parentId == null || parentId == 0L) {
+            // 鏍硅妭鐐规繁搴︿负1
+            depthMap.put(nodeId, 1);
+            return 1;
+        }
+
+        // 瀛愯妭鐐规繁搴� = 鐖惰妭鐐规繁搴� + 1
+        int parentDepth = computeDepthFromRoot(parentId, structureById, depthMap);
+        int depth = parentDepth + 1;
+        depthMap.put(nodeId, depth);
+        return depth;
+    }
+
+    private void buildOperationListPostOrder(Long parentId,
+                                             Map<Long, List<ProductionBomStructure>> treeMap,
+                                             Map<String, ProductionBomStructure> uniqueOperationMap,
+                                             Map<Long, ProductionBomStructure> structureById,
+                                             Long rootProductModelId) {
+        List<ProductionBomStructure> children = treeMap.get(parentId);
+        if (children == null || children.isEmpty()) {
+            return;
+        }
+        for (ProductionBomStructure child : children) {
+            // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+            buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId);
+
+            // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+            if (child.getTechnologyOperationId() != null) {
+                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+                String key = buildBomOperationDedupKey(child, outputProductModelId);
+                // 鍘婚噸鏃朵繚鐣欐繁搴︽渶澶х殑鎿嶄綔锛堝悗搴忛亶鍘嗗厛閬囧埌娣卞眰鑺傜偣锛屾墍浠ョ洿鎺ヨ鐩栧嵆鍙級
+                uniqueOperationMap.put(key, child);
+            }
+        }
     }
 
     private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
@@ -571,7 +708,7 @@
             return;
         }
         if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
-            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収" + task.getWorkOrderNo());
         }
         long reportCount = productionProductMainMapper.selectCount(
                 Wrappers.<ProductionProductMain>lambdaQuery()

--
Gitblit v1.9.3