fix(inventory): enforce warehouse transfer reservation ownership

This commit is contained in:
2026-10-05 07:24:53 +08:00
parent 548a133de6
commit 5b4d9624a9
14 changed files with 293 additions and 62 deletions
@@ -74,6 +74,43 @@ class InventoryCommandServiceTest {
lenient().when(commands.lockInboundTransitBalances(any(), any(), any())).thenReturn(List.of());
}
@Test
void rejectsDispatchAndRelabelAgainstTransferReservationEvenWithForgedBusinessKey() {
var balance = balance(200L, 1);
var position = new InventoryPosition(); position.setId(300L); position.setBalanceId(200L);
position.setAvailablePackages(1L);
when(commands.lockPosition("100", 300L)).thenReturn(position);
when(commands.lockBalance("100", 200L)).thenReturn(balance);
lenient().when(commands.transferReservation("100", 300L))
.thenReturn(new InventoryCommandMapper.TransferReservation(900L, 1));
var request = new InventoryCommandRequests.Move(300L, 1, "WT-FORGED", "WT-FORGED",
"WAREHOUSE_TRANSFER_OUTBOUND:WT-FORGED", "WAREHOUSE_TRANSFER:WT-FORGED:ALLOCATE", null);
assertThrows(ResponseStatusException.class, () -> service.allocate("100", "7", request));
assertThrows(ResponseStatusException.class, () -> service.hold("100", "7", request));
assertEquals(1L, position.getAvailablePackages());
verify(positions, never()).updateById(any(InventoryPosition.class));
verify(ledgers, never()).insert(any(InventoryLedger.class));
}
@Test
void onlyExactInternalTransferOwnerCanConsumeReservation() {
var balance = balance(200L, 1);
var position = position(300L, 200L, 1);
when(commands.lockPosition("100", 300L)).thenReturn(position);
when(commands.lockBalance("100", 200L)).thenReturn(balance);
when(commands.transferReservation("100", 300L)).thenReturn(new InventoryCommandMapper.TransferReservation(900L, 1));
var allocate = new InventoryCommandRequests.Move(300L, 1, "WT-1", "WT-1", "EVENT", "ALLOCATE-1", null);
assertThrows(ResponseStatusException.class, () -> service.allocateWarehouseTransfer("100", "7", 901L, allocate, null));
service.allocateWarehouseTransfer("100", "7", 900L, allocate, null);
var pick = new InventoryCommandRequests.Move(300L, 1, "WT-1", "WT-1", "EVENT", "PICK-1", null);
service.pickWarehouseTransfer("100", "7", 900L, pick, null);
var ship = new InventoryCommandRequests.Move(300L, 1, "WT-1", "WT-1", "EVENT", "SHIP-1", null);
service.shipWarehouseTransfer("100", "7", 900L, ship, null);
assertEquals(0L, position.getAvailablePackages());
assertEquals(0L, position.getPickedPackages());
verify(ledgers, times(3)).insert(any(InventoryLedger.class));
}
@Test
void stockInUpdatesBalancePositionAndLedgerInOneTransaction() throws Exception {
assertTrue(InventoryCommandService.class.getMethod("stockIn", String.class, String.class,