gongchunyi
2 天以前 d29080af4e965ba341cb85a5bc45ecd183c06783
src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -44,6 +44,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -115,7 +116,7 @@
        // 下单入口统一补齐来源单据、计划和工艺信息,避免前端分别传多套字段。
        validateAndFillOrder(productionOrder, oldOrder);
        if (productionOrder.getNpsNo() == null || productionOrder.getNpsNo().trim().isEmpty()) {
            productionOrder.setNpsNo(generateNextOrderNo());
            productionOrder.setNpsNo(generateNextOrderNo(productionOrder.getCreateTime() != null ? productionOrder.getCreateTime() : LocalDateTime.now()));
        }
        if (productionOrder.getCompleteQuantity() == null) {
            productionOrder.setCompleteQuantity(BigDecimal.ZERO);
@@ -438,9 +439,54 @@
        productionOrderBomMapper.insert(orderBom);
        Map<Long, Long> idMap = new HashMap<>();
        BigDecimal lastProcessDemandedQuantity = orderQuantity;
        // 构建 sourceId → sourceNode 映射 和 parentId → children 映射
        Map<Long, TechnologyBomStructure> sourceById = new HashMap<>();
        Map<Long, List<TechnologyBomStructure>> childrenMap = new LinkedHashMap<>();
        for (TechnologyBomStructure source : structureList) {
            // 子节点 parentId 需要映射成新快照节点 id,才能保留原始 BOM 层级。
            if (source == null || source.getId() == null) {
                continue;
            }
            sourceById.put(source.getId(), source);
            Long parentId = source.getParentId();
            childrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(source);
        }
        // BFS 从根节点开始,父节点先于子节点处理
        Deque<TechnologyBomStructure> queue = new ArrayDeque<>();
        List<TechnologyBomStructure> rootNodes = childrenMap.get(null);
        if (rootNodes != null) {
            queue.addAll(rootNodes);
        }
        // parentId=0 的也视为根节点
        List<TechnologyBomStructure> zeroParentNodes = childrenMap.get(0L);
        if (zeroParentNodes != null) {
            for (TechnologyBomStructure node : zeroParentNodes) {
                if (!queue.contains(node)) {
                    queue.add(node);
                }
            }
        }
        while (!queue.isEmpty()) {
            TechnologyBomStructure source = queue.poll();
            if (source == null || source.getId() == null) {
                continue;
            }
            // 计算需求量 = 父节点需求量 × 自身 unitQuantity
            BigDecimal parentDemandedQuantity = orderQuantity;
            Long sourceParentId = source.getParentId();
            if (sourceParentId != null && sourceParentId != 0L) {
                Long parentTargetId = idMap.get(sourceParentId);
                if (parentTargetId != null) {
                    // 父节点已经插入,用父节点的 targetId 从已插入列表找
                    // 这里我们直接用存下来的父节点需求量
                    TechnologyBomStructure parentSource = sourceById.get(sourceParentId);
                    if (parentSource != null && parentSource.getDemandedQuantity() != null) {
                        parentDemandedQuantity = parentSource.getDemandedQuantity();
                    }
                }
            }
            ProductionBomStructure target = new ProductionBomStructure();
            target.setProductionOrderId(productionOrder.getId());
            target.setProductionOrderBomId(orderBom.getId());
@@ -448,11 +494,20 @@
            target.setProductModelId(source.getProductModelId());
            target.setTechnologyOperationId(source.getOperationId());
            target.setUnitQuantity(source.getUnitQuantity());
            target.setDemandedQuantity(lastProcessDemandedQuantity.multiply(source.getUnitQuantity()));
            target.setDemandedQuantity(parentDemandedQuantity.multiply(defaultDecimal(source.getUnitQuantity())));
            target.setUnit(source.getUnit());
            productionBomStructureMapper.insert(target);
            idMap.put(source.getId(), target.getId());
            lastProcessDemandedQuantity = target.getDemandedQuantity();
            // 将当前节点的 demandedQuantity 回写到 source 对象上,供子节点计算使用
            source.setDemandedQuantity(target.getDemandedQuantity());
            // 将子节点加入队列
            List<TechnologyBomStructure> children = childrenMap.get(source.getId());
            if (children != null) {
                for (TechnologyBomStructure child : children) {
                    queue.add(child);
                }
            }
        }
        return orderBom;
    }
