From 9cc2ddd5012a448d6187250121ba7f0cd0c5663b Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期一, 10 八月 2026 10:17:25 +0800
Subject: [PATCH] 下发报错修改

---
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  214 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 177 insertions(+), 37 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 200e95f..8278148 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;
@@ -30,6 +31,7 @@
 import com.ruoyi.technology.pojo.TechnologyOperationParam;
 import com.ruoyi.technology.pojo.TechnologyParam;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -48,6 +50,7 @@
  * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
  * @since 2026-04-21 03:55:52
  */
+@Slf4j
 @Service
 @RequiredArgsConstructor()
 public class ProductionBomStructureServiceImpl extends ServiceImpl<ProductionBomStructureMapper, ProductionBomStructure> implements ProductionBomStructureService {
@@ -136,6 +139,9 @@
             entity.setProductionOrderBomId(orderBomId);
             if (item.getId() == null) {
                 entity.setParentId(null);
+                // 鏂板鑺傜偣鐨勯渶姹傞噺鐢卞悗绔寜BOM鏍戝舰缁撴瀯閲嶆柊璁$畻锛屼笉娓呯┖鍙兘瀵艰嚧鍓嶇浼犵殑鍊兼孩鍑�
+                entity.setDemandedQuantity(null);
+                entity.setId(null);
                 insertList.add(entity);
                 tempEntityMap.put(item.getTempId(), entity);
             } else {
@@ -145,6 +151,11 @@
 
         // 鎵归噺鏂板锛屾嬁鍒版暟鎹簱鐢熸垚鐨勭湡瀹濱D
         if (!insertList.isEmpty()) {
+            for (ProductionBomStructure entity : insertList) {
+                log.info("鍑嗗鏂板BOM缁撴瀯鑺傜偣: productModelId={}, technologyOperationId={}, unitQuantity={}, demandedQuantity={}, unit={}",
+                        entity.getProductModelId(), entity.getTechnologyOperationId(),
+                        entity.getUnitQuantity(), entity.getDemandedQuantity(), entity.getUnit());
+            }
             this.saveBatch(insertList);
         }
 
@@ -215,24 +226,76 @@
         if (structureList == null || structureList.isEmpty()) {
             return;
         }
-        List<ProductionBomStructure> updateList = new ArrayList<>();
-        BigDecimal lastProcessDemandedQuantity = orderQuantity;
+        log.info("寮�濮嬫寜BOM鏍戝舰缁撴瀯璁$畻闇�姹傞噺锛岃鍗曟暟閲�={}, BOM鑺傜偣鎬绘暟={}", orderQuantity, structureList.size());
+        // 鏋勫缓 id 鈫� structure 鏄犲皠鍜� parentId 鈫� children 鏄犲皠
+        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+        Map<Long, List<ProductionBomStructure>> childrenMap = new LinkedHashMap<>();
         for (ProductionBomStructure structure : structureList) {
             if (structure == null || structure.getId() == null) {
                 continue;
             }
+            structureById.put(structure.getId(), structure);
+            Long parentId = structure.getParentId();
+            childrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
+        }
 
-            BigDecimal demandedQuantity = lastProcessDemandedQuantity.multiply(defaultDecimal(structure.getUnitQuantity()));
-//            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
-//                continue;
-//            }
+        List<ProductionBomStructure> updateList = new ArrayList<>();
+        // 浠庢牴鑺傜偣寮�濮嬶紝鎸夋爲褰㈠眰绾ч�愬眰璁$畻闇�姹傞噺
+        // 鏍硅妭鐐� parentId 涓� null 鎴� 0
+        Deque<Long> queue = new ArrayDeque<>();
+        List<ProductionBomStructure> rootNodes = childrenMap.get(null);
+        if (rootNodes != null) {
+            for (ProductionBomStructure root : rootNodes) {
+                queue.add(root.getId());
+            }
+        }
+        // parentId=0 鐨勪篃瑙嗕负鏍硅妭鐐�
+        List<ProductionBomStructure> zeroParentNodes = childrenMap.get(0L);
+        if (zeroParentNodes != null) {
+            for (ProductionBomStructure root : zeroParentNodes) {
+                if (!queue.contains(root.getId())) {
+                    queue.add(root.getId());
+                }
+            }
+        }
+
+        while (!queue.isEmpty()) {
+            Long nodeId = queue.poll();
+            ProductionBomStructure node = structureById.get(nodeId);
+            if (node == null) {
+                continue;
+            }
+            // 璁$畻褰撳墠鑺傜偣鐨勯渶姹傛暟閲� = 鐖惰妭鐐归渶姹傞噺 脳 鑷韩 unitQuantity
+            // 鏍硅妭鐐癸細闇�姹傞噺 = 璁㈠崟鏁伴噺 脳 unitQuantity
+            BigDecimal parentDemandedQuantity = orderQuantity;
+            Long parentId = node.getParentId();
+            if (parentId != null && parentId != 0L) {
+                ProductionBomStructure parent = structureById.get(parentId);
+                if (parent != null && parent.getDemandedQuantity() != null) {
+                    parentDemandedQuantity = parent.getDemandedQuantity();
+                }
+            }
+            BigDecimal demandedQuantity = parentDemandedQuantity.multiply(defaultDecimal(node.getUnitQuantity()));
+
+            log.info("BOM闇�姹傞噺璁$畻: nodeId={}, parentId={}, parentDemandedQuantity={}, unitQuantity={}, demandedQuantity={}",
+                    node.getId(), node.getParentId(), parentDemandedQuantity,
+                    defaultDecimal(node.getUnitQuantity()), demandedQuantity);
+
             ProductionBomStructure update = new ProductionBomStructure();
-            update.setId(structure.getId());
+            update.setId(node.getId());
             update.setDemandedQuantity(demandedQuantity);
             updateList.add(update);
-            structure.setDemandedQuantity(demandedQuantity);
-            lastProcessDemandedQuantity = demandedQuantity;
+            node.setDemandedQuantity(demandedQuantity);
+
+            // 灏嗗瓙鑺傜偣鍔犲叆闃熷垪
+            List<ProductionBomStructure> children = childrenMap.get(nodeId);
+            if (children != null) {
+                for (ProductionBomStructure child : children) {
+                    queue.add(child.getId());
+                }
+            }
         }
+
         if (!updateList.isEmpty()) {
             this.updateBatchById(updateList);
         }
@@ -262,7 +325,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;
@@ -291,15 +354,8 @@
                                             ProductionOrderBom orderBom,
                                             List<ProductionBomStructure> structureList,
                                             Long rootProductModelId) {
-        // 閲嶆柊鏌ヨBOM缁撴瀯锛屾寜瀛愯妭鐐逛紭鍏堟帓搴�
-        List<ProductionBomStructure> routingStructureList = this.list(
-                Wrappers.<ProductionBomStructure>lambdaQuery()
-                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
-                        .orderByDesc(ProductionBomStructure::getParentId)
-                        .orderByAsc(ProductionBomStructure::getId));
-
         ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
-        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(routingStructureList, rootProductModelId);
+        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
         List<ProductionOrderRoutingOperation> existingOperationList = productionOrderRoutingOperationMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                         .eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
@@ -393,12 +449,27 @@
         Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
 
         // 浣跨敤鍚庡簭閬嶅巻鏋勫缓鎿嶄綔鍒楄〃锛堝厛瀛愬悗鐖讹紝纭繚宸ヨ壓璺嚎椤哄簭姝g‘锛�
-        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
-        buildOperationListPostOrder(null, treeMap, uniqueOperationMap, structureById, rootProductModelId);
+        // 浣跨敤娣卞害浣滀负鎺掑簭渚濇嵁鐨勮緟鍔╃粨鏋�
+        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;
+            }
+            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();
@@ -414,29 +485,102 @@
         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, Integer> childCountMap = new HashMap<>();
+        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
 
-        // 绗竴閬嶏細缁熻姣忎釜鑺傜偣鐨勫瓙鑺傜偣鏁伴噺锛屽悓鏃舵瀯寤哄垵濮嬫槧灏�
+        // 鏋勫缓鐖�-瀛愭槧灏勫拰ID鏄犲皠
         for (ProductionBomStructure structure : structureList) {
             if (structure == null) continue;
             Long parentId = structure.getParentId();
-            childCountMap.merge(parentId, 1, Integer::sum);  // 缁熻姣忎釜鐖惰妭鐐规湁澶氬皯涓瓙鑺傜偣
             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 countA = childCountMap.getOrDefault(a.getId(), 0);
-                int countB = childCountMap.getOrDefault(b.getId(), 0);
-                return Integer.compare(countB, countA);  // 瀛愯妭鐐瑰鐨勬帓鍓嶉潰
+                // 浼樺厛鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈紙鏈�娣卞眰浼樺厛锛�
+                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,
@@ -455,7 +599,9 @@
             // 鍐嶅鐞嗗綋鍓嶈妭鐐�
             if (child.getTechnologyOperationId() != null) {
                 Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
-                uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(child, outputProductModelId), child);
+                String key = buildBomOperationDedupKey(child, outputProductModelId);
+                // 鍘婚噸鏃朵繚鐣欐繁搴︽渶澶х殑鎿嶄綔锛堝悗搴忛亶鍘嗗厛閬囧埌娣卞眰鑺傜偣锛屾墍浠ョ洿鎺ヨ鐩栧嵆鍙級
+                uniqueOperationMap.put(key, child);
             }
         }
     }
@@ -535,12 +681,6 @@
         if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
             update.setIsProduction(desiredOperation.getIsProduction());
             currentOperation.setIsProduction(desiredOperation.getIsProduction());
-            changed = true;
-        }
-        // 鏇存柊 dragSort 瀛楁锛岀‘淇濆伐鑹鸿矾绾块『搴忔纭�
-        if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
-            update.setDragSort(desiredOperation.getDragSort());
-            currentOperation.setDragSort(desiredOperation.getDragSort());
             changed = true;
         }
         if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
@@ -630,7 +770,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()
@@ -803,8 +943,8 @@
             return;
         }
         for (ProductionBomStructureDto node : source) {
-            flattenTree(node.getChildren(), result);  // 鍏堥�掑綊娣诲姞瀛愯妭鐐�
             result.add(node);
+            flattenTree(node.getChildren(), result);
         }
     }
 

--
Gitblit v1.9.3