From 2d928d667b4aaf3bc360dd5fc41d9c0660898141 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 11 Sep 2026 16:10:49 +0800 Subject: [PATCH] fix: resolve cross-plan pallet allocations --- .../inboundplan/dto/InboundPlanResponse.java | 3 +- .../service/InboundPlanService.java | 37 +++++++++++++++++- .../openapi/overseas-business-v1.yaml | 3 ++ .../service/InboundPlanServiceTest.java | 38 +++++++++++++++++++ 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanResponse.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanResponse.java index d20d7e549..f36ce2706 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanResponse.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/dto/InboundPlanResponse.java @@ -49,7 +49,8 @@ public record InboundPlanResponse( int actualPackageCount) { } - public record Allocation(Long lineId, Long palletId, BigDecimal allocatedVolumeCbm, + public record Allocation(Long lineId, Long palletId, String palletNo, String palletOwnerPlanNo, + boolean palletOwnedByCurrentPlan, BigDecimal allocatedVolumeCbm, int plannedPackageCount, int countedPackageCount, int pickedPackageCount, BigDecimal actualVolumeCbm, String status, int version) { } diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java index f85c2c700..930b74881 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundPlanService.java @@ -1026,6 +1026,34 @@ public class InboundPlanService { new LambdaQueryWrapper() .eq(InboundPlanPalletAllocation::getPlanId, plan.getId()) .orderByAsc(InboundPlanPalletAllocation::getId)); + List referencedPalletIds = allocations.stream() + .map(InboundPlanPalletAllocation::getPalletId) + .filter(Objects::nonNull) + .distinct() + .toList(); + Map referencedPallets = referencedPalletIds.isEmpty() + ? Map.of() + : palletMapper.selectBatchIds(referencedPalletIds).stream() + .collect(Collectors.toMap(InboundPlanPallet::getId, pallet -> pallet)); + if (referencedPallets.size() != referencedPalletIds.size()) { + throw new ResponseStatusException(HttpStatus.CONFLICT, "入库计划分配引用的托盘不存在"); + } + List externalOwnerPlanIds = referencedPallets.values().stream() + .map(InboundPlanPallet::getPlanId) + .filter(Objects::nonNull) + .filter(ownerPlanId -> !Objects.equals(ownerPlanId, plan.getId())) + .distinct() + .toList(); + Map palletOwnerPlanNos = new HashMap<>(); + palletOwnerPlanNos.put(plan.getId(), plan.getPlanNo()); + if (!externalOwnerPlanIds.isEmpty()) { + palletOwnerPlanNos.putAll(planMapper.selectBatchIds(externalOwnerPlanIds).stream() + .collect(Collectors.toMap(InboundPlan::getId, InboundPlan::getPlanNo))); + } + if (referencedPallets.values().stream().anyMatch(pallet -> + pallet.getPlanId() == null || !palletOwnerPlanNos.containsKey(pallet.getPlanId()))) { + throw new ResponseStatusException(HttpStatus.CONFLICT, "入库计划分配引用的托盘所属计划不存在"); + } return new InboundPlanResponse(plan.getId(), plan.getPlanNo(), plan.getCustomerId(), plan.getSourceOrderId(), sourceOrder == null ? null : sourceOrder.orderNo(), sourceOrder == null ? null : sourceOrder.customerName(), @@ -1043,9 +1071,14 @@ public class InboundPlanService { pallet.getWarehousePalletId(), pallet.getWarehouseLocationId(), pallet.getWarehouseResourceLockId(), pallet.getPalletType(), pallet.getAssignmentStatus(), pallet.getLockedAt(), pallet.getActualVolumeCbm(), pallet.getActualPackageCount())).toList(), - allocations.stream().map(item -> new InboundPlanResponse.Allocation(item.getLineId(), item.getPalletId(), + allocations.stream().map(item -> { + InboundPlanPallet referencedPallet = referencedPallets.get(item.getPalletId()); + return new InboundPlanResponse.Allocation(item.getLineId(), item.getPalletId(), + referencedPallet.getPalletNo(), palletOwnerPlanNos.get(referencedPallet.getPlanId()), + Objects.equals(referencedPallet.getPlanId(), plan.getId()), item.getAllocatedVolumeCbm(), item.getPlannedPackageCount(), item.getCountedPackageCount(), - item.getPickedPackageCount(), item.getActualVolumeCbm(), item.getStatus(), item.getVersion())).toList(), + item.getPickedPackageCount(), item.getActualVolumeCbm(), item.getStatus(), item.getVersion()); + }).toList(), plan.getVersion() == null ? 0 : plan.getVersion(), plan.getPlannedArrivalDate(), plan.getPalletType(), Boolean.TRUE.equals(plan.getAssignedFlag()), Boolean.TRUE.equals(plan.getMergeRequired()), Boolean.TRUE.equals(plan.getUrgentFlag()), plan.getCreationMode(), plan.getPlanRemark(), diff --git a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml index 973f4d855..2038a62d9 100644 --- a/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml +++ b/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml @@ -2908,6 +2908,9 @@ components: properties: lineId: { type: string, pattern: '^[0-9]+$' } palletId: { type: string, pattern: '^[0-9]+$' } + palletNo: { type: string, description: 分配实际引用的托盘码,跨计划合托时仍返回真实托盘码 } + palletOwnerPlanNo: { type: string, description: 托盘所属入库计划号 } + palletOwnedByCurrentPlan: { type: boolean, description: 托盘是否归属当前详情入库计划 } allocatedVolumeCbm: { type: number } plannedPackageCount: { type: integer } countedPackageCount: { type: integer } diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanServiceTest.java index 2da5db8c9..523c4e2d0 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanServiceTest.java @@ -334,6 +334,44 @@ class InboundPlanServiceTest { verify(orderMapper).findDetailOrder("100", 1L); } + @Test + void detailResolvesCrossPlanMergedPalletWithoutChangingOwnedPalletList() { + InboundPlan currentPlan = existingPlan("100", 1L, "IP-CURRENT"); + InboundPlan ownerPlan = existingPlan("100", 2L, "IP-OWNER"); + InboundPlanPallet ownedPallet = new InboundPlanPallet(); + ownedPallet.setId(301L); + ownedPallet.setPlanId(currentPlan.getId()); + ownedPallet.setPalletNo("DRYU2309389-101-005"); + ownedPallet.setSequenceNo(1); + ownedPallet.setActualPackageCount(0); + InboundPlanPallet mergedPallet = new InboundPlanPallet(); + mergedPallet.setId(302L); + mergedPallet.setPlanId(ownerPlan.getId()); + mergedPallet.setPalletNo("DRYU2309389-101-006"); + InboundPlanPalletAllocation allocation = new InboundPlanPalletAllocation(); + allocation.setLineId(201L); + allocation.setPalletId(302L); + allocation.setPlannedPackageCount(150); + allocation.setCountedPackageCount(150); + allocation.setPickedPackageCount(150); + allocation.setVersion(0); + + when(planMapper.selectOne(any())).thenReturn(currentPlan); + when(palletMapper.selectList(any())).thenReturn(List.of(ownedPallet)); + when(allocationMapper.selectList(any())).thenReturn(List.of(allocation)); + when(palletMapper.selectBatchIds(any())).thenReturn(List.of(mergedPallet)); + when(planMapper.selectBatchIds(any())).thenReturn(List.of(ownerPlan)); + + var result = service.detailByPlanNo("100", "IP-CURRENT"); + + assertEquals(List.of("DRYU2309389-101-005"), + result.pallets().stream().map(pallet -> pallet.palletNo()).toList()); + assertEquals("DRYU2309389-101-006", result.allocations().get(0).palletNo()); + assertEquals("IP-OWNER", result.allocations().get(0).palletOwnerPlanNo()); + assertEquals(false, result.allocations().get(0).palletOwnedByCurrentPlan()); + assertEquals(150, result.allocations().get(0).pickedPackageCount()); + } + @Test void detailFailsClosedWhenReceivingWarehouseFactIsMissing() { InboundPlan plan = existingPlan("100", 1L, "LIP-1");