@@ -508,9 +563,10 @@
                .orderByDesc(ProductionOrder::getId);
    }
    private String generateNextOrderNo() {
    private String generateNextOrderNo(LocalDateTime createTime) {
        // 生成下一个生产订单号
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        LocalDate localDate = createTime.toLocalDate();
        String datePrefix = localDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "SC" + datePrefix;
        ProductionOrder latestOrder = this.getOne(Wrappers.<ProductionOrder>lambdaQuery()
                .likeRight(ProductionOrder::getNpsNo, prefix)
@@ -1064,8 +1120,19 @@
        }
        // 过滤出非根节点(实际领料项)
        // 排除投入品与产出品相同且比例为1的情况(自身加工,不需要领料)
        List<ProductionBomStructureVo> childStructureList = bomStructureList.stream()
                .filter(s -> s != null && s.getParentId() != null && s.getParentId() != 0)
                .filter(s -> {
                    ProductionBomStructureVo parent = structureByIdMap.get(s.getParentId());
                    if (parent == null) {
                        return true;
                    }
                    // 投入品与产出品相同且比例为1时,不需要领料
                    boolean sameProduct = Objects.equals(s.getProductModelId(), parent.getProductModelId());
                    boolean unitRatio = BigDecimal.ONE.compareTo(defaultDecimal(s.getUnitQuantity())) == 0;
                    return !(sameProduct && unitRatio);
                })
                .collect(Collectors.toList());
        // 遍历处理数据并组装结果
@@ -1093,40 +1160,35 @@
            }
        }
        Map<String, ProductionOrderPickVo> mergedPickMap = new LinkedHashMap<>();
        List<ProductionOrderPickVo> pickList = new ArrayList<>();
        for (ProductionBomStructureVo structure : childStructureList) {
            if (structure == null || structure.getProductModelId() == null) {
                continue;
            }
            Long productModelId = structure.getProductModelId();
            String mergeKey = String.valueOf(structure.getTechnologyOperationId()) + "#" + productModelId;
            ProductionOrderPickVo vo = mergedPickMap.get(mergeKey);
            if (vo == null) {
                vo = new ProductionOrderPickVo();
                vo.setProductModelId(productModelId);
                vo.setOperationName(structure.getOperationName());
                vo.setTechnologyOperationId(structure.getTechnologyOperationId());
                vo.setProductName(structure.getProductName());
                vo.setModel(structure.getModel());
                vo.setDemandedQuantity(BigDecimal.ZERO);
                vo.setUnit(structure.getUnit());
                List<String> batchNoList = stockBatchNoMap.get(productModelId) == null
                        ? Collections.emptyList()
                        : new ArrayList<>(stockBatchNoMap.get(productModelId));
                vo.setBatchNoList(batchNoList);
                vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO));
                vo.setBom(true);
                mergedPickMap.put(mergeKey, vo);
            }
            vo.setDemandedQuantity(defaultDecimal(vo.getDemandedQuantity()).add(defaultDecimal(structure.getDemandedQuantity())));
            ProductionOrderPickVo vo = new ProductionOrderPickVo();
            vo.setProductModelId(productModelId);
            vo.setOperationName(structure.getOperationName());
            vo.setTechnologyOperationId(structure.getTechnologyOperationId());
            vo.setProductName(structure.getProductName());
            vo.setModel(structure.getModel());
            vo.setDemandedQuantity(defaultDecimal(structure.getDemandedQuantity()));
            vo.setUnit(structure.getUnit());
            List<String> batchNoList = stockBatchNoMap.get(productModelId) == null
                    ? Collections.emptyList()
                    : new ArrayList<>(stockBatchNoMap.get(productModelId));
            vo.setBatchNoList(batchNoList);
            vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO));
            vo.setBom(true);
            pickList.add(vo);
        }
        return new ArrayList<>(mergedPickMap.values());
        return pickList;
    }
    @Override
    public int updateOrder(ProductionOrderDto productionOrderDto) {
        // 更新生产订单主数据
        productionOrderDto.setStatus(5);
        productionOrderDto.setStatus(ProductOrderStatusEnum.END.getCode());
        return baseMapper.updateById(productionOrderDto);
    }
}