From 8099343fcaf245d2db974160e53900fbf0cb030d Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 4 Sep 2026 12:28:47 +0800 Subject: [PATCH] fix: align PDA inventory with pallet location blocks --- .../client/WarehousePalletLocationClient.java | 10 -- .../baiyue/firstleg/dto/LoadingPickDtos.java | 6 +- .../firstleg/service/LoadingPickService.java | 93 ++++++++++++------- .../openapi/phase3-pda-convergence-v1.yaml | 18 +++- .../PdaConvergenceOpenApiContractTest.java | 7 ++ .../service/LoadingPickServiceTest.java | 80 ++++++++++++---- .../admin-test-env-modules/phase3-loading.mjs | 11 ++- 7 files changed, 153 insertions(+), 72 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/client/WarehousePalletLocationClient.java b/firstleg/src/main/java/com/baiyue/firstleg/client/WarehousePalletLocationClient.java index fd92f964c..618d54e6c 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/client/WarehousePalletLocationClient.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/client/WarehousePalletLocationClient.java @@ -46,13 +46,6 @@ public interface WarehousePalletLocationClient { ApiResponse releaseBlock(@RequestHeader("X-Internal-Service-Token") String token, @RequestBody BlockReleaseRequest request); - @GetMapping("/pallet-locations/occupied-resources") - ApiResponse> occupiedResources( - @RequestHeader("X-Internal-Service-Token") String token, - @RequestParam("tenantId") long tenantId, - @RequestParam("sourceService") String sourceService, - @RequestParam("businessId") long businessId); - record BlockReserveRequest(long warehouseId, String sourceService, long businessId, String inboundCode, int requiredSlotCount, String idempotencyKey, long operatorId, LocalDateTime expiresAt) {} @@ -65,9 +58,6 @@ public interface WarehousePalletLocationClient { record BlockResource(long blockId, long reservationId, long locationId, String locationCode, int slotNo, boolean sharedOverflow, String resourceStatus) {} record BlockResult(long blockId, String blockStatus, List resources) {} - record OccupiedResource(long reservationId, long occupancyId, int allocationNo, long warehouseId, - long palletId, long locationId, String locationCode, boolean sharedOverflow, - int allocatedPackageCount) {} record PalletSnapshot(long palletId, String palletCode, String palletType, BigDecimal capacityCbm, BigDecimal tareWeightKg) {} } diff --git a/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java b/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java index 3a68085fa..bb7818725 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/dto/LoadingPickDtos.java @@ -92,6 +92,7 @@ public final class LoadingPickDtos { public record PickItem(Long id, Long loadingPlanItemId, Long tenantId, Long inboundId, Long inboundDetailId, String orderNo, String inboundCode, String cargoName, List boxCodes, + List inventoryResources, Integer plannedPackageCount, Integer pickedPackageCount, String itemStatus, Integer version) { } @@ -131,9 +132,10 @@ public final class LoadingPickDtos { Integer itemCount, Integer pendingItemCount) { } - public record InventoryResource(Long reservationId, Long occupancyId, Long palletId, + public record InventoryResource(Long blockId, Integer slotNo, Long reservationId, + Long weightResultId, Integer palletSequence, Long palletId, Long locationId, String locationCode, Boolean sharedOverflow, - Integer availablePackageCount) { + String slotStatus, Integer availablePackageCount) { } public record InboundInventory(Long inboundId, Integer availablePackageCount, diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java index 49c0ffcbe..b5b15dd8a 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java @@ -1,9 +1,7 @@ package com.baiyue.firstleg.service; -import com.baiyue.common.core.api.ApiResponse; import com.baiyue.common.core.api.ResultCode; import com.baiyue.common.core.exception.BizException; -import com.baiyue.firstleg.client.WarehousePalletLocationClient; import com.baiyue.firstleg.dto.LoadingPickDtos.PickItem; import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.PartialPickRequest; @@ -34,6 +32,7 @@ import com.baiyue.firstleg.entity.LoadingPickTaskEntity; import com.baiyue.firstleg.entity.LoadingPlanItemEntity; import com.baiyue.firstleg.entity.LoadingPlanHistoryEntity; import com.baiyue.firstleg.entity.InboundStatusHistoryEntity; +import com.baiyue.firstleg.entity.InboundPalletAllocationEntity; import com.baiyue.firstleg.entity.ContainerBookingEntity; import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper; import com.baiyue.firstleg.loading.service.LoadingDeliveryService; @@ -46,12 +45,11 @@ import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper; import com.baiyue.firstleg.mapper.LoadingPickItemMapper.CartonLabelRow; import com.baiyue.firstleg.mapper.LoadingPickItemMapper; import com.baiyue.firstleg.repository.LoadingPickRepository; +import com.baiyue.firstleg.repository.InboundPalletAllocationRepository; import com.baiyue.firstleg.repository.LoadingCompletionCommandRepository; import com.baiyue.firstleg.repository.SmartLoadingRepository; import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository; import jakarta.annotation.Resource; -import feign.FeignException; -import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.support.TransactionTemplate; @@ -80,8 +78,6 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker; @Service public class LoadingPickService { private static final Logger log = LoggerFactory.getLogger(LoadingPickService.class); - private static final long PLATFORM_WAREHOUSE_RESOURCE_TENANT_ID = 0L; - private static final String SOURCE_SERVICE = "firstleg-service"; @Resource private LoadingPickRepository repository; @Resource @@ -107,9 +103,7 @@ public class LoadingPickService { @Resource private PdaPickSettlementService settlementService; @Resource - private WarehousePalletLocationClient warehouse; - @Value("${baiyue.security.internal-service-token:test-internal-service-token}") - private String internalToken; + private InboundPalletAllocationRepository palletAllocations; /** Opens the field task after planning and ocean release; the real container number may be filled later. */ @Transactional @@ -906,14 +900,19 @@ public class LoadingPickService { ? repository.items(task.getId()) : repository.items(task.getId(), warehouseId); Map> cartonsByItem = repository.cartonLabels(task.getId()).stream() .collect(Collectors.groupingBy(CartonLabelRow::getPickItemId)); + Map tenantByInbound = tenantByInbound(task.getId()); + Map> inventoryByInbound = inventoryByInbound( + booking.getWarehouseId(), source, tenantByInbound); List items = source.stream().map(item -> { List cartons = cartonsByItem.getOrDefault(item.getId(), List.of()); CartonLabelRow first = cartons.isEmpty() ? null : cartons.get(0); - return new PickItem(item.getId(), item.getLoadingPlanItemId(), first == null ? null : first.getTenantId(), + Long tenantId = first == null ? tenantByInbound.get(item.getInboundId()) : first.getTenantId(); + return new PickItem(item.getId(), item.getLoadingPlanItemId(), tenantId, item.getInboundId(), item.getInboundDetailId(), first == null ? null : first.getOrderNo(), first == null ? null : first.getInboundCode(), first == null ? null : first.getCargoName(), - cartons.stream().map(CartonLabelRow::getBoxCode).toList(), item.getPlannedPackageCount(), + cartons.stream().map(CartonLabelRow::getBoxCode).toList(), + inventoryByInbound.getOrDefault(item.getInboundId(), List.of()), item.getPlannedPackageCount(), item.getPickedPackageCount(), item.getItemStatus(), item.getVersion()); }).toList(); LoadingPickAssignmentEntity assigned = repository.assignment(task.getId()); @@ -1036,17 +1035,11 @@ public class LoadingPickService { private InventorySnapshot buildInventorySnapshot(LoadingPickTaskEntity task, long warehouseId, List items) { + Map> inventoryByInbound = inventoryByInbound( + warehouseId, items, tenantByInbound(task.getId())); List inbounds = items.stream().map(LoadingPickItemEntity::getInboundId) .filter(Objects::nonNull).distinct().sorted().map(inboundId -> { - List current = occupiedResources(inboundId); - List resources = current.stream() - .filter(resource -> resource.warehouseId() == warehouseId) - .sorted(Comparator.comparingLong(WarehousePalletLocationClient.OccupiedResource::reservationId) - .thenComparingLong(WarehousePalletLocationClient.OccupiedResource::occupancyId)) - .map(resource -> new InventoryResource(resource.reservationId(), resource.occupancyId(), - resource.palletId(), resource.locationId(), resource.locationCode(), - resource.sharedOverflow(), resource.allocatedPackageCount())) - .toList(); + List resources = inventoryByInbound.getOrDefault(inboundId, List.of()); int available = resources.stream().mapToInt(InventoryResource::availablePackageCount).sum(); return new InboundInventory(inboundId, available, resources); }).toList(); @@ -1057,20 +1050,51 @@ public class LoadingPickService { LocalDateTime.now(), token, inbounds); } - private List occupiedResources(long inboundId) { - ApiResponse> response; - try { - response = warehouse.occupiedResources(internalToken, PLATFORM_WAREHOUSE_RESOURCE_TENANT_ID, - SOURCE_SERVICE, inboundId); - } catch (FeignException exception) { - throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "仓储实时库存查询失败,请刷新后重试"); + private Map tenantByInbound(long taskId) { + return repository.inboundOwners(taskId).stream().collect(Collectors.toMap( + LoadingPickItemMapper.InboundOwner::inboundId, + LoadingPickItemMapper.InboundOwner::tenantId, + (left, right) -> left)); + } + + private Map> inventoryByInbound(long warehouseId, + List items, + Map tenantByInbound) { + Map> result = new HashMap<>(); + for (Long inboundId : items.stream().map(LoadingPickItemEntity::getInboundId) + .filter(Objects::nonNull).distinct().toList()) { + Long tenantId = tenantByInbound.get(inboundId); + if (tenantId == null) throw conflict("PDA任务缺少入库单客户归属"); + List resources = palletAllocations.list(tenantId, inboundId).stream() + .filter(resource -> Objects.equals(resource.getWarehouseId(), warehouseId)) + .filter(resource -> "CONFIRMED".equals(resource.getAllocationStatus())) + .sorted(Comparator.comparing(InboundPalletAllocationEntity::getBlockId, + Comparator.nullsLast(Long::compareTo)) + .thenComparing(InboundPalletAllocationEntity::getSlotNo, + Comparator.nullsLast(Integer::compareTo))) + .map(LoadingPickService::inventoryResource) + .toList(); + result.put(inboundId, resources); } - if (response == null || !response.successful() || response.data() == null) { - ResultCode code = response == null ? ResultCode.SERVICE_UNAVAILABLE : ResultCode.of(response.code()); - throw new BizException(code, response == null || response.message() == null - ? "仓储实时库存查询失败,请刷新后重试" : response.message()); + return result; + } + + private static InventoryResource inventoryResource(InboundPalletAllocationEntity resource) { + if (resource.getBlockId() == null || resource.getSlotNo() == null + || resource.getReservationId() == null || resource.getLocationId() == null) { + throw conflict("入库单库位块快照不完整,请重新确认测量入库"); } - return response.data(); + return new InventoryResource(resource.getBlockId(), resource.getSlotNo(), + resource.getReservationId(), resource.getWeightResultId(), resource.getPalletSequence(), + resource.getPalletId(), resource.getLocationId(), resource.getLocationCode(), + Boolean.TRUE.equals(resource.getSharedOverflow()), resource.getSlotStatus(), available(resource)); + } + + private static int available(InboundPalletAllocationEntity resource) { + int allocated = count(resource.getAllocatedPackageCount()); + int picked = count(resource.getPickedPackageCount()); + if (picked > allocated) throw conflict("整票库位槽已拣箱数超过分配箱数"); + return allocated - picked; } private static String inventoryToken(LoadingPickTaskEntity task, long warehouseId, @@ -1080,8 +1104,9 @@ public class LoadingPickService { for (InboundInventory inbound : inbounds) { canonical.append('|').append(inbound.inboundId()).append('|').append(inbound.availablePackageCount()); for (InventoryResource resource : inbound.resources()) { - canonical.append('|').append(resource.reservationId()).append('|').append(resource.occupancyId()) - .append('|').append(resource.locationId()).append('|').append(resource.availablePackageCount()); + canonical.append('|').append(resource.blockId()).append('|').append(resource.slotNo()) + .append('|').append(resource.reservationId()).append('|').append(resource.locationId()) + .append('|').append(resource.availablePackageCount()); } } return hash(canonical.toString()); diff --git a/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml b/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml index daf52d98f..495956511 100644 --- a/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml +++ b/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml @@ -201,7 +201,7 @@ components: items: {$ref: '#/components/schemas/PickItem'} PickItem: type: object - required: [id, loadingPlanItemId, tenantId, inboundId, inboundDetailId, boxCodes, plannedPackageCount, pickedPackageCount, itemStatus, version] + required: [id, loadingPlanItemId, tenantId, inboundId, inboundDetailId, boxCodes, inventoryResources, plannedPackageCount, pickedPackageCount, itemStatus, version] properties: id: {type: integer, format: int64} loadingPlanItemId: {type: integer, format: int64} @@ -215,6 +215,10 @@ components: type: array description: Stable carton label codes; one successful scan represents one carton items: {type: string} + inventoryResources: + type: array + description: Current authoritative whole-block slot snapshots for this inbound; never projected from legacy occupancy rows + items: {$ref: '#/components/schemas/InventoryResource'} plannedPackageCount: {type: integer, minimum: 1} pickedPackageCount: {type: integer, minimum: 0} itemStatus: {type: string, enum: [PENDING, PICKING, PICKED, PARTIAL, SKIPPED]} @@ -334,12 +338,16 @@ components: items: {$ref: '#/components/schemas/InventoryResource'} InventoryResource: type: object - required: [reservationId, occupancyId, palletId, locationId, sharedOverflow, availablePackageCount] + required: [blockId, slotNo, reservationId, locationId, sharedOverflow, slotStatus, availablePackageCount] properties: + blockId: {type: integer, format: int64} + slotNo: {type: integer, minimum: 1} reservationId: {type: integer, format: int64} - occupancyId: {type: integer, format: int64} - palletId: {type: integer, format: int64} + weightResultId: {type: integer, format: int64, nullable: true} + palletSequence: {type: integer, minimum: 1, nullable: true} + palletId: {type: integer, format: int64, nullable: true} locationId: {type: integer, format: int64} locationCode: {type: string, nullable: true} sharedOverflow: {type: boolean} - availablePackageCount: {type: integer, minimum: 1} + slotStatus: {type: string, enum: [RESERVED_EMPTY, BOUND]} + availablePackageCount: {type: integer, minimum: 0} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java index b7b9e7141..7401e6d91 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/PdaConvergenceOpenApiContractTest.java @@ -52,6 +52,8 @@ class PdaConvergenceOpenApiContractTest { String batchItemRequest = yaml.substring( yaml.indexOf(" BatchItemRequest:"), yaml.indexOf(" ReviewRequest:")); + String inventoryResource = yaml.substring( + yaml.indexOf(" InventoryResource:")); assertThat(taskLookup) .contains("name: cabinetNo", "name: loadingPlanId") .doesNotContain("name: containerNo"); @@ -64,5 +66,10 @@ class PdaConvergenceOpenApiContractTest { .doesNotContain("containerNo:"); assertThat(batchItemRequest) .doesNotContain("releaseMode:", "reservationIds:", "locationIds:"); + assertThat(inventoryResource) + .contains("blockId:", "slotNo:", "reservationId:", "weightResultId:", "slotStatus:") + .doesNotContain("occupancyId:"); + assertThat(yaml).contains("inventoryResources:", + "never projected from legacy occupancy rows"); } } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java index 6665d207e..5943da340 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java @@ -11,8 +11,7 @@ import com.baiyue.firstleg.dto.LoadingPickDtos.ClaimRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.AssignRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.CompleteLoadingRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.Task; -import com.baiyue.firstleg.client.WarehousePalletLocationClient; -import com.baiyue.common.core.api.ApiResponse; +import com.baiyue.firstleg.entity.InboundPalletAllocationEntity; import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity; import com.baiyue.firstleg.entity.LoadingPickHistoryEntity; import com.baiyue.firstleg.entity.LoadingPickItemEntity; @@ -33,6 +32,7 @@ import com.baiyue.firstleg.loading.coload.model.ColoadGroupModels.Member; import com.baiyue.firstleg.mapper.InboundStatusHistoryMapper; import com.baiyue.firstleg.mapper.LoadingPickItemMapper; import com.baiyue.firstleg.repository.LoadingPickRepository; +import com.baiyue.firstleg.repository.InboundPalletAllocationRepository; import com.baiyue.firstleg.repository.LoadingCompletionCommandRepository; import com.baiyue.firstleg.repository.SmartLoadingRepository; import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository; @@ -100,7 +100,7 @@ class LoadingPickServiceTest { @MockBean private PdaPickSettlementService settlementService; @MockBean - private WarehousePalletLocationClient warehouse; + private InboundPalletAllocationRepository palletAllocations; @Resource private LoadingPickService service; @@ -122,6 +122,10 @@ class LoadingPickServiceTest { when(completionCommands.insert(any())).thenReturn(1); when(completionCommands.renew(anyLong(), anyString(), any(java.time.LocalDateTime.class))).thenReturn(true); when(repository.acceptCompletion(anyLong(), anyInt())).thenReturn(1); + when(repository.inboundOwners(anyLong())).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(101L, 50L))); + when(repository.inbound(anyLong(), anyLong())).thenAnswer(invocation -> + new LoadingInboundMapper.Snapshot(invocation.getArgument(1), invocation.getArgument(0), "LOADING", 1)); } @Test @@ -437,6 +441,7 @@ class LoadingPickServiceTest { when(repository.allTaskItemsResolved(20L)).thenReturn(false); when(repository.inboundOwners(20L)).thenReturn(List.of( new LoadingPickItemMapper.InboundOwner(101L, 50L))); + when(palletAllocations.list(101L, 50L)).thenReturn(List.of(allocation(50L, 2))); when(repository.inbound(101L, 50L)).thenReturn( new LoadingInboundMapper.Snapshot(50L, 101L, "LOADING", 7)); var result = service.task(20L, 101L); @@ -449,6 +454,14 @@ class LoadingPickServiceTest { assertThat(result.sourceType()).isEqualTo("SIMULATION"); assertThat(result.recordStatus()).isEqualTo("ACTIVE"); assertThat(result.mergedIntoContainerBookingId()).isNull(); + assertThat(result.items().get(0).inventoryResources()).singleElement().satisfies(resource -> { + assertThat(resource.blockId()).isEqualTo(71L); + assertThat(resource.slotNo()).isEqualTo(1); + assertThat(resource.reservationId()).isEqualTo(72L); + assertThat(resource.locationId()).isEqualTo(74L); + assertThat(resource.availablePackageCount()).isEqualTo(2); + }); + verify(palletAllocations).list(101L, 50L); verify(completionCommands, never()).latest(20L); } @@ -458,7 +471,9 @@ class LoadingPickServiceTest { when(repository.task(20L)).thenReturn(task); when(repository.items(20L, 101L)).thenReturn(List.of(item())); when(repository.cartonLabels(20L)).thenReturn(List.of()); - when(repository.inboundOwners(20L)).thenReturn(List.of()); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(101L, 50L))); + when(palletAllocations.list(101L, 50L)).thenReturn(List.of()); doThrow(new IllegalStateException("completion command schema unavailable")) .when(completionCommands).latest(20L); @@ -1123,10 +1138,17 @@ class LoadingPickServiceTest { when(repository.allTaskItemsResolved(20L)).thenReturn(true); when(repository.touchTask(20L, 0)).thenReturn(1); when(repository.allPlanItemsPicked(10L)).thenReturn(true); - when(warehouse.occupiedResources(any(), any(Long.class), any(), any(Long.class))).thenReturn( - ApiResponse.success(List.of(new WarehousePalletLocationClient.OccupiedResource( - 71L, 72L, 0, 101L, 73L, 74L, "A-01", false, 2)))); - String snapshotToken = service.inventorySnapshot(20L, 101L).snapshotToken(); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(1L, 50L), + new LoadingPickItemMapper.InboundOwner(1L, 51L))); + when(palletAllocations.list(anyLong(), anyLong())).thenAnswer(invocation -> + List.of(allocation(invocation.getArgument(1), 2))); + var snapshot = service.inventorySnapshot(20L, 101L); + String snapshotToken = snapshot.snapshotToken(); + assertThat(snapshot.inbounds()).hasSize(2); + assertThat(snapshot.inbounds().get(0).resources().get(0)) + .extracting("blockId", "slotNo", "reservationId", "locationId", "availablePackageCount") + .containsExactly(71L, 1, 72L, 74L, 2); BatchRequest request = new BatchRequest(101L, 10L, 99L, 0, snapshotToken, List.of( new BatchItemRequest(30L, "PICK", 2, null, 0, null), new BatchItemRequest(31L, "SKIP", null, null, 0, "damaged carton"))); @@ -1164,9 +1186,10 @@ class LoadingPickServiceTest { when(repository.touchTask(20L, 0)).thenReturn(1); when(smartLoadingRepository.startPicking(10L, 9L, "operator")).thenReturn(1); when(smartLoadingRepository.operation("PDA-START-20")).thenReturn(existingStart); - when(warehouse.occupiedResources(any(), any(Long.class), any(), any(Long.class))).thenReturn( - ApiResponse.success(List.of(new WarehousePalletLocationClient.OccupiedResource( - 71L, 72L, 0, 101L, 73L, 74L, "A-01", false, 100)))); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(1L, 50L))); + when(palletAllocations.list(anyLong(), anyLong())).thenAnswer(invocation -> + List.of(allocation(invocation.getArgument(1), 100))); String snapshotToken = service.inventorySnapshot(20L, 101L).snapshotToken(); BatchRequest request = new BatchRequest(101L, 10L, 99L, 0, snapshotToken, List.of( new BatchItemRequest(30L, "PICK", 100, null, 0, null))); @@ -1215,9 +1238,10 @@ class LoadingPickServiceTest { when(repository.assignment(20L)).thenReturn(assignment()); when(repository.items(20L)).thenReturn(List.of(picked)); when(repository.items(20L, 101L)).thenReturn(List.of(picked)); - when(warehouse.occupiedResources(any(), any(Long.class), any(), any(Long.class))).thenReturn( - ApiResponse.success(List.of(new WarehousePalletLocationClient.OccupiedResource( - 71L, 72L, 0, 101L, 73L, 74L, "A-01", false, 2)))); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(1L, 50L))); + when(palletAllocations.list(anyLong(), anyLong())).thenAnswer(invocation -> + List.of(allocation(invocation.getArgument(1), 2))); BatchRequest request = new BatchRequest(101L, 10L, 99L, 0, "0".repeat(64), List.of( new BatchItemRequest(30L, "PICK", 2, null, 0, null))); @@ -1258,9 +1282,10 @@ class LoadingPickServiceTest { when(repository.pick(30L, 2, 0, 101L)).thenReturn(1); when(repository.allTaskItemsResolved(20L)).thenReturn(true); when(repository.touchTask(20L, 0)).thenReturn(1); - when(warehouse.occupiedResources(any(), any(Long.class), any(), any(Long.class))).thenReturn( - ApiResponse.success(List.of(new WarehousePalletLocationClient.OccupiedResource( - 71L, 72L, 0, 101L, 73L, 74L, "A-01", false, 2)))); + when(repository.inboundOwners(20L)).thenReturn(List.of( + new LoadingPickItemMapper.InboundOwner(1L, 50L))); + when(palletAllocations.list(anyLong(), anyLong())).thenAnswer(invocation -> + List.of(allocation(invocation.getArgument(1), 2))); String snapshotToken = service.inventorySnapshot(20L, 101L).snapshotToken(); BatchItemRequest line = new BatchItemRequest(30L, "PICK", 2, null, 0, null); @@ -1378,6 +1403,27 @@ class LoadingPickServiceTest { return item; } + private static InboundPalletAllocationEntity allocation(long inboundId, int packageCount) { + InboundPalletAllocationEntity allocation = new InboundPalletAllocationEntity(); + allocation.setId(72L); + allocation.setTenantId(1L); + allocation.setInboundId(inboundId); + allocation.setBlockId(71L); + allocation.setSlotNo(1); + allocation.setAllocationNo(1); + allocation.setWarehouseId(101L); + allocation.setPalletId(73L); + allocation.setLocationId(74L); + allocation.setLocationCode("A-01"); + allocation.setSharedOverflow(false); + allocation.setReservationId(72L); + allocation.setSlotStatus("BOUND"); + allocation.setAllocationStatus("CONFIRMED"); + allocation.setAllocatedPackageCount(packageCount); + allocation.setPickedPackageCount(0); + return allocation; + } + private static LoadingPickAssignmentEntity assignment() { LoadingPickAssignmentEntity assignment = new LoadingPickAssignmentEntity(); assignment.setPickTaskId(20L); diff --git a/scripts/admin-test-env-modules/phase3-loading.mjs b/scripts/admin-test-env-modules/phase3-loading.mjs index 2220b49f9..da9ad2755 100644 --- a/scripts/admin-test-env-modules/phase3-loading.mjs +++ b/scripts/admin-test-env-modules/phase3-loading.mjs @@ -124,8 +124,10 @@ function inventorySignature(snapshot) { inboundId: id(inbound?.inboundId), availablePackageCount: Number(inbound?.availablePackageCount), resources: (inbound?.resources || []).map((resource) => ({ - reservationId: id(resource?.reservationId), occupancyId: id(resource?.occupancyId), - palletId: id(resource?.palletId), locationId: id(resource?.locationId), + blockId: id(resource?.blockId), slotNo: Number(resource?.slotNo), + reservationId: id(resource?.reservationId), weightResultId: id(resource?.weightResultId), + palletSequence: Number(resource?.palletSequence), palletId: id(resource?.palletId), + locationId: id(resource?.locationId), slotStatus: resource?.slotStatus || null, sharedOverflow: resource?.sharedOverflow === true, availablePackageCount: Number(resource?.availablePackageCount), })), @@ -622,8 +624,9 @@ export async function run(context) { && id(inventory?.warehouseId) === warehouseId && Boolean(inventory?.capturedAt) && typeof inventory?.snapshotToken === 'string' && inventory.snapshotToken.length === 64 && Number(inventoryInbound?.availablePackageCount) >= 1 - && (inventoryInbound?.resources || []).every((resource) => id(resource?.reservationId) - && id(resource?.occupancyId) && id(resource?.palletId) && id(resource?.locationId) + && (inventoryInbound?.resources || []).every((resource) => id(resource?.blockId) + && Number(resource?.slotNo) >= 1 && id(resource?.reservationId) && id(resource?.locationId) + && ['RESERVED_EMPTY', 'BOUND'].includes(resource?.slotStatus) && Number(resource?.availablePackageCount) >= 0) && Number(inventoryInbound?.availablePackageCount) === (inventoryInbound?.resources || []) .reduce((total, resource) => total + Number(resource?.availablePackageCount || 0), 0)