From 3066a8f5c1f475997bfe23857ba4bae9395900c4 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期四, 13 八月 2026 10:19:24 +0800
Subject: [PATCH] fix: 领料功能修改,移除订单领料,添加工序领料功能,支持按工序查询物料与已领料记录

---
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  381 +++++++++++++++++-------------------------------------
 1 files changed, 119 insertions(+), 262 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 31cdc79..304d0e8 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.production.bean.dto.ProductionBomStructureDto;
 import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
@@ -23,6 +24,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,7 +32,6 @@
 import com.ruoyi.technology.pojo.TechnologyOperationParam;
 import com.ruoyi.technology.pojo.TechnologyParam;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -60,123 +61,137 @@
     private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
     private final ProductionProductMainMapper productionProductMainMapper;
+    private final ProductModelMapper productModelMapper;
     private final TechnologyOperationMapper technologyOperationMapper;
     private final TechnologyOperationParamMapper technologyOperationParamMapper;
     private final TechnologyParamMapper technologyParamMapper;
 
     /**
-     * 鏍规嵁BOM鏌ヨ骞剁粍瑁呯粨鏋勬爲銆�
+     * 鎸夎鍗旴OM鏌ヨ鎵佸钩鐗╂枡鏄庣粏銆�
      */
     @Override
     public List<ProductionBomStructureVo> listByBomId(Long bomId) {
-        // 鎸塀OMID鏌ヨ鐢熶骇缁撴瀯鏁版嵁
-        List<ProductionBomStructureVo> list = productionBomStructureMapper.listByBomId(bomId);
-        Map<Long, ProductionBomStructureVo> map = new HashMap<>();
-        for (ProductionBomStructureVo node : list) {
-            node.setChildren(new ArrayList<>());
-            map.put(node.getId(), node);
+        if (bomId == null) {
+            return new ArrayList<>();
         }
-
-        List<ProductionBomStructureVo> tree = new ArrayList<>();
-        for (ProductionBomStructureVo node : list) {
-            Long parentId = node.getParentId();
-            if (parentId == null || parentId == 0L) {
-                tree.add(node);
-                continue;
-            }
-            ProductionBomStructureVo parent = map.get(parentId);
-            if (parent != null) {
-                parent.getChildren().add(node);
-            }
-        }
-        return tree;
+        return productionBomStructureMapper.listByBomId(bomId);
     }
 
+    /**
+     * 鎸夌敓浜ц鍗曟煡璇㈣鍗旴OM蹇収鐨勬墎骞崇墿鏂欐槑缁嗐��
+     */
+    @Override
+    public List<ProductionBomStructureVo> listByOrderId(Long productionOrderId) {
+        if (productionOrderId == null) {
+            return new ArrayList<>();
+        }
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+                Wrappers.<ProductionOrderBom>lambdaQuery()
+                        .eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
+                        .orderByDesc(ProductionOrderBom::getId)
+                        .last("limit 1"));
+        if (orderBom == null || orderBom.getId() == null) {
+            return new ArrayList<>();
+        }
+        return listByBomId(orderBom.getId());
+    }
+
+    /**
+     * 鍏ㄩ噺鍚屾璁㈠崟BOM蹇収鐨勬墎骞崇墿鏂欐槑缁嗭紝骞舵寜鍏朵腑鐨勫伐搴忛噸寤鸿鍗曞伐鑹鸿矾绾垮揩鐓т笌宸ュ崟銆�
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean addProductionBomStructure(ProductionBomStructureDto dto) {
-        // 鏂板鐢熶骇BOM缁撴瀯
-        // 璇诲彇褰撳墠璁㈠崟BOM涓婚敭锛屽苟鎶婂墠绔爲缁撴瀯鎷嶅钩鎴愬垪琛�
         Long orderBomId = dto.getProductionOrderBomId();
-        List<ProductionBomStructureDto> flatDtoList = new ArrayList<>();
-        flattenTree(dto.getChildren(), flatDtoList);
+        if (orderBomId == null) {
+            throw new ServiceException("璁㈠崟BOM ID涓嶈兘涓虹┖");
+        }
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectById(orderBomId);
+        if (orderBom == null) {
+            throw new ServiceException("璁㈠崟BOM涓嶅瓨鍦�");
+        }
+        Long productionOrderId = dto.getProductionOrderId() != null
+                ? dto.getProductionOrderId()
+                : orderBom.getProductionOrderId();
 
-        // 鏌ヨ鏁版嵁搴撳凡鏈夌粨鏋勶紝鐢ㄤ簬鍚庣画鍋氬鍒犳敼瀵规瘮
+        List<ProductionBomStructureDto> detailList = dto.getDetailList() == null
+                ? Collections.emptyList()
+                : dto.getDetailList();
+
         List<ProductionBomStructure> dbList = this.list(new LambdaQueryWrapper<ProductionBomStructure>()
                 .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId));
+        Set<Long> dbIds = dbList.stream().map(ProductionBomStructure::getId).collect(Collectors.toSet());
 
-        // 鏀堕泦鍓嶇浠嶇劧瀛樺湪鐨勮妭鐐笽D
-        Set<Long> frontendIds = new HashSet<>();
-        for (ProductionBomStructureDto item : flatDtoList) {
-            if (item.getId() != null) {
-                frontendIds.add(item.getId());
-            }
-        }
-
-        // 璁$畻闇�瑕佸垹闄ょ殑鑺傜偣锛堟暟鎹簱鏈夈�佸墠绔凡鍒犻櫎锛�
-        Set<Long> deleteIds = new HashSet<>();
-        for (ProductionBomStructure dbItem : dbList) {
-            if (!frontendIds.contains(dbItem.getId())) {
-                deleteIds.add(dbItem.getId());
-            }
-        }
-        // 鍏堝垹鎺夊墠绔凡缁忕Щ闄ょ殑鑺傜偣
-        if (!deleteIds.isEmpty()) {
-            this.removeByIds(deleteIds);
-        }
-
-        // 鎸夋槸鍚︽湁ID鎷嗗垎涓烘柊澧炲拰鏇存柊锛屽悓鏃剁紦瀛樻柊澧炶妭鐐圭殑涓存椂ID鏄犲皠
+        Set<Long> submittedIds = new HashSet<>();
+        Set<String> relationKeys = new HashSet<>();
         List<ProductionBomStructure> insertList = new ArrayList<>();
         List<ProductionBomStructure> updateList = new ArrayList<>();
-        Map<String, ProductionBomStructure> tempEntityMap = new HashMap<>();
 
-        for (ProductionBomStructureDto item : flatDtoList) {
+        for (ProductionBomStructureDto item : detailList) {
+            Long productModelId = item.getProductModelId();
+            Long technologyOperationId = item.getTechnologyOperationId();
+            if (productModelId == null) {
+                throw new ServiceException("璇烽�夋嫨鐗╂枡瑙勬牸");
+            }
+            if (productModelMapper.selectById(productModelId) == null) {
+                throw new ServiceException("鐗╂枡瑙勬牸涓嶅瓨鍦�");
+            }
+            if (technologyOperationId == null) {
+                throw new ServiceException("璇烽�夋嫨娑堣�楀伐搴�");
+            }
+            if (technologyOperationMapper.selectById(technologyOperationId) == null) {
+                throw new ServiceException("娑堣�楀伐搴忎笉瀛樺湪");
+            }
+            if (productModelId.equals(orderBom.getProductModelId())) {
+                throw new ServiceException("鎴愬搧瑙勬牸涓嶈兘浣滀负鑷韩鐨勭墿鏂�");
+            }
+            if (!relationKeys.add(productModelId + "#" + technologyOperationId)) {
+                throw new ServiceException("鍚屼竴鐗╂枡瑙勬牸鍦ㄥ悓涓�宸ュ簭涓嬩笉鑳介噸澶嶉厤缃�");
+            }
+
             ProductionBomStructure entity = new ProductionBomStructure();
-            BeanUtils.copyProperties(item, entity);
             entity.setProductionOrderBomId(orderBomId);
+            entity.setProductionOrderId(productionOrderId);
+            entity.setProductModelId(productModelId);
+            entity.setTechnologyOperationId(technologyOperationId);
+            // 鎵佸钩蹇収涓嶅啀浣跨敤灞傜骇涓庢暟閲忚涔�
+            entity.setParentId(null);
+            entity.setUnitQuantity(null);
+            entity.setDemandedQuantity(null);
+            entity.setUnit(null);
+
             if (item.getId() == null) {
-                entity.setParentId(null);
                 insertList.add(entity);
-                tempEntityMap.put(item.getTempId(), entity);
             } else {
+                if (!dbIds.contains(item.getId())) {
+                    throw new ServiceException("璁㈠崟BOM鐗╂枡鏄庣粏涓嶅瓨鍦ㄦ垨涓嶅睘浜庡綋鍓嶈鍗旴OM");
+                }
+                entity.setId(item.getId());
+                submittedIds.add(item.getId());
                 updateList.add(entity);
             }
         }
 
-        // 鎵归噺鏂板锛屾嬁鍒版暟鎹簱鐢熸垚鐨勭湡瀹濱D
+        Set<Long> deleteIds = new HashSet<>(dbIds);
+        deleteIds.removeAll(submittedIds);
+        if (!deleteIds.isEmpty()) {
+            this.removeByIds(deleteIds);
+        }
+        if (!updateList.isEmpty()) {
+            this.updateBatchById(updateList);
+        }
         if (!insertList.isEmpty()) {
             this.saveBatch(insertList);
         }
 
-        // 鏂板鑺傜偣浜屾鍥炲啓鐖禝D锛堝墠绔紶鐨勬槸涓存椂鐖禝D锛�
-        List<ProductionBomStructure> parentFixList = new ArrayList<>();
-        for (ProductionBomStructureDto item : flatDtoList) {
-            if (item.getId() == null && item.getParentTempId() != null) {
-                ProductionBomStructure child = tempEntityMap.get(item.getTempId());
-                if (child == null) {
-                    continue;
-                }
-                ProductionBomStructure parent = tempEntityMap.get(item.getParentTempId());
-                // 鐖惰妭鐐规槸鏈鏂板鏃讹紝鐩存帴鐢ㄦ柊澧炲悗鐨勭湡瀹濱D锛涘惁鍒欏洖閫�涓哄墠绔紶鍏ョ埗ID
-                Long realParentId = parent != null ? parent.getId() : Long.valueOf(item.getParentTempId());
-                child.setParentId(realParentId);
-                parentFixList.add(child);
-            }
-        }
-
-        // 鍥炲啓鏂板鑺傜偣鐨勭埗瀛愬叧绯�
-        if (!parentFixList.isEmpty()) {
-            this.updateBatchById(parentFixList);
-        }
-        // 鎵归噺鏇存柊宸叉湁鑺傜偣
-        if (!updateList.isEmpty()) {
-            this.updateBatchById(updateList);
-        }
-        syncDemandedQuantityAndTaskPlanQuantity(orderBomId, dto.getProductionOrderId());
+        syncRoutingAndTaskByStructure(orderBomId, productionOrderId);
         return true;
     }
 
-    private void syncDemandedQuantityAndTaskPlanQuantity(Long orderBomId, Long productionOrderId) {
+    /**
+     * 璁㈠崟BOM鐗╂枡鍙樺寲鍚庯紝鎸夊叾宸ュ簭闆嗗悎閲嶅缓璁㈠崟宸ヨ壓璺嚎宸ュ簭蹇収涓庡伐鍗曡鍒掓暟閲忋��
+     */
+    private void syncRoutingAndTaskByStructure(Long orderBomId, Long productionOrderId) {
         if (orderBomId == null) {
             return;
         }
@@ -193,55 +208,20 @@
             return;
         }
 
