From f57064d2fa563ee4cfeeccd715850ba8b8aa4f60 Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期一, 18 五月 2026 09:44:33 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New_pro' into dev_宁夏_英泽防锈

---
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  405 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 399 insertions(+), 6 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 2bded77..31cdc79 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -3,25 +3,40 @@
 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.common.exception.ServiceException;
 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.ProductionOrderRoutingMapper;
 import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
+import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
+import com.ruoyi.production.mapper.ProductionProductMainMapper;
 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.ProductionOrderRouting;
 import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
+import com.ruoyi.production.pojo.ProductionProductMain;
 import com.ruoyi.production.service.ProductionBomStructureService;
+import com.ruoyi.technology.mapper.TechnologyOperationMapper;
+import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
+import com.ruoyi.technology.mapper.TechnologyParamMapper;
+import com.ruoyi.technology.pojo.TechnologyOperation;
+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;
 
 import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -40,8 +55,14 @@
     private final ProductionBomStructureMapper productionBomStructureMapper;
     private final ProductionOrderBomMapper productionOrderBomMapper;
     private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
     private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
+    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
+    private final ProductionProductMainMapper productionProductMainMapper;
+    private final TechnologyOperationMapper technologyOperationMapper;
+    private final TechnologyOperationParamMapper technologyOperationParamMapper;
+    private final TechnologyParamMapper technologyParamMapper;
 
     /**
      * 鏍规嵁BOM鏌ヨ骞剁粍瑁呯粨鏋勬爲銆�
@@ -177,12 +198,17 @@
                 Wrappers.<ProductionBomStructure>lambdaQuery()
                         .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId)
                         .orderByAsc(ProductionBomStructure::getId));
+        //鍚屾闇�姹傛暟閲�
         syncStructureDemandedQuantity(structureList, orderQuantity);
+        Long rootProductModelId = orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId();
+        //鍚屾鐢熶骇宸ヨ壓璺嚎
+        syncRoutingOperationsByBom(currentProductionOrderId, productionOrder, orderBom, structureList, rootProductModelId);
+        //鍚屾宸ュ崟
         syncTaskPlanQuantity(
                 currentProductionOrderId,
                 structureList,
                 orderQuantity,
-                orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId());
+                rootProductModelId);
     }
 
     private void syncStructureDemandedQuantity(List<ProductionBomStructure> structureList, BigDecimal orderQuantity) {
@@ -190,19 +216,22 @@
             return;
         }
         List<ProductionBomStructure> updateList = new ArrayList<>();
+        BigDecimal lastProcessDemandedQuantity = orderQuantity;
         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;
-            }
+
+            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);
@@ -239,7 +268,7 @@
                 continue;
             }
             ProductionOrderRoutingOperation routingOperation = routingOperationMap.get(task.getProductionOrderRoutingOperationId());
-            if (routingOperation == null || routingOperation.getTechnologyRoutingOperationId() == null) {
+            if (routingOperation == null) {
                 continue;
             }
             BigDecimal planQuantity = resolveTaskPlanQuantity(
@@ -256,6 +285,333 @@
             productionOperationTaskMapper.updateById(update);
         }
     }
+
+    private void syncRoutingOperationsByBom(Long productionOrderId,
+                                            ProductionOrder productionOrder,
+                                            ProductionOrderBom orderBom,
+                                            List<ProductionBomStructure> structureList,
+                                            Long rootProductModelId) {
+        ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
+        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
+        List<ProductionOrderRoutingOperation> existingOperationList = productionOrderRoutingOperationMapper.selectList(
+                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
+                        .eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
+                        .eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId)
+                        .orderByAsc(ProductionOrderRoutingOperation::getDragSort)
+                        .orderByAsc(ProductionOrderRoutingOperation::getId));
+        Map<String, Deque<ProductionOrderRoutingOperation>> existingBucketMap = buildExistingRoutingOperationBucketMap(existingOperationList);
+        List<ProductionOrderRoutingOperation> finalOperationList = new ArrayList<>();
+        for (ProductionOrderRoutingOperation desiredOperation : desiredOperationList) {
+            String bucketKey = buildRoutingOperationBucketKey(
+                    desiredOperation.getTechnologyOperationId(),
+                    desiredOperation.getProductModelId());
+            Deque<ProductionOrderRoutingOperation> matchedQueue = existingBucketMap.get(bucketKey);
+            ProductionOrderRoutingOperation matchedOperation = matchedQueue == null ? null : matchedQueue.pollFirst();
+            if (matchedOperation == null) {
+                matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
+            } else {
+                updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation);
+            }
+            finalOperationList.add(matchedOperation);
+        }
+        for (Deque<ProductionOrderRoutingOperation> queue : existingBucketMap.values()) {
+            while (queue != null && !queue.isEmpty()) {
+                removeRoutingOperationSnapshot(queue.pollFirst());
+            }
+        }
+        syncRoutingOperationTasks(productionOrderId, finalOperationList);
+    }
+
+    private ProductionOrderRouting getOrCreateOrderRoutingSnapshot(Long productionOrderId,
+                                                                   ProductionOrder productionOrder,
+                                                                   ProductionOrderBom orderBom,
+                                                                   Long rootProductModelId) {
+        ProductionOrderRouting orderRouting = productionOrderRoutingMapper.selectOne(
+                Wrappers.<ProductionOrderRouting>lambdaQuery()
+                        .eq(ProductionOrderRouting::getProductionOrderId, productionOrderId)
+                        .orderByDesc(ProductionOrderRouting::getId)
+                        .last("limit 1"));
+        if (orderRouting == null) {
+            orderRouting = new ProductionOrderRouting();
+            orderRouting.setProductionOrderId(productionOrderId);
+            orderRouting.setProductModelId(rootProductModelId);
+            orderRouting.setTechnologyRoutingId(productionOrder == null ? null : productionOrder.getTechnologyRoutingId());
+            orderRouting.setBomId(orderBom == null ? null : orderBom.getBomId());
+            orderRouting.setOrderBomId(orderBom == null ? null : orderBom.getId());
+            productionOrderRoutingMapper.insert(orderRouting);
+            return orderRouting;
+        }
+        ProductionOrderRouting update = new ProductionOrderRouting();
+        update.setId(orderRouting.getId());
+        boolean changed = false;
+        if (!Objects.equals(orderRouting.getProductModelId(), rootProductModelId)) {
+            update.setProductModelId(rootProductModelId);
+            orderRouting.setProductModelId(rootProductModelId);
+            changed = true;
+        }
+        Long technologyRoutingId = productionOrder == null ? null : productionOrder.getTechnologyRoutingId();
+        if (!Objects.equals(orderRouting.getTechnologyRoutingId(), technologyRoutingId)) {
+            update.setTechnologyRoutingId(technologyRoutingId);
+            orderRouting.setTechnologyRoutingId(technologyRoutingId);
+            changed = true;
+        }
+        Long bomId = orderBom == null ? null : orderBom.getBomId();
+        if (!Objects.equals(orderRouting.getBomId(), bomId)) {
+            update.setBomId(bomId);
+            orderRouting.setBomId(bomId);
+            changed = true;
+        }
+        Long orderBomId = orderBom == null ? null : orderBom.getId();
+        if (!Objects.equals(orderRouting.getOrderBomId(), orderBomId)) {
+            update.setOrderBomId(orderBomId);
+            orderRouting.setOrderBomId(orderBomId);
+            changed = true;
+        }
+        if (changed) {
+            productionOrderRoutingMapper.updateById(update);
+        }
+        return orderRouting;
+    }
+
+    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) {
+                continue;
+            }
+            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
+            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
+        }
+        List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
+        int dragSort = 1;
+        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
+            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
+            TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId());
+            ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
+            routingOperation.setProductModelId(outputProductModelId);
+            routingOperation.setTechnologyOperationId(bomStructure.getTechnologyOperationId());
+            routingOperation.setOperationName(technologyOperation == null ? null : technologyOperation.getName());
+            routingOperation.setIsQuality(technologyOperation == null ? null : technologyOperation.getIsQuality());
+            routingOperation.setIsProduction(technologyOperation == null ? null : technologyOperation.getIsProduction());
+            routingOperation.setType(technologyOperation == null ? null : technologyOperation.getType());
+            routingOperation.setDragSort(dragSort++);
+            desiredOperationList.add(routingOperation);
+        }
+        return desiredOperationList;
+    }
+
+    private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
+        Map<String, Deque<ProductionOrderRoutingOperation>> existingBucketMap = new LinkedHashMap<>();
+        if (existingOperationList == null || existingOperationList.isEmpty()) {
+            return existingBucketMap;
+        }
+        for (ProductionOrderRoutingOperation routingOperation : existingOperationList) {
+            String bucketKey = buildRoutingOperationBucketKey(
+                    routingOperation.getTechnologyOperationId(),
+                    routingOperation.getProductModelId());
+            existingBucketMap.computeIfAbsent(bucketKey, key -> new ArrayDeque<>()).addLast(routingOperation);
+        }
+        return existingBucketMap;
+    }
+
+    private ProductionOrderRoutingOperation insertRoutingOperationSnapshot(Long orderRoutingId,
+                                                                           Long productionOrderId,
+                                                                           ProductionOrderRoutingOperation desiredOperation) {
+        ProductionOrderRoutingOperation insert = new ProductionOrderRoutingOperation();
+        insert.setOrderRoutingId(orderRoutingId);
+        insert.setProductionOrderId(productionOrderId);
+        insert.setProductModelId(desiredOperation.getProductModelId());
+        insert.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
+        insert.setOperationName(desiredOperation.getOperationName());
+        insert.setIsQuality(desiredOperation.getIsQuality());
+        insert.setIsProduction(desiredOperation.getIsProduction());
+        insert.setType(desiredOperation.getType());
+        insert.setDragSort(desiredOperation.getDragSort());
+        productionOrderRoutingOperationMapper.insert(insert);
+        syncRoutingOperationParams(insert.getId(), productionOrderId, insert.getTechnologyOperationId());
+        return insert;
+    }
+
+    private void updateRoutingOperationSnapshotIfNecessary(ProductionOrderRoutingOperation currentOperation,
+                                                           Long orderRoutingId,
+                                                           Long productionOrderId,
+                                                           ProductionOrderRoutingOperation desiredOperation) {
+        if (currentOperation == null || currentOperation.getId() == null) {
+            return;
+        }
+        ProductionOrderRoutingOperation update = new ProductionOrderRoutingOperation();
+        update.setId(currentOperation.getId());
+        boolean changed = false;
+        if (!Objects.equals(currentOperation.getOrderRoutingId(), orderRoutingId)) {
+            update.setOrderRoutingId(orderRoutingId);
+            currentOperation.setOrderRoutingId(orderRoutingId);
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getProductionOrderId(), productionOrderId)) {
+            update.setProductionOrderId(productionOrderId);
+            currentOperation.setProductionOrderId(productionOrderId);
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getProductModelId(), desiredOperation.getProductModelId())) {
+            update.setProductModelId(desiredOperation.getProductModelId());
+            currentOperation.setProductModelId(desiredOperation.getProductModelId());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getTechnologyOperationId(), desiredOperation.getTechnologyOperationId())) {
+            update.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
+            currentOperation.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getOperationName(), desiredOperation.getOperationName())) {
+            update.setOperationName(desiredOperation.getOperationName());
+            currentOperation.setOperationName(desiredOperation.getOperationName());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getIsQuality(), desiredOperation.getIsQuality())) {
+            update.setIsQuality(desiredOperation.getIsQuality());
+            currentOperation.setIsQuality(desiredOperation.getIsQuality());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
+            update.setIsProduction(desiredOperation.getIsProduction());
+            currentOperation.setIsProduction(desiredOperation.getIsProduction());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
+            update.setType(desiredOperation.getType());
+            currentOperation.setType(desiredOperation.getType());
+            changed = true;
+        }
+        if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
+            update.setDragSort(desiredOperation.getDragSort());
+            currentOperation.setDragSort(desiredOperation.getDragSort());
+            changed = true;
+        }
+        if (changed) {
+            productionOrderRoutingOperationMapper.updateById(update);
+        }
+    }
+
+    private void removeRoutingOperationSnapshot(ProductionOrderRoutingOperation routingOperation) {
+        if (routingOperation == null || routingOperation.getId() == null) {
+            return;
+        }
+        ProductionOperationTask task = productionOperationTaskMapper.selectOne(
+                Wrappers.<ProductionOperationTask>lambdaQuery()
+                        .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, routingOperation.getId())
+                        .last("limit 1"));
+        if (task != null) {
+            validateTaskCanRemove(task);
+            productionOperationTaskMapper.deleteById(task.getId());
+        }
+        productionOrderRoutingOperationParamMapper.delete(
+                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
+                        .eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, routingOperation.getId()));
+        productionOrderRoutingOperationMapper.deleteById(routingOperation.getId());
+    }
+
+    private void syncRoutingOperationTasks(Long productionOrderId, List<ProductionOrderRoutingOperation> routingOperationList) {
+        if (routingOperationList == null || routingOperationList.isEmpty()) {
+            return;
+        }
+        List<Long> routingOperationIdList = routingOperationList.stream()
+                .map(ProductionOrderRoutingOperation::getId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        if (routingOperationIdList.isEmpty()) {
+            return;
+        }
+        Map<Long, ProductionOperationTask> taskByRoutingOperationId = productionOperationTaskMapper.selectList(
+                        Wrappers.<ProductionOperationTask>lambdaQuery()
+                                .in(ProductionOperationTask::getProductionOrderRoutingOperationId, routingOperationIdList)
+                                .orderByAsc(ProductionOperationTask::getId))
+                .stream()
+                .filter(item -> item != null && item.getProductionOrderRoutingOperationId() != null)
+                .collect(Collectors.toMap(
+                        ProductionOperationTask::getProductionOrderRoutingOperationId,
+                        item -> item,
+                        (left, right) -> left,
+                        LinkedHashMap::new));
+        for (int i = 0; i < routingOperationList.size(); i++) {
+            ProductionOrderRoutingOperation routingOperation = routingOperationList.get(i);
+            if (routingOperation == null || routingOperation.getId() == null) {
+                continue;
+            }
+            boolean shouldHaveTask = i == routingOperationList.size() - 1 || Boolean.TRUE.equals(routingOperation.getIsProduction());
+            ProductionOperationTask existingTask = taskByRoutingOperationId.get(routingOperation.getId());
+            if (shouldHaveTask) {
+                if (existingTask == null) {
+                    ProductionOperationTask task = new ProductionOperationTask();
+                    task.setProductionOrderId(productionOrderId);
+                    task.setProductionOrderRoutingOperationId(routingOperation.getId());
+                    task.setPlanQuantity(BigDecimal.ZERO);
+                    task.setCompleteQuantity(BigDecimal.ZERO);
+                    task.setWorkOrderNo(generateNextTaskNo());
+                    task.setStatus(2);
+                    productionOperationTaskMapper.insert(task);
+                }
+                continue;
+            }
+            if (existingTask != null) {
+                validateTaskCanRemove(existingTask);
+                productionOperationTaskMapper.deleteById(existingTask.getId());
+            }
+        }
+    }
+
+    private void validateTaskCanRemove(ProductionOperationTask task) {
+        if (task == null || task.getId() == null) {
+            return;
+        }
+        if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+        }
+        long reportCount = productionProductMainMapper.selectCount(
+                Wrappers.<ProductionProductMain>lambdaQuery()
+                        .eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
+        if (reportCount > 0) {
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ崟");
+        }
+    }
+
+    private void syncRoutingOperationParams(Long routingOperationId, Long productionOrderId, Long technologyOperationId) {
+        if (routingOperationId == null || technologyOperationId == null) {
+            return;
+        }
+        List<TechnologyOperationParam> operationParamList = technologyOperationParamMapper.selectList(
+                Wrappers.<TechnologyOperationParam>lambdaQuery()
+                        .eq(TechnologyOperationParam::getTechnologyOperationId, technologyOperationId)
+                        .orderByAsc(TechnologyOperationParam::getId));
+        for (TechnologyOperationParam operationParam : operationParamList) {
+            TechnologyParam technologyParam = technologyParamMapper.selectById(operationParam.getTechnologyParamId());
+            if (technologyParam == null) {
+                continue;
+            }
+            ProductionOrderRoutingOperationParam snapshot = new ProductionOrderRoutingOperationParam();
+            snapshot.setProductionOrderId(productionOrderId);
+            snapshot.setProductionOrderRoutingOperationId(routingOperationId);
+            snapshot.setTechnologyOperationId(operationParam.getTechnologyOperationId());
+            snapshot.setTechnologyOperationParamId(operationParam.getId());
+            snapshot.setParamId(technologyParam.getId());
+            snapshot.setParamCode(technologyParam.getParamCode());
+            snapshot.setParamName(technologyParam.getParamName());
+            snapshot.setParamType(technologyParam.getParamType());
+            snapshot.setParamFormat(technologyParam.getParamFormat());
+            snapshot.setUnit(technologyParam.getUnit());
+            snapshot.setIsRequired(technologyParam.getIsRequired());
+            snapshot.setRemark(technologyParam.getRemark());
+            snapshot.setStandardValue(operationParam.getStandardValue());
+            productionOrderRoutingOperationParamMapper.insert(snapshot);
+        }
+    }
+
     private Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> structureList,
                                                                       Long rootProductModelId) {
         if (structureList == null || structureList.isEmpty()) {
@@ -289,6 +645,7 @@
         }
         return demandedQuantityMap;
     }
+
     private BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
                                                Map<String, BigDecimal> demandedQuantityMap,
                                                BigDecimal orderQuantity,
@@ -310,6 +667,16 @@
         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);
     }
@@ -326,6 +693,7 @@
         ProductionBomStructure parent = structureById.get(bomStructure.getParentId());
         return parent != null ? parent : bomStructure;
     }
+
     private Long resolveOutputProductModelId(ProductionBomStructure outputNode,
                                              Long rootProductModelId) {
         if (outputNode == null) {
@@ -334,6 +702,31 @@
         return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId;
     }
 
+    private TechnologyOperation getTechnologyOperation(Long technologyOperationId) {
+        if (technologyOperationId == null) {
+            return null;
+        }
+        return technologyOperationMapper.selectById(technologyOperationId);
+    }
+
+    private String generateNextTaskNo() {
+        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+        ProductionOperationTask latestTask = productionOperationTaskMapper.selectOne(
+                Wrappers.<ProductionOperationTask>lambdaQuery()
+                        .likeRight(ProductionOperationTask::getWorkOrderNo, "GD" + datePrefix)
+                        .orderByDesc(ProductionOperationTask::getWorkOrderNo)
+                        .last("limit 1"));
+        int sequenceNumber = 1;
+        if (latestTask != null && latestTask.getWorkOrderNo() != null && latestTask.getWorkOrderNo().startsWith("GD" + datePrefix)) {
+            try {
+                sequenceNumber = Integer.parseInt(latestTask.getWorkOrderNo().substring(("GD" + datePrefix).length())) + 1;
+            } catch (NumberFormatException ignored) {
+                sequenceNumber = 1;
+            }
+        }
+        return "GD" + String.format("%s%03d", datePrefix, sequenceNumber);
+    }
+
     private BigDecimal defaultDecimal(BigDecimal value) {
         return value == null ? BigDecimal.ZERO : value;
     }

--
Gitblit v1.9.3