From ca69434698371134b27fcf880ecacbe7991e5d70 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 25 Aug 2026 18:11:29 +0800 Subject: [PATCH] fix: persist PDA movement state semantics --- .../service/PdaPalletOperationService.java | 3 ++- .../move/service/PdaInventoryMoveService.java | 11 ++++---- .../PdaPalletOperationServiceTest.java | 25 +++++++++++++++++++ .../service/PdaInventoryMoveServiceTest.java | 14 ++++++++--- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java index 3bc77d10c..076d3c66d 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java @@ -264,7 +264,8 @@ public class PdaPalletOperationService { ledger.setBusinessType(operation.getOperationType()); ledger.setBusinessOrderId(operation.getId()); ledger.setBusinessOrderNo(String.valueOf(operation.getId())); ledger.setInboundCode(balance.getInboundCode()); ledger.setInboundOrderNo(balance.getInboundOrderNo()); ledger.setIdempotencyKey(idempotencyKey); - ledger.setStatusFrom("PALLET:" + sourcePallet); ledger.setStatusTo("PALLET:" + targetPallet); + ledger.setStatusFrom("OCCUPIED"); + ledger.setStatusTo("UNBOUND".equals(targetPallet) ? "UNBOUND" : "OCCUPIED"); ledger.setBeforePackages(before); ledger.setDeltaPackages(delta); ledger.setAfterPackages(after); ledger.setOperatorId(identity.operatorKey()); ledger.setRemark(trim(reason)); ledger.setOccurredAt(LocalDateTime.now()); ledger.setCreatedAt(ledger.getOccurredAt()); ledgers.insert(ledger); diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveService.java b/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveService.java index 03be9225d..ab7b71d58 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveService.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveService.java @@ -117,8 +117,7 @@ public class PdaInventoryMoveService { position.setWarehouseLocationId(target.locationId()); position.setWarehouseLocationCode(target.locationCode()); position.setVersion(value(position.getVersion()) + 1); position.setUpdatedAt(completedAt); positions.updateById(position); - ledger(operation, position, balance, operatorKey, key, request.reason(), source.locationCode(), - target.locationCode(), completedAt); + ledger(operation, position, balance, operatorKey, key, request.reason(), completedAt); } operation.setPalletVersionAfter(relocated.afterVersion()); operation.setStatus("COMPLETED"); operation.setCompletedAt(completedAt); @@ -150,18 +149,18 @@ public class PdaInventoryMoveService { } private void ledger(PdaInventoryMove operation, InventoryPosition position, InventoryBalance balance, - String operator, String key, String reason, String source, String target, - LocalDateTime now) { + String operator, String key, String reason, LocalDateTime now) { InventoryLedger row = new InventoryLedger(); row.setId(IdWorker.getId()); row.setCustomerId(position.getCustomerId()); row.setBalanceId(balance.getId()); row.setPositionId(position.getId()); row.setOverseasWarehouseId(String.valueOf(operation.getOverseasWarehouseId())); row.setDestinationWarehouseCode(balance.getDestinationWarehouseCode()); row.setInboundOrderId(balance.getInboundOrderId()); row.setPalletId(position.getPalletId()); row.setPalletNo(position.getPalletNo()); row.setBatchNo(position.getBatchNo()); - row.setSkuCode(balance.getSkuCode()); row.setWarehouseLocationCode(target); row.setBusinessType("INTERNAL_MOVE"); + row.setSkuCode(balance.getSkuCode()); row.setWarehouseLocationCode(position.getWarehouseLocationCode()); + row.setBusinessType("INTERNAL_MOVE"); row.setBusinessOrderId(operation.getId()); row.setBusinessOrderNo(operation.getMoveNo()); row.setInboundCode(balance.getInboundCode()); row.setInboundOrderNo(balance.getInboundOrderNo()); row.setIdempotencyKey("MOVE:" + operation.getId() + ":" + position.getId()); - row.setStatusFrom(source); row.setStatusTo(target); long packages = physical(position); + row.setStatusFrom("OCCUPIED"); row.setStatusTo("OCCUPIED"); long packages = physical(position); row.setBeforePackages(packages); row.setDeltaPackages(0L); row.setAfterPackages(packages); row.setOperatorId(operator); row.setRemark(reason.trim()); row.setOccurredAt(now); row.setCreatedAt(now); ledgers.insert(row); diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java index 59301bc76..d13c5b887 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java @@ -3,6 +3,9 @@ package com.baiyue.lastleg.palletops.service; import com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper; import com.baiyue.lastleg.inventory.mapper.InventoryLedgerMapper; import com.baiyue.lastleg.inventory.mapper.InventoryPositionMapper; +import com.baiyue.lastleg.inventory.entity.InventoryBalance; +import com.baiyue.lastleg.inventory.entity.InventoryLedger; +import com.baiyue.lastleg.inventory.entity.InventoryPosition; import com.baiyue.lastleg.palletops.dto.PalletOperationRequests; import com.baiyue.lastleg.palletops.entity.PdaPalletOperation; import com.baiyue.lastleg.palletops.gateway.PalletPhysicalGateway; @@ -15,6 +18,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.TransactionDefinition; @@ -94,6 +98,27 @@ class PdaPalletOperationServiceTest { verifyNoInteractions(ledgers, history); } + @Test void inventoryLedgerStoresStateSemanticsInsteadOfLongPalletCodes() { + InventoryBalance balance = new InventoryBalance(); balance.setId(200L); balance.setCustomerId("100"); + balance.setOverseasWarehouseId("88"); balance.setInboundOrderId(300L); balance.setInboundCode("IN-1"); + InventoryPosition position = new InventoryPosition(); position.setId(100L); position.setPalletId(20L); + position.setPalletNo("PDAOPS-ADMIN-API-20260825095854036-SWAP-TARGET"); + position.setBatchNo("DEFAULT"); position.setWarehouseLocationCode("PDAOPS-LONG-LOCATION-CODE"); + PdaPalletOperation operation = new PdaPalletOperation(); operation.setId(400L); + operation.setOperationType("PALLET_SWAP"); + + ReflectionTestUtils.invokeMethod(service, "ledger", identity(), operation, balance, position, + "idem:out", 5L, -5L, 0L, + "PDAOPS-ADMIN-API-20260825095854036-SOURCE", + "PDAOPS-ADMIN-API-20260825095854036-TARGET", "swap"); + + ArgumentCaptor ledger = ArgumentCaptor.forClass(InventoryLedger.class); + verify(ledgers).insert(ledger.capture()); + assertEquals("OCCUPIED", ledger.getValue().getStatusFrom()); + assertEquals("OCCUPIED", ledger.getValue().getStatusTo()); + assertEquals("PDAOPS-LONG-LOCATION-CODE", ledger.getValue().getWarehouseLocationCode()); + } + private static PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("7", "picker", 88L); } private static PalletPhysicalGateway.PalletReference pallet(long id, String code, long warehouse, int version) { return new PalletPhysicalGateway.PalletReference(id, code, warehouse, 1000L + id, diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveServiceTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveServiceTest.java index cdb3714ae..7207e9c2f 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveServiceTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveServiceTest.java @@ -60,9 +60,10 @@ class PdaInventoryMoveServiceTest { @Test void atomicallyRelocatesPhysicalPalletAndEveryWarehouseScopedPosition() { + String targetLocationCode = "PDAOPS-ADMIN-API-20260825095854036-MOVE"; when(warehouse.resolvePallet("PAL-1")).thenReturn(pallet(900L, 20L, 2)); when(warehouse.resolveLocation(900L, 20L)).thenReturn(location(20L, "A-01")); - when(warehouse.resolveLocation(900L, "B-01")).thenReturn(location(21L, "B-01")); + when(warehouse.resolveLocation(900L, targetLocationCode)).thenReturn(location(21L, targetLocationCode)); InventoryPosition position = new InventoryPosition(); position.setId(11L); position.setCustomerId("100"); position.setBalanceId(10L); position.setOverseasWarehouseId("900"); position.setPalletId(30L); position.setPalletNo("PAL-1"); position.setWarehouseLocationId(20L); position.setWarehouseLocationCode("A-01"); @@ -76,7 +77,7 @@ class PdaInventoryMoveServiceTest { eq(21L), anyString(), eq("库位优化"))).thenReturn(transition(false)); var response = service.move(900L, "operator-1", - new PdaInventoryMoveRequest("PAL-1", "B-01", 2, "move-1", "库位优化")); + new PdaInventoryMoveRequest("PAL-1", targetLocationCode, 2, "move-1", "库位优化")); verify(physical).apply(eq(900L), argThat(value -> value.palletId() == 30L && value.locationId() == 20L && value.version() == 2), eq("OCCUPIED"), @@ -84,11 +85,16 @@ class PdaInventoryMoveServiceTest { ArgumentCaptor updated = ArgumentCaptor.forClass(InventoryPosition.class); verify(positions).updateById(updated.capture()); assertThat(updated.getValue().getWarehouseLocationId()).isEqualTo(21L); - assertThat(updated.getValue().getWarehouseLocationCode()).isEqualTo("B-01"); + assertThat(updated.getValue().getWarehouseLocationCode()).isEqualTo(targetLocationCode); assertThat(response.packageCount()).isEqualTo(6L); assertThat(response.palletVersion()).isEqualTo(3); assertThat(response.status()).isEqualTo("COMPLETED"); - verify(ledgers).insert(any(InventoryLedger.class)); verify(moves).updateById(any(PdaInventoryMove.class)); + ArgumentCaptor ledger = ArgumentCaptor.forClass(InventoryLedger.class); + verify(ledgers).insert(ledger.capture()); + assertThat(ledger.getValue().getStatusFrom()).isEqualTo("OCCUPIED"); + assertThat(ledger.getValue().getStatusTo()).isEqualTo("OCCUPIED"); + assertThat(ledger.getValue().getWarehouseLocationCode()).isEqualTo(targetLocationCode); + verify(moves).updateById(any(PdaInventoryMove.class)); } @Test