-        BigDecimal orderQuantity = defaultDecimal(productionOrder.getQuantity());
         List<ProductionBomStructure> structureList = this.list(
                 Wrappers.<ProductionBomStructure>lambdaQuery()
                         .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId)
                         .orderByAsc(ProductionBomStructure::getId));
-        //鍚屾闇�姹傛暟閲�
-        syncStructureDemandedQuantity(structureList, orderQuantity);
-        Long rootProductModelId = orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId();
-        //鍚屾鐢熶骇宸ヨ壓璺嚎
+        Long rootProductModelId = orderBom.getProductModelId() != null
+                ? orderBom.getProductModelId()
+                : productionOrder.getProductModelId();
+        // 鍚屾鐢熶骇宸ヨ壓璺嚎蹇収
         syncRoutingOperationsByBom(currentProductionOrderId, productionOrder, orderBom, structureList, rootProductModelId);
-        //鍚屾宸ュ崟
-        syncTaskPlanQuantity(
-                currentProductionOrderId,
-                structureList,
-                orderQuantity,
-                rootProductModelId);
+        // 鍚屾宸ュ崟璁″垝鏁伴噺锛氭墎骞矪OM鏃犳暟閲忛厤缃紝璁″垝鏁伴噺缁熶竴鍙栬鍗曟暟閲�
+        syncTaskPlanQuantity(currentProductionOrderId, TaskPlanQuantityUtil.resolveTaskPlanQuantity(productionOrder));
     }
 
