| | |
| | | if (taskList == null || taskList.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | Set<Long> routingOperationIds = taskList.stream() |
| | | .map(ProductionOperationTask::getProductionOrderRoutingOperationId) |
| | | .filter(Objects::nonNull) |
| | |
| | | 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); |
| | | |
| | | // 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) { |
| | | continue; |
| | |
| | | if (routingOperation == null || routingOperation.getTechnologyRoutingOperationId() == null) { |
| | | continue; |
| | | } |
| | | BigDecimal planQuantity = resolveTaskPlanQuantity(routingOperation, demandedQuantityMap, orderQuantity); |
| | | BigDecimal planQuantity = resolveTaskPlanQuantity( |
| | | routingOperation, |
| | | demandedQuantityMap, |
| | | orderQuantity, |
| | | rootProductModelId); |
| | | if (compareDecimal(task.getPlanQuantity(), planQuantity) == 0) { |
| | | continue; |
| | | } |
| | |
| | | productionOperationTaskMapper.updateById(update); |
| | | } |
| | | } |
| | | |
| | | private Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> structureList, |
| | | Long rootProductModelId, |
| | | BigDecimal orderQuantity) { |
| | | Long rootProductModelId) { |
| | | if (structureList == null || structureList.isEmpty()) { |
| | | return Collections.emptyMap(); |
| | | } |
| | |
| | | .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 || bomStructure.getUnitQuantity() == null) { |
| | | if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) { |
| | | continue; |
| | | } |
| | | Long outputProductModelId = resolveOutputProductModelId(bomStructure, structureById, rootProductModelId); |
| | | // 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, bomStructure.getUnitQuantity().multiply(orderQuantity), BigDecimal::add); |
| | | demandedQuantityMap.merge(key, defaultDecimal(outputNode == null ? null : outputNode.getDemandedQuantity()), BigDecimal::add); |
| | | } |
| | | return demandedQuantityMap; |
| | | } |
| | | |
| | | private BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation, |
| | | Map<String, BigDecimal> demandedQuantityMap, |
| | | BigDecimal orderQuantity) { |
| | | 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(), |
| | | routingOperation.getProductModelId()); |
| | | outputProductModelId); |
| | | BigDecimal planQuantity = demandedQuantityMap.get(key); |
| | | return planQuantity != null ? planQuantity : orderQuantity; |
| | | } |
| | |
| | | return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId); |
| | | } |
| | | |
| | | private Long resolveOutputProductModelId(ProductionBomStructure bomStructure, |
| | | Map<Long, ProductionBomStructure> structureById, |
| | | Long rootProductModelId) { |
| | | 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; |
| | | } |
| | | 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(); |
| | | return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId; |
| | | } |
| | | |
| | | private BigDecimal defaultDecimal(BigDecimal value) { |