From 775b2c48635502befa6d592a80d4d35fe19ee5a0 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 22 Aug 2026 11:46:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/PdaPickSettlementService.java | 18 +++++++---- .../service/PdaPickSettlementServiceTest.java | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/PdaPickSettlementService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/PdaPickSettlementService.java index 93bfe6f8a..7207d64e0 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/PdaPickSettlementService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/PdaPickSettlementService.java @@ -22,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -254,8 +255,10 @@ public class PdaPickSettlementService { throw conflict("入仓单缺少真实订单引用"); } List quantities = lines.stream() - .map(line -> new OrderFulfillmentSplitClient.QuantityLine( - line.item().inboundDetailId(), line.item().packageCount())) + .collect(Collectors.groupingBy(line -> line.item().inboundDetailId(), LinkedHashMap::new, + Collectors.summingInt(line -> count(line.item().packageCount(), "测量明细箱数")))) + .entrySet().stream() + .map(entry -> new OrderFulfillmentSplitClient.QuantityLine(entry.getKey(), entry.getValue())) .toList(); OrderFulfillmentSplitClient.CreateRequest request = new OrderFulfillmentSplitClient.CreateRequest( source.tenantId(), root.orderId(), source.orderId(), loadingPlanId, containerBookingId, @@ -333,15 +336,18 @@ public class PdaPickSettlementService { if (!measuredDetailIds.containsAll(pickedByDetail.keySet())) { throw conflict("PDA 已拣明细未匹配已审核测量明细"); } + Map remainingPickedByDetail = new HashMap<>(pickedByDetail); List result = new ArrayList<>(); for (MeasurementItemRow item : measurements) { int measured = count(item.packageCount(), "测量明细箱数"); - int picked = pickedByDetail.getOrDefault(item.inboundDetailId(), 0); - if (picked > measured) { - throw conflict("PDA 已拣箱数超过测量明细箱数"); - } + int requested = remainingPickedByDetail.getOrDefault(item.inboundDetailId(), 0); + int picked = Math.min(measured, requested); + remainingPickedByDetail.put(item.inboundDetailId(), requested - picked); result.add(new MeasurementSplitLine(item, picked, measured - picked)); } + if (remainingPickedByDetail.values().stream().anyMatch(remaining -> remaining != 0)) { + throw conflict("PDA 已拣箱数超过测量明细箱数"); + } return result; } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/PdaPickSettlementServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/PdaPickSettlementServiceTest.java index f4fd32ed0..306cbe216 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/PdaPickSettlementServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/PdaPickSettlementServiceTest.java @@ -79,6 +79,37 @@ class PdaPickSettlementServiceTest { verify(splits).convergePartialPlanItem(21L, 9L, "operator"); } + @Test + void distributesOnePickedCartonAcrossRepeatedMeasurementRowsOfTheSameInboundDetail() { + LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 1, 1, "PICKED"); + resolved(List.of(item)); + when(splits.lockParent(31L)).thenReturn(parent(2)); + when(splits.lockLatestApprovedItemsForInbound(10001L, 31L)).thenReturn(List.of( + new MeasurementItemRow(51L, 61L, 41L, 1), + new MeasurementItemRow(52L, 61L, 41L, 1))); + when(allocations.lockConfirmed(10001L, 31L)).thenAnswer(invocation -> + List.of(allocation(1L, 1, 501L, 2))); + when(warehouse.settle(eq("internal-token"), any())).thenReturn(ApiResponse.success( + new WarehousePalletLocationClient.SettlementResult(List.of(), List.of(transfer(1, 501L, 1))))); + writes(1, 1); + when(splits.insertSplitItem(anyLong(), eq(10001L), anyLong(), eq(31L), anyLong(), anyInt(), + eq(41L), eq(61L), eq(52L), eq(1))).thenReturn(1); + when(splits.cloneMeasurementItem(eq(10001L), eq(61L), eq(52L), anyLong(), + anyLong(), anyLong(), anyInt(), eq(1))).thenReturn(1); + when(splits.updateMeasurementItemForLoaded(10001L, 52L, 0)).thenReturn(1); + + service.settle(1L, 9L, "operator"); + + verify(splits).updateMeasurementItemForLoaded(10001L, 51L, 1); + verify(splits).updateMeasurementItemForLoaded(10001L, 52L, 0); + verify(splits).cloneMeasurementItem(eq(10001L), eq(61L), eq(52L), anyLong(), + anyLong(), anyLong(), anyInt(), eq(1)); + verify(orderSplits).split(eq("internal-token"), eq(9L), + org.mockito.ArgumentMatchers.argThat(request -> request.lines().size() == 1 + && request.lines().get(0).sourceDetailId() == 41L + && request.lines().get(0).packageCount() == 2)); + } + @Test void reusesWarehouseSettlementTargetWhenRetryingAfterLocalRollback() { LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 3, 1, "PARTIAL");