-    private void syncStructureDemandedQuantity(List<ProductionBomStructure> structureList, BigDecimal orderQuantity) {
-        if (structureList == null || structureList.isEmpty()) {
-            return;
-        }
-        List<ProductionBomStructure> updateList = new ArrayList<>();
-        BigDecimal lastProcessDemandedQuantity = orderQuantity;
-        for (ProductionBomStructure structure : structureList) {
-            if (structure == null || structure.getId() == null) {
-                continue;
-            }
-
-            BigDecimal demandedQuantity = lastProcessDemandedQuantity.multiply(defaultDecimal(structure.getUnitQuantity()));
-//            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
-//                continue;
-//            }
-            ProductionBomStructure update = new ProductionBomStructure();
-            update.setId(structure.getId());
-            update.setDemandedQuantity(demandedQuantity);
-            updateList.add(update);
-            structure.setDemandedQuantity(demandedQuantity);
-            lastProcessDemandedQuantity = demandedQuantity;
-        }
-        if (!updateList.isEmpty()) {
-            this.updateBatchById(updateList);
-        }
-    }
-
-    private void syncTaskPlanQuantity(Long productionOrderId,
-                                      List<ProductionBomStructure> structureList,
-                                      BigDecimal orderQuantity,
-                                      Long rootProductModelId) {
+    private void syncTaskPlanQuantity(Long productionOrderId, BigDecimal planQuantity) {
         List<ProductionOperationTask> taskList = productionOperationTaskMapper.selectList(
                 Wrappers.<ProductionOperationTask>lambdaQuery()
                         .eq(ProductionOperationTask::getProductionOrderId, productionOrderId)
@@ -249,33 +229,10 @@
         if (taskList == null || taskList.isEmpty()) {
             return;
         }
-        Set<Long> routingOperationIds = taskList.stream()
-                .map(ProductionOperationTask::getProductionOrderRoutingOperationId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        if (routingOperationIds.isEmpty()) {
-            return;
-        }
-        Map<Long, ProductionOrderRoutingOperation> routingOperationMap = productionOrderRoutingOperationMapper
-                .selectBatchIds(routingOperationIds)
-                .stream()
-                .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);
         for (ProductionOperationTask task : taskList) {
-            if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
+            if (task == null || task.getId() == null) {
                 continue;
             }
-            ProductionOrderRoutingOperation routingOperation = routingOperationMap.get(task.getProductionOrderRoutingOperationId());
-            if (routingOperation == null) {
-                continue;
-            }
-            BigDecimal planQuantity = resolveTaskPlanQuantity(
-                    routingOperation,
-                    demandedQuantityMap,
-                    orderQuantity,
-                    rootProductModelId);
             if (compareDecimal(task.getPlanQuantity(), planQuantity) == 0) {
                 continue;
             }
@@ -310,7 +267,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);
         }
@@ -373,30 +330,30 @@
         return orderRouting;
     }
 
+    /**
+     * 鎵佸钩BOM鎸夊伐搴忓幓閲嶇敓鎴愭湡鏈涚殑璁㈠崟宸ュ簭鍒楄〃锛�
+     * 椤哄簭鍙栫墿鏂欐槑缁嗕腑宸ュ簭棣栨鍑虹幇鐨勯『搴忥紝浜у嚭瑙勬牸鍥哄畾涓鸿鍗曟垚鍝佽鏍笺��
+     */
     private List<ProductionOrderRoutingOperation> buildDesiredRoutingOperationList(List<ProductionBomStructure> structureList,
                                                                                    Long rootProductModelId) {
         if (structureList == null || structureList.isEmpty()) {
             return Collections.emptyList();
         }
-        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) {
+        Set<Long> uniqueOperationIdList = new LinkedHashSet<>();
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null || structure.getTechnologyOperationId() == null) {
                 continue;
             }
-            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
-            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
+            uniqueOperationIdList.add(structure.getTechnologyOperationId());
         }
