From cb8ee71facb5520be75dcc9b77e245edc752650e Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期三, 13 五月 2026 15:00:12 +0800
Subject: [PATCH] fix:1.生产订单按照bom结构的单位需求数量更改 2.修改生产订单修改对应报工的数量

---
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 283 insertions(+), 5 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 00ab057..d0dab50 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -1,17 +1,29 @@
 package com.ruoyi.production.service.impl;
 
+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.production.bean.dto.ProductionBomStructureDto;
 import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
 import com.ruoyi.production.mapper.ProductionBomStructureMapper;
+import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
+import com.ruoyi.production.mapper.ProductionOrderBomMapper;
+import com.ruoyi.production.mapper.ProductionOrderMapper;
+import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
 import com.ruoyi.production.pojo.ProductionBomStructure;
+import com.ruoyi.production.pojo.ProductionOperationTask;
+import com.ruoyi.production.pojo.ProductionOrder;
+import com.ruoyi.production.pojo.ProductionOrderBom;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
 import com.ruoyi.production.service.ProductionBomStructureService;
 import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -25,13 +37,18 @@
 @RequiredArgsConstructor()
 public class ProductionBomStructureServiceImpl extends ServiceImpl<ProductionBomStructureMapper, ProductionBomStructure> implements ProductionBomStructureService {
 
-    private  final ProductionBomStructureMapper productionBomStructureMapper;
+    private final ProductionBomStructureMapper productionBomStructureMapper;
+    private final ProductionOrderBomMapper productionOrderBomMapper;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
+    private final ProductionOperationTaskMapper productionOperationTaskMapper;
 
     /**
      * 鏍规嵁BOM鏌ヨ骞剁粍瑁呯粨鏋勬爲銆�
      */
     @Override
     public List<ProductionBomStructureVo> listByBomId(Long bomId) {
+        // 鎸塀OMID鏌ヨ鐢熶骇缁撴瀯鏁版嵁
         List<ProductionBomStructureVo> list = productionBomStructureMapper.listByBomId(bomId);
         Map<Long, ProductionBomStructureVo> map = new HashMap<>();
         for (ProductionBomStructureVo node : list) {
@@ -54,4 +71,265 @@
         return tree;
     }
 
+    @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);
+
+        // 鏌ヨ鏁版嵁搴撳凡鏈夌粨鏋勶紝鐢ㄤ簬鍚庣画鍋氬鍒犳敼瀵规瘮
+        List<ProductionBomStructure> dbList = this.list(new LambdaQueryWrapper<ProductionBomStructure>()
+                .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId));
+
+        // 鏀堕泦鍓嶇浠嶇劧瀛樺湪鐨勮妭鐐笽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鏄犲皠
+        List<ProductionBomStructure> insertList = new ArrayList<>();
+        List<ProductionBomStructure> updateList = new ArrayList<>();
+        Map<String, ProductionBomStructure> tempEntityMap = new HashMap<>();
+
+        for (ProductionBomStructureDto item : flatDtoList) {
+            ProductionBomStructure entity = new ProductionBomStructure();
+            BeanUtils.copyProperties(item, entity);
+            entity.setProductionOrderBomId(orderBomId);
+            if (item.getId() == null) {
+                entity.setParentId(null);
+                insertList.add(entity);
+                tempEntityMap.put(item.getTempId(), entity);
+            } else {
+                updateList.add(entity);
+            }
+        }
+
+        // 鎵归噺鏂板锛屾嬁鍒版暟鎹簱鐢熸垚鐨勭湡瀹濱D
+        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());
+        return true;
+    }
+
+    private void syncDemandedQuantityAndTaskPlanQuantity(Long orderBomId, Long productionOrderId) {
+        if (orderBomId == null) {
+            return;
+        }
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectById(orderBomId);
+        if (orderBom == null) {
+            return;
+        }
+        Long currentProductionOrderId = productionOrderId != null ? productionOrderId : orderBom.getProductionOrderId();
+        if (currentProductionOrderId == null) {
+            return;
+        }
+        ProductionOrder productionOrder = productionOrderMapper.selectById(currentProductionOrderId);
+        if (productionOrder == null) {
+            return;
+        }
+
+        BigDecimal orderQuantity = defaultDecimal(productionOrder.getQuantity());
+        List<ProductionBomStructure> structureList = this.list(
+                Wrappers.<ProductionBomStructure>lambdaQuery()
+                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId)
+                        .orderByAsc(ProductionBomStructure::getId));
+        syncStructureDemandedQuantity(structureList, orderQuantity);
+        syncTaskPlanQuantity(
+                currentProductionOrderId,
+                structureList,
+                orderQuantity,
+                orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId());
+    }
+
+    private void syncStructureDemandedQuantity(List<ProductionBomStructure> structureList, BigDecimal orderQuantity) {
+        if (structureList == null || structureList.isEmpty()) {
+            return;
+        }
+        List<ProductionBomStructure> updateList = new ArrayList<>();
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null || structure.getId() == null) {
+                continue;
+            }
+            BigDecimal demandedQuantity = defaultDecimal(structure.getUnitQuantity()).multiply(orderQuantity);
+            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
+                continue;
+            }
+            ProductionBomStructure update = new ProductionBomStructure();
+            update.setId(structure.getId());
+            update.setDemandedQuantity(demandedQuantity);
+            updateList.add(update);
+            structure.setDemandedQuantity(demandedQuantity);
+        }
+        if (!updateList.isEmpty()) {
+            this.updateBatchById(updateList);
+        }
+    }
+
+    private void syncTaskPlanQuantity(Long productionOrderId,
+                                      List<ProductionBomStructure> structureList,
+                                      BigDecimal orderQuantity,
+                                      Long rootProductModelId) {
+        List<ProductionOperationTask> taskList = productionOperationTaskMapper.selectList(
+                Wrappers.<ProductionOperationTask>lambdaQuery()
+                        .eq(ProductionOperationTask::getProductionOrderId, productionOrderId)
+                        .orderByAsc(ProductionOperationTask::getId));
+        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));
+        Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId, orderQuantity);
+
+        for (ProductionOperationTask task : taskList) {
+            if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
+                continue;
+            }
+            ProductionOrderRoutingOperation routingOperation = routingOperationMap.get(task.getProductionOrderRoutingOperationId());
+            if (routingOperation == null || routingOperation.getTechnologyRoutingOperationId() == null) {
+                continue;
+            }
+            BigDecimal planQuantity = resolveTaskPlanQuantity(routingOperation, demandedQuantityMap, orderQuantity);
+            if (compareDecimal(task.getPlanQuantity(), planQuantity) == 0) {
+                continue;
+            }
+            ProductionOperationTask update = new ProductionOperationTask();
+            update.setId(task.getId());
+            update.setPlanQuantity(planQuantity);
+            productionOperationTaskMapper.updateById(update);
+        }
+    }
+
+    private Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> structureList,
+                                                                      Long rootProductModelId,
+                                                                      BigDecimal orderQuantity) {
+        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<>();
+        for (ProductionBomStructure bomStructure : structureList) {
+            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null || bomStructure.getUnitQuantity() == null) {
+                continue;
+            }
+            Long outputProductModelId = resolveOutputProductModelId(bomStructure, structureById, rootProductModelId);
+            String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
+            demandedQuantityMap.merge(key, bomStructure.getUnitQuantity().multiply(orderQuantity), BigDecimal::add);
+        }
+        return demandedQuantityMap;
+    }
+
+    private BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
+                                               Map<String, BigDecimal> demandedQuantityMap,
+                                               BigDecimal orderQuantity) {
+        if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
+            return orderQuantity;
+        }
+        String key = buildOperationDemandedQuantityKey(
+                routingOperation.getTechnologyOperationId(),
+                routingOperation.getProductModelId());
+        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 Long resolveOutputProductModelId(ProductionBomStructure bomStructure,
+                                             Map<Long, ProductionBomStructure> structureById,
+                                             Long rootProductModelId) {
+        if (bomStructure == null) {
+            return rootProductModelId;
+        }
+        Long parentId = bomStructure.getParentId();
+        if (parentId == null) {
+            return rootProductModelId != null ? rootProductModelId : bomStructure.getProductModelId();
+        }
+        ProductionBomStructure parent = structureById.get(parentId);
+        if (parent != null && parent.getProductModelId() != null) {
+            return parent.getProductModelId();
+        }
+        return rootProductModelId != null ? rootProductModelId : bomStructure.getProductModelId();
+    }
+
+    private BigDecimal defaultDecimal(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    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