From 1e8d85c714f6cb8857c179886366e75a41423ab4 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 24 Aug 2026 22:51:33 +0800 Subject: [PATCH] fix: support id-only overseas destinations --- .../pda/service/InboundStockReceiptService.java | 7 +++++-- .../command/dto/InventoryCommandRequests.java | 4 ++-- .../command/service/InventoryCommandService.java | 14 ++++++++++---- .../command/InventoryCommandServiceTest.java | 16 ++++++++++++++++ .../phase3-port-schedules.mjs | 10 +++++----- .../phase3-producer-chain-contract.test.mjs | 1 + 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptService.java index f236833d4..114d20195 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptService.java @@ -188,8 +188,11 @@ public class InboundStockReceiptService { if (packages <= 0 || pallet.getWarehousePalletId() == null) { throw conflict("Stock-in requires picked packages and an assigned warehouse pallet"); } - String destinationCode = required(first(line.getDestinationWarehouseCode(), order.getFbaWarehouseCode()), - "Destination warehouse code is required for stock-in"); + String destinationCode = first(line.getDestinationWarehouseCode(), order.getFbaWarehouseCode()); + if (destinationCode == null && trim(line.getDestinationWarehouseId()) == null) { + throw conflict("Destination warehouse ID or code is required for stock-in"); + } + if (destinationCode == null) destinationCode = ""; String operationKey = "PDA_STOCK_IN:" + task.getId() + ":" + allocation.getId() + ":" + sku.skuCode(); String overseasWarehouseId = required(order.getOverseasWarehouseId(), "Actual overseas warehouse is required for stock-in"); diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/dto/InventoryCommandRequests.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/dto/InventoryCommandRequests.java index 48e7b0a3d..2773296fa 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/dto/InventoryCommandRequests.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/dto/InventoryCommandRequests.java @@ -17,7 +17,7 @@ public final class InventoryCommandRequests { String overseasWarehouseCode, String overseasWarehouseName, String destinationWarehouseId, - @NotBlank String destinationWarehouseCode, + String destinationWarehouseCode, String destinationWarehouseName, @NotNull Long inboundOrderId, @NotBlank String inboundOrderNo, @@ -44,7 +44,7 @@ public final class InventoryCommandRequests { String overseasWarehouseCode, String overseasWarehouseName, String destinationWarehouseId, - @NotBlank String destinationWarehouseCode, + String destinationWarehouseCode, String destinationWarehouseName, @NotNull Long inboundOrderId, @NotBlank String inboundOrderNo, diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java index cc8d917af..f42015986 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java @@ -233,8 +233,14 @@ public class InventoryCommandService { String inboundCode, String requestedSkuCode, String productNameZh, String productNameEn) { String skuCode = sku(requestedSkuCode); + String destinationId = trim(destinationWarehouseId); + String destinationCode = trim(destinationWarehouseCode); + if (destinationId == null && destinationCode == null) { + throw badRequest("Destination warehouse ID or code is required"); + } + if (destinationCode == null) destinationCode = ""; InventoryBalance balance = balances.lockDimension(customerId, overseasWarehouseId, - destinationWarehouseCode, inboundOrderId, inboundCode); + destinationCode, inboundOrderId, inboundCode); if (balance != null) { mergeSkuSnapshot(balance, skuCode); return balance; @@ -246,8 +252,8 @@ public class InventoryCommandService { balance.setOverseasWarehouseId(overseasWarehouseId.trim()); balance.setOverseasWarehouseCode(trim(overseasWarehouseCode)); balance.setOverseasWarehouseName(trim(overseasWarehouseName)); - balance.setDestinationWarehouseId(trim(destinationWarehouseId)); - balance.setDestinationWarehouseCode(destinationWarehouseCode.trim()); + balance.setDestinationWarehouseId(destinationId); + balance.setDestinationWarehouseCode(destinationCode); balance.setDestinationWarehouseName(trim(destinationWarehouseName)); balance.setInboundOrderId(inboundOrderId); balance.setInboundOrderNo(inboundOrderNo.trim()); @@ -264,7 +270,7 @@ public class InventoryCommandService { return balance; } catch (DuplicateKeyException exception) { InventoryBalance concurrent = balances.lockDimension(customerId, overseasWarehouseId, - destinationWarehouseCode, inboundOrderId, inboundCode); + destinationCode, inboundOrderId, inboundCode); if (concurrent != null) { mergeSkuSnapshot(concurrent, skuCode); return concurrent; diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryCommandServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryCommandServiceTest.java index 1fa98af51..5722fc1e3 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryCommandServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryCommandServiceTest.java @@ -92,6 +92,22 @@ class InventoryCommandServiceTest { verify(ledgers).insert(any(InventoryLedger.class)); } + @Test + void registersIdOnlyOverseasDestinationWithoutInventingAWarehouseCode() { + when(balances.lockDimension("100", "WH-1", "", 101L, "IN-CODE-1")).thenReturn(null); + InventoryCommandRequests.InTransit request = new InventoryCommandRequests.InTransit( + "Customer 100", "WH-1", "WH1", "Warehouse 1", "DEST-OVERSEAS", null, + "New York warehouse", 101L, "IN-1", "IN-CODE-1", "SKU-1", "Product 1", null, + 1, "ORD-1", "EVT-1", "transit-id-only", null); + + service.registerInTransit("100", "SYSTEM", request); + + ArgumentCaptor inserted = ArgumentCaptor.forClass(InventoryBalance.class); + verify(balances).insert(inserted.capture()); + assertEquals("DEST-OVERSEAS", inserted.getValue().getDestinationWarehouseId()); + assertEquals("", inserted.getValue().getDestinationWarehouseCode()); + } + @Test void stockInTransfersPackagesFromInTransitToAvailable() { InventoryBalance balance = balance(200L, 0); diff --git a/scripts/admin-test-env-modules/phase3-port-schedules.mjs b/scripts/admin-test-env-modules/phase3-port-schedules.mjs index 1611f64e5..314271727 100644 --- a/scripts/admin-test-env-modules/phase3-port-schedules.mjs +++ b/scripts/admin-test-env-modules/phase3-port-schedules.mjs @@ -56,9 +56,9 @@ function oceanDraft(context, suffix, master) { } } -async function ensureOceanBooking(context, suffix, master) { - if (context.createdResources?.oceanBooking?.id) { - const existingId = id(context.createdResources.oceanBooking.id) +async function ensureOceanBooking(context, suffix, master, preferredOceanBookingId = null) { + const existingId = id(preferredOceanBookingId || context.createdResources?.oceanBooking?.id) + if (existingId) { const response = await request(context, 'GET', `${OCEAN}/${existingId}`) const detail = context.apiSuccess(MODULE, '读取船期关联订舱真实柜次分配', response, `oceanBookingId=${existingId}`, OPTIONS) @@ -118,10 +118,10 @@ export async function run(context) { const master = await resolveOceanBookingMaster(context, MODULE) if (!master) return - const ocean = await ensureOceanBooking(context, suffix, master) - if (!ocean?.id) return const flow = context.createdResources?.phase3Loading || context.createdResources?.phase3ContainerLoading + const ocean = await ensureOceanBooking(context, suffix, master, flow?.oceanBookingId) + if (!ocean?.id) return const containerBookingId = ['COMPLETED', 'LOADED'].includes(flow?.finalStatus) ? id(flow.containerBookingId) : null const knownAllocation = containerBookingId diff --git a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs index c5d841082..9d9038c6c 100644 --- a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs @@ -503,6 +503,7 @@ test('downstream container consumers prefer the phase3Loading fixture', () => { assert.doesNotMatch(serviceCenter, /链路承运商-/) assert.doesNotMatch(serviceCenter, /customerName: `服务中心链路客户-/) const schedules = source('./phase3-port-schedules.mjs') + assert.match(schedules, /ensureOceanBooking\(context, suffix, master, flow\?\.oceanBookingId\)/) assert.match(schedules, /allocatedContainerBookingIds: \(detail\.containers \|\| \[\]\)/) assert.match(schedules, /ocean\.allocatedContainerBookingIds\?\.includes\(containerBookingId\)/) assert.match(schedules, /if \(containerBookingId && !knownAllocation\)/)