-        List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
+
+        List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>(uniqueOperationIdList.size());
         int dragSort = 1;
-        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
-            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
-            TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId());
+        for (Long operationId : uniqueOperationIdList) {
+            TechnologyOperation technologyOperation = getTechnologyOperation(operationId);
             ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
-            routingOperation.setProductModelId(outputProductModelId);
-            routingOperation.setTechnologyOperationId(bomStructure.getTechnologyOperationId());
+            routingOperation.setProductModelId(rootProductModelId);
+            routingOperation.setTechnologyOperationId(operationId);
             routingOperation.setOperationName(technologyOperation == null ? null : technologyOperation.getName());
             routingOperation.setIsQuality(technologyOperation == null ? null : technologyOperation.getIsQuality());
             routingOperation.setIsProduction(technologyOperation == null ? null : technologyOperation.getIsProduction());
@@ -571,7 +528,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()
@@ -612,94 +569,8 @@
         }
     }
 
-    private Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> structureList,
-                                                                      Long rootProductModelId) {
-        if (structureList == null || structureList.isEmpty()) {
-            return Collections.emptyMap();
-        }
-        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, BigDecimal> demandedQuantityMap = new HashMap<>();
-        Set<String> mergedOutputNodeKeySet = new HashSet<>();
-        for (ProductionBomStructure bomStructure : structureList) {
-            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
-                continue;
-            }
-            // Resolve the output node first, then read the output node demand for the task plan quantity.
-            ProductionBomStructure outputNode = resolveOperationOutputNode(bomStructure, structureById);
-            Long outputProductModelId = resolveOutputProductModelId(outputNode, rootProductModelId);
-            if (outputProductModelId == null) {
-                continue;
-            }
-            String mergedOutputNodeKey = buildOperationOutputNodeKey(
-                    bomStructure.getTechnologyOperationId(),
-                    outputNode == null ? null : outputNode.getId(),
-                    outputProductModelId);
-            if (!mergedOutputNodeKeySet.add(mergedOutputNodeKey)) {
-                continue;
-            }
-            // Multiple input rows can point to the same output node, so only count that output demand once.
-            String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
-            demandedQuantityMap.merge(key, defaultDecimal(outputNode == null ? null : outputNode.getDemandedQuantity()), BigDecimal::add);
-        }
-        return demandedQuantityMap;
-    }
-
-    private BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
-                                               Map<String, BigDecimal> demandedQuantityMap,
-                                               BigDecimal orderQuantity,
-                                               Long rootProductModelId) {
-        if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
-            return orderQuantity;
-        }
-        Long outputProductModelId = routingOperation.getProductModelId() != null
-                ? routingOperation.getProductModelId()
-                : rootProductModelId;
-        String key = buildOperationDemandedQuantityKey(
-                routingOperation.getTechnologyOperationId(),
-                outputProductModelId);
-        BigDecimal planQuantity = demandedQuantityMap.get(key);
-        return planQuantity != null ? planQuantity : orderQuantity;
-    }
-
-    private String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
-        return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
-    }
-
     private String buildRoutingOperationBucketKey(Long operationId, Long outputProductModelId) {
         return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
-    }
-
-    private String buildBomOperationDedupKey(ProductionBomStructure bomStructure, Long outputProductModelId) {
-        Long operationId = bomStructure == null ? null : bomStructure.getTechnologyOperationId();
-        Long parentId = bomStructure == null ? null : bomStructure.getParentId();
-        return operationId + "#" + outputProductModelId + "#" + parentId;
-    }
-
-    private String buildOperationOutputNodeKey(Long operationId, Long outputNodeId, Long outputProductModelId) {
-        return String.valueOf(operationId) + "#" + String.valueOf(outputNodeId) + "#" + String.valueOf(outputProductModelId);
-    }
-
-    private ProductionBomStructure resolveOperationOutputNode(ProductionBomStructure bomStructure,
-                                                              Map<Long, ProductionBomStructure> structureById) {
-        if (bomStructure == null) {
-            return null;
-        }
-        // The root node is the first output node; other rows use their direct parent as the current operation output.
-        if (bomStructure.getParentId() == null) {
-            return bomStructure;
-        }
-        ProductionBomStructure parent = structureById.get(bomStructure.getParentId());
-        return parent != null ? parent : bomStructure;
-    }
-
-    private Long resolveOutputProductModelId(ProductionBomStructure outputNode,
-                                             Long rootProductModelId) {
-        if (outputNode == null) {
-            return rootProductModelId;
-        }
-        return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId;
     }
 
     private TechnologyOperation getTechnologyOperation(Long technologyOperationId) {
@@ -733,20 +604,6 @@
 
     private int compareDecimal(BigDecimal left, BigDecimal right) {
         return defaultDecimal(left).compareTo(defaultDecimal(right));
-    }
-
-    /**
-     * 灏嗘爲褰㈢粨鏋勬媿骞虫垚鍒楄〃锛屼究浜庣粺涓�淇濆瓨銆�
-     */
-    private void flattenTree(List<ProductionBomStructureDto> source, List<ProductionBomStructureDto> result) {
-        // 鎵佸钩鍖栧鐞嗘爲
-        if (source == null) {
-            return;
-        }
-        for (ProductionBomStructureDto node : source) {
-            result.add(node);
-            flattenTree(node.getChildren(), result);
-        }
     }
 
 }

--
Gitblit v1.9.3