fix: replay completed dispatch picks

This commit is contained in:
2026-09-02 02:03:15 +08:00
parent 666add1cf9
commit b5d7be7d28
2 changed files with 17 additions and 11 deletions
@@ -77,22 +77,29 @@ public class DispatchPdaWorkflowService {
DispatchPdaRequests.Pick request) {
DispatchOrder order = requireWarehouseOrder(warehouseId, dispatchNo);
String customerId = order.getCustomerId();
DispatchPdaTask task = tasks.lockByDispatch(customerId, order.getId());
if (task == null) throw conflict("Dispatch PDA task is not available for picking");
if (!warehouseId.equals(task.getWarehouseId())) throw conflict("PDA pick warehouse does not match task warehouse");
DispatchPdaOperation replay = replay(customerId, "PICK", request.idempotencyKey(), request);
if (replay != null) {
DispatchPdaResponses.Picked result = read(replay, DispatchPdaResponses.Picked.class);
if (!task.getId().equals(replay.getTaskId()) || result.dispatchItemId() != itemId) {
throw conflict("Idempotency key was reused with a different dispatch pick request");
}
return result;
}
requirePdaStatus(order);
requireVehicle(order);
items.bindReceivedPallets(customerId, order.getId());
DispatchPdaTask task = tasks.lockByDispatch(customerId, order.getId());
if (task == null || !("PDA_PENDING".equals(task.getStatus()) || "PICKING".equals(task.getStatus()))) {
if (!("PDA_PENDING".equals(task.getStatus()) || "PICKING".equals(task.getStatus()))) {
throw conflict("Dispatch PDA task is not available for picking");
}
if (!warehouseId.equals(task.getWarehouseId())) throw conflict("PDA pick warehouse does not match task warehouse");
bindOperator(task, operatorId, operatorName);
DispatchItem item = items.selectById(itemId);
if (item == null || !customerId.equals(item.getCustomerId()) || !order.getId().equals(item.getDispatchOrderId())) {
throw notFound("Dispatch pallet item not found");
}
if (!warehouseId.equals(item.getOverseasWarehouseId())) throw conflict("Pallet does not belong to selected warehouse");
DispatchPdaOperation replay = replay(customerId, "PICK", request.idempotencyKey(), request);
if (replay != null) return read(replay, DispatchPdaResponses.Picked.class);
InventoryPosition position = positions.selectById(request.positionId());
if (position == null || !customerId.equals(position.getCustomerId())
|| item.getWarehousePalletId() == null || !item.getWarehousePalletId().equals(position.getPalletId())) {
@@ -108,18 +108,16 @@ class DispatchPdaWorkflowServiceTest {
}
@Test
void exactPickRetryReturnsPersistedResultWithoutInventoryDeduction() throws Exception {
DispatchOrder order = order("100", "DSP-1", "WH-1", "PICKING");
void exactPickRetryReturnsPersistedResultAfterTaskAutomaticallyCompleted() throws Exception {
DispatchOrder order = order("100", "DSP-1", "WH-1", "READY_TO_DEPART");
order.setVehiclePlate("CA-100");
DispatchPdaTask task = task(11L, "100", "WH-1", "PICKING");
DispatchPdaTask task = task(11L, "100", "WH-1", "COMPLETED");
task.setOperatorId("7");
DispatchItem item = item(21L, "100", 5);
DispatchPdaRequests.Pick request = new DispatchPdaRequests.Pick(31L, 2, 2, "pick-1", null);
DispatchPdaResponses.Picked persisted = new DispatchPdaResponses.Picked(21L, 31L, 2, 2, false, false);
DispatchPdaOperation replay = operation("PICK", request, persisted);
when(orders.findGlobalByDispatchNo("DSP-1")).thenReturn(order);
when(tasks.lockByDispatch("100", 1L)).thenReturn(task);
when(items.selectById(21L)).thenReturn(item);
when(operations.findKey("100", "pick-1")).thenReturn(replay);
DispatchPdaResponses.Picked result = service.pick("WH-1", "DSP-1", 21L, "7", "Picker", request);
@@ -127,6 +125,7 @@ class DispatchPdaWorkflowServiceTest {
assertEquals(2, result.packages());
verify(inventory, never()).allocate(any(), any(), any());
verify(picks, never()).insert((DispatchPdaPick) any());
verify(items, never()).bindReceivedPallets(any(), any());
}
@Test
@@ -207,7 +206,7 @@ class DispatchPdaWorkflowServiceTest {
private DispatchPdaOperation operation(String type, Object request, Object result) throws Exception {
DispatchPdaOperation value = new DispatchPdaOperation();
value.setOperationType(type); value.setStatus("COMPLETED");
value.setTaskId(11L); value.setOperationType(type); value.setStatus("COMPLETED");
value.setRequestHash(HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256")
.digest(objectMapper.writeValueAsString(request).getBytes(StandardCharsets.UTF_8))));
value.setResultJson(objectMapper.writeValueAsString(result));