From ac18f69ec5ad4348a696b8816dd52f771f641e34 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 7 Sep 2026 21:10:43 +0800 Subject: [PATCH] fix(lastleg): preserve dropship source pallets --- deploy/sql/海外区域统一增量-MySQL8.sql | 18 ++++++++++++++++++ .../dropship/service/DropshipOrderService.java | 4 ++-- .../inboundplan/entity/InboundPlanPallet.java | 1 + .../pda/entity/InboundStockReceipt.java | 1 + .../pda/service/InboundPdaWorkflowService.java | 2 +- .../service/InboundStockReceiptService.java | 3 ++- .../service/InboundPlanService.java | 4 +++- .../src/main/resources/db/lastleg.sql | 8 +++++--- .../service/DropshipOrderServiceTest.java | 3 ++- .../service/InboundPdaWorkflowServiceTest.java | 2 ++ .../InboundStockReceiptServiceTest.java | 6 +++++- .../service/InboundPlanServiceTest.java | 4 ++++ 12 files changed, 46 insertions(+), 10 deletions(-) diff --git a/deploy/sql/海外区域统一增量-MySQL8.sql b/deploy/sql/海外区域统一增量-MySQL8.sql index d21a9c28c..7f1bd7736 100644 --- a/deploy/sql/海外区域统一增量-MySQL8.sql +++ b/deploy/sql/海外区域统一增量-MySQL8.sql @@ -1842,3 +1842,21 @@ CALL assert_receiving_warehouse_assignment_ready(); DROP PROCEDURE assert_receiving_warehouse_assignment_ready; SELECT 'PASS' AS migration_status, '海外接柜仓预分配与柜级修改结构已就绪' AS message; + +-- 一件代发来源托盘与海外仓实物托盘分离,实物绑定不得覆盖来源身份。 +USE baiyue_lastleg; +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() + AND table_name='ll_inbound_plan_pallet' AND column_name='source_pallet_no'), + 'SELECT 1', + 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; +ALTER TABLE ll_inbound_plan_pallet + MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '当前托盘编号:分配前为计划占位码,分配后为海外仓实物托盘码'; + +SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() + AND table_name='ll_inbound_stock_receipt' AND column_name='source_pallet_no'), + 'SELECT 1', + 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; +ALTER TABLE ll_inbound_stock_receipt + MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '海外仓实物托盘码'; diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/dropship/service/DropshipOrderService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/dropship/service/DropshipOrderService.java index c8e1e029f..3c75db35d 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/dropship/service/DropshipOrderService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/dropship/service/DropshipOrderService.java @@ -135,8 +135,8 @@ public class DropshipOrderService { throw conflict("Dropship pallet activation is incomplete; repair profiles before retrying"); } Map> receiptsByPallet = receipts.stream() - .filter(receipt -> receipt.getPalletNo() != null) - .collect(Collectors.groupingBy(InboundStockReceipt::getPalletNo)); + .filter(receipt -> receipt.getSourcePalletNo() != null) + .collect(Collectors.groupingBy(InboundStockReceipt::getSourcePalletNo)); if (receiptsByPallet.size() != profilesForOrder.size()) { throw conflict("PDA pallet count does not match dropship source pallet count"); } diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundPlanPallet.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundPlanPallet.java index 28eea73e4..fbd1be83b 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundPlanPallet.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/entity/InboundPlanPallet.java @@ -16,6 +16,7 @@ public class InboundPlanPallet { private String customerId; private Long planId; private String palletNo; + private String sourcePalletNo; private String destinationWarehouseId; private String destinationWarehouseCode; private String destinationWarehouseName; diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/entity/InboundStockReceipt.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/entity/InboundStockReceipt.java index 410985cdc..c3b936225 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/entity/InboundStockReceipt.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/entity/InboundStockReceipt.java @@ -25,6 +25,7 @@ public class InboundStockReceipt { private String productNameEn; private Long warehousePalletId; private String palletNo; + private String sourcePalletNo; private Long warehouseLocationId; private String warehouseLocationCode; private String batchNo; diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowService.java index 872c68bda..78ca21628 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowService.java @@ -945,7 +945,7 @@ public class InboundPdaWorkflowService { boolean wholePalletInbound = "ONE_CLICK_DROPSHIP".equals(orderType); Map palletsByNo = wholePalletInbound ? repository.pallets(plan.getId()).stream().collect(java.util.stream.Collectors.toMap( - InboundPlanPallet::getPalletNo, value -> value)) : Map.of(); + InboundPlanPallet::getSourcePalletNo, value -> value)) : Map.of(); Map allocationsByPallet = wholePalletInbound ? allocations.stream().collect(java.util.stream.Collectors.toMap( InboundPlanPalletAllocation::getPalletId, value -> value)) : Map.of(); 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 0a7b27372..c2a92f054 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 @@ -116,7 +116,7 @@ public class InboundStockReceiptService { if (value(allocation.getPickedPackageCount()) != value(allocation.getPlannedPackageCount())) { throw conflict("One-click dropship inbound must receive a complete source pallet"); } - DropshipPalletSnapshot sourcePallet = dropshipPallets.get(pallet.getPalletNo()); + DropshipPalletSnapshot sourcePallet = dropshipPallets.get(pallet.getSourcePalletNo()); if (sourcePallet == null || sourcePallet.packageCount() != value(allocation.getPickedPackageCount())) { throw conflict("One-click dropship source pallet SKU package total does not match PDA receipt"); } @@ -261,6 +261,7 @@ public class InboundStockReceiptService { receipt.setProductNameEn(sku.productNameEn()); receipt.setWarehousePalletId(pallet.getWarehousePalletId()); receipt.setPalletNo(pallet.getPalletNo()); + receipt.setSourcePalletNo(pallet.getSourcePalletNo()); receipt.setWarehouseLocationId(pallet.getWarehouseLocationId()); receipt.setBatchNo(plan.getPlanNo()); receipt.setReceivedPackages(packages); 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 99d7ccacb..4c5f08a41 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 @@ -297,7 +297,8 @@ public class InboundPlanService { if (palletVolume.compareTo(remainingVolume) > 0) palletVolume = remainingVolume; InboundPlanPallet pallet = new InboundPlanPallet(); pallet.setId(IdWorker.getId()); pallet.setCustomerId(plan.getCustomerId()); pallet.setPlanId(plan.getId()); - pallet.setPalletNo(source.palletNo().trim()); pallet.setDestinationWarehouseId(order.destinationWarehouseId()); + pallet.setPalletNo(source.palletNo().trim()); pallet.setSourcePalletNo(source.palletNo().trim()); + pallet.setDestinationWarehouseId(order.destinationWarehouseId()); pallet.setDestinationWarehouseCode(order.destinationWarehouseCode()); pallet.setDestinationWarehouseName(order.destinationWarehouseName()); pallet.setCapacityCbm(PalletAllocator.PALLET_CAPACITY_CBM); pallet.setAllocatedVolumeCbm(palletVolume); @@ -437,6 +438,7 @@ public class InboundPlanService { String sourcePalletNo = palletIndex < sourcePalletNos.size() ? sourcePalletNos.get(palletIndex) : null; pallet.setPalletNo(sourcePalletNo == null || sourcePalletNo.isBlank() ? plan.getPlanNo() + "-P" + String.format("%03d", palletIndex + 1) : sourcePalletNo.trim()); + pallet.setSourcePalletNo(sourcePalletNo == null || sourcePalletNo.isBlank() ? null : sourcePalletNo.trim()); pallet.setDestinationWarehouseId(sample.destinationWarehouseId()); pallet.setDestinationWarehouseCode(sample.destinationWarehouseCode()); pallet.setDestinationWarehouseName(sample.destinationWarehouseName()); diff --git a/lastleg-service/src/main/resources/db/lastleg.sql b/lastleg-service/src/main/resources/db/lastleg.sql index ebd69ebc2..8749cd660 100644 --- a/lastleg-service/src/main/resources/db/lastleg.sql +++ b/lastleg-service/src/main/resources/db/lastleg.sql @@ -555,7 +555,8 @@ CREATE TABLE IF NOT EXISTS ll_inbound_plan_pallet ( id BIGINT NOT NULL COMMENT '计划托盘ID(雪花ID)', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', plan_id BIGINT NOT NULL COMMENT '入库计划ID', - pallet_no VARCHAR(64) NOT NULL COMMENT '计划托盘编号', + pallet_no VARCHAR(64) NOT NULL COMMENT '当前托盘编号:分配前为计划占位码,分配后为海外仓实物托盘码', + source_pallet_no VARCHAR(128) NULL COMMENT '一件代发不可变来源托盘号快照', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', @@ -617,7 +618,7 @@ ALTER TABLE ll_inbound_plan_pallet COMMENT='尾程入库计划托盘表:按目 ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN id BIGINT NOT NULL COMMENT '计划托盘ID(雪花ID)', MODIFY COLUMN plan_id BIGINT NOT NULL COMMENT '入库计划ID', - MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '计划托盘编号', + MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '当前托盘编号:分配前为计划占位码,分配后为海外仓实物托盘码', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', @@ -1105,7 +1106,8 @@ CREATE TABLE IF NOT EXISTS ll_inbound_stock_receipt ( line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', order_id BIGINT NOT NULL COMMENT '订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照', product_name_zh VARCHAR(255) NULL COMMENT '中文品名快照', product_name_en VARCHAR(255) NULL COMMENT '英文品名快照', - warehouse_pallet_id BIGINT NOT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(64) NOT NULL COMMENT '托盘号', + warehouse_pallet_id BIGINT NOT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(64) NOT NULL COMMENT '海外仓实物托盘码', + source_pallet_no VARCHAR(128) NULL COMMENT '一件代发不可变来源托盘号快照', warehouse_location_id BIGINT NULL COMMENT '仓库库位ID', warehouse_location_code VARCHAR(128) NULL COMMENT '仓库库位编码', batch_no VARCHAR(128) NOT NULL COMMENT '库存批次号', received_packages BIGINT NOT NULL COMMENT '实收箱数', inventory_balance_id BIGINT NOT NULL COMMENT '库存余额记录ID', inventory_position_id BIGINT NOT NULL COMMENT '库存仓位记录ID', diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/dropship/service/DropshipOrderServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/dropship/service/DropshipOrderServiceTest.java index 9c37e00a0..28d916bfe 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/dropship/service/DropshipOrderServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/dropship/service/DropshipOrderServiceTest.java @@ -141,7 +141,8 @@ class DropshipOrderServiceTest { private static InboundStockReceipt receipt(long palletId, String palletNo, long positionId, long packages) { InboundStockReceipt receipt = new InboundStockReceipt(); - receipt.setOrderId(10L); receipt.setWarehousePalletId(palletId); receipt.setPalletNo(palletNo); + receipt.setOrderId(10L); receipt.setWarehousePalletId(palletId); + receipt.setPalletNo("WH-" + palletId); receipt.setSourcePalletNo(palletNo); receipt.setInventoryPositionId(positionId); receipt.setReceivedPackages(packages); return receipt; } diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowServiceTest.java index 8d90ec21f..f8093b7c4 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowServiceTest.java @@ -557,6 +557,8 @@ class InboundPdaWorkflowServiceTest { @Test void dropshipTaskIsMarkedAndWholePalletPickReceivesThePlannedPalletAtOnce() { plan.setSourceOrderId(101L); + targetPallet.setPalletNo("WH-PALLET-21"); + targetPallet.setSourcePalletNo("PLT-21"); LastlegOrder order = new LastlegOrder(); order.setId(101L); order.setOrderType("ONE_CLICK_DROPSHIP"); when(repository.order(101L)).thenReturn(order); diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptServiceTest.java index 9ebb45b68..a6278e98c 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptServiceTest.java @@ -218,6 +218,7 @@ class InboundStockReceiptServiceTest { void activatesDropshipAfterGenericStockInReceiptIsCreated() { Fixture fixture = fixture(5, 5, 5, 10); fixture.order.setOrderType("ONE_CLICK_DROPSHIP"); + fixture.pallet.setPalletNo("WH-PALLET-21"); when(dropshipOrders.palletSnapshots("100", 101L)).thenReturn(List.of(dropshipPallet("PLT-21", 5))); when(orders.selectBatchIds(any())).thenReturn(List.of(fixture.order)); when(inventory.stockIn(eq("100"), eq("operator"), any(InventoryCommandRequests.StockIn.class))) @@ -230,6 +231,8 @@ class InboundStockReceiptServiceTest { verify(dropshipOrders).activateAfterStockIn(eq("100"), eq(101L), eq(2L), activationReceipts.capture()); assertEquals(1, activationReceipts.getValue().size()); assertEquals(10L, activationReceipts.getValue().get(0).getInventoryPositionId()); + assertEquals("PLT-21", activationReceipts.getValue().get(0).getSourcePalletNo()); + assertEquals("WH-PALLET-21", activationReceipts.getValue().get(0).getPalletNo()); } @Test @@ -311,7 +314,8 @@ class InboundStockReceiptServiceTest { private InboundPlanPallet pallet(long id, long warehousePalletId) { InboundPlanPallet pallet = new InboundPlanPallet(); pallet.setId(id); pallet.setPlanId(1L); - pallet.setPalletNo("PLT-" + id); pallet.setWarehousePalletId(warehousePalletId); + pallet.setPalletNo("PLT-" + id); pallet.setSourcePalletNo("PLT-" + id); + pallet.setWarehousePalletId(warehousePalletId); pallet.setWarehouseLocationId(3001L); return pallet; } 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 77f2e42a5..0908f48d0 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 @@ -253,6 +253,8 @@ class InboundPlanServiceTest { verify(palletMapper, times(2)).insert(pallets.capture()); assertEquals(List.of("SOURCE-P-1", "SOURCE-P-2"), pallets.getAllValues().stream().map(InboundPlanPallet::getPalletNo).toList()); + assertEquals(List.of("SOURCE-P-1", "SOURCE-P-2"), + pallets.getAllValues().stream().map(InboundPlanPallet::getSourcePalletNo).toList()); ArgumentCaptor allocations = ArgumentCaptor.forClass(InboundPlanPalletAllocation.class); verify(allocationMapper, times(2)).insert(allocations.capture()); @@ -354,6 +356,8 @@ class InboundPlanServiceTest { verify(palletMapper, times(2)).insert(pallets.capture()); assertEquals(List.of("SOURCE-P-1", "SOURCE-P-2"), pallets.getAllValues().stream().map(InboundPlanPallet::getPalletNo).toList()); + assertEquals(List.of("SOURCE-P-1", "SOURCE-P-2"), + pallets.getAllValues().stream().map(InboundPlanPallet::getSourcePalletNo).toList()); ArgumentCaptor allocations = ArgumentCaptor.forClass(InboundPlanPalletAllocation.class); verify(allocationMapper, times(2)).insert(allocations.capture());