| | |
| | | |
| | | 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; |
| | |
| | | private final ProductionOperationTaskMapper productionOperationTaskMapper; |
| | | private final ProductionOrderBomMapper productionOrderBomMapper; |
| | | private final ProductionBomStructureMapper productionBomStructureMapper; |
| | | private final ProductionOrderMapper productionOrderMapper; |
| | | private final ProductionProductMainMapper productionProductMainMapper; |
| | | private final ProductionProductOutputMapper productionProductOutputMapper; |
| | | private final ProductionOrderPickMapper productionOrderPickMapper; |
| | |
| | | // 下单入口统一补齐来源单据、计划和工艺信息,避免前端分别传多套字段。 |
| | | 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); |
| | |
| | | .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) |
| | |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.pickByBomId(orderBom.getId()); |
| | | // 查询完整的BOM结构(包括根节点),用于计算层级需求数量 |
| | | List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.listByBomId(orderBom.getId()); |
| | | if (bomStructureList == null || bomStructureList.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 查询生产订单获取订单数量 |
| | | ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId); |
| | | BigDecimal orderQuantity = productionOrder != null ? defaultDecimal(productionOrder.getQuantity()) : BigDecimal.ZERO; |
| | | |
| | | // 构建树形结构并计算层级需求数量 |
| | | Map<Long, ProductionBomStructureVo> structureByIdMap = bomStructureList.stream() |
| | | .filter(s -> s != null && s.getId() != null) |
| | | .collect(Collectors.toMap(ProductionBomStructureVo::getId, s -> s)); |
| | | |
| | | // 按层级计算需求数量:子级需求数量 = 父级需求数量 × 子级单位产出所需数量 |
| | | for (ProductionBomStructureVo structure : bomStructureList) { |
| | | if (structure == null) continue; |
| | | |
| | | if (structure.getParentId() == null || structure.getParentId() == 0) { |
| | | // 根节点:需求数量 = 订单数量 |
| | | structure.setDemandedQuantity(orderQuantity); |
| | | } else { |
| | | // 子节点:需求数量 = 父级需求数量 × 子级单位产出所需数量 |
| | | ProductionBomStructureVo parent = structureByIdMap.get(structure.getParentId()); |
| | | if (parent != null) { |
| | | BigDecimal parentDemandedQty = defaultDecimal(parent.getDemandedQuantity()); |
| | | BigDecimal unitQuantity = defaultDecimal(structure.getUnitQuantity()); |
| | | structure.setDemandedQuantity(parentDemandedQty.multiply(unitQuantity)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 过滤出非根节点(实际领料项) |
| | | // 排除投入品与产出品相同且比例为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()); |
| | | |
| | | // 遍历处理数据并组装结果 |
| | | List<Long> productModelIds = bomStructureList.stream() |
| | | List<Long> productModelIds = childStructureList.stream() |
| | | .map(ProductionBomStructureVo::getProductModelId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | |
| | | } |
| | | } |
| | | |
| | | Map<String, ProductionOrderPickVo> mergedPickMap = new LinkedHashMap<>(); |
| | | for (ProductionBomStructureVo structure : bomStructureList) { |
| | | 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 |