From 16a2f83da67e683d4200ceac14ee1514f9facff6 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 11 Aug 2026 15:19:14 +0800 Subject: [PATCH] fix(firstleg): start loading when PDA task is claimed --- .../firstleg/service/LoadingPickService.java | 5 +-- .../service/LoadingPickServiceTest.java | 36 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java index bed597ee9..935829b4f 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingPickService.java @@ -127,6 +127,7 @@ public class LoadingPickService { throw conflict("PDA任务分配版本已变化"); } } + startPickingIfNeeded(task, operatorId, operatorName); insertOperation(taskId, operationId, requestHash, "CLAIM", operatorId, operatorName); return view(task, null); } @@ -384,7 +385,7 @@ public class LoadingPickService { } } - /** 首笔实际拣货才将预装柜计划推进为拣货中;领取、跳拣和任务创建均不改变货柜状态。 */ + /** 进入PDA拣货任务即将预装柜计划推进为拣货中;状态推进和历史写入保持幂等。 */ private void startPickingIfNeeded(LoadingPickTaskEntity task, long operatorId, String operatorName) { if (smartLoadingRepository.startPicking(task.getLoadingPlanId(), operatorId, operatorName) != 1) { return; @@ -399,7 +400,7 @@ public class LoadingPickService { history.setAfterSnapshot("{\"source\":\"PDA\",\"status\":\"LOADING\"}"); history.setOperatorId(operatorId); history.setOperatorName(operatorName); - history.setOperationReason("首笔实际拣货"); + history.setOperationReason("进入PDA拣货任务"); smartLoadingRepository.insert(history); } diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java index da6a9688c..e989d2083 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/LoadingPickServiceTest.java @@ -7,6 +7,7 @@ import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.BatchRequest; import com.baiyue.firstleg.dto.LoadingPickDtos.BatchItemRequest; +import com.baiyue.firstleg.dto.LoadingPickDtos.ClaimRequest; import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity; import com.baiyue.firstleg.entity.LoadingPickHistoryEntity; import com.baiyue.firstleg.entity.LoadingPickItemEntity; @@ -25,6 +26,7 @@ import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -79,7 +81,7 @@ class LoadingPickServiceTest { } @Test - void startsLoadingOnlyAfterTheFirstActualPick() { + void keepsPickAsStartLoadingFallbackForOlderClients() { LoadingPickTaskEntity task = task(); LoadingPickItemEntity item = item(); preparePick(task, item, "pick-start-loading"); @@ -92,6 +94,38 @@ class LoadingPickServiceTest { verify(smartLoadingRepository).insert(any(com.baiyue.firstleg.entity.LoadingPlanHistoryEntity.class)); } + @Test + void claimStartsLoadingAndSameOperatorReentryDoesNotDuplicateStartHistory() { + LoadingPickTaskEntity task = task(); + LoadingPickAssignmentEntity assignment = assignment(); + AtomicReference operation = new AtomicReference<>(); + when(repository.operation("claim-1")).thenAnswer(invocation -> operation.get()); + when(repository.operation("claim-2")).thenReturn(null); + when(repository.task(20L)).thenReturn(task); + when(repository.taskForUpdate(20L)).thenReturn(task); + when(repository.assignment(20L)).thenReturn(null, assignment); + when(repository.createAssignment(20L, 9L, "operator", 9L, "operator", "CLAIMED")).thenReturn(1); + when(smartLoadingRepository.startPicking(10L, 9L, "operator")).thenReturn(1, 0); + doAnswer(invocation -> { + LoadingPickOperationEntity value = invocation.getArgument(0); + if ("claim-1".equals(value.getOperationId())) operation.set(value); + return null; + }).when(repository).insert(any(LoadingPickOperationEntity.class)); + + service.claim(20L, new ClaimRequest(0, "claim-1"), 9L, "operator"); + service.claim(20L, new ClaimRequest(0, "claim-1"), 9L, "operator"); + service.claim(20L, new ClaimRequest(0, "claim-2"), 9L, "operator"); + + verify(smartLoadingRepository, times(2)).startPicking(10L, 9L, "operator"); + verify(smartLoadingRepository, times(1)).insert(argThat( + (com.baiyue.firstleg.entity.LoadingPlanHistoryEntity history) -> + "START_LOADING".equals(history.getActionType()) + && "EDITING".equals(history.getFromStatus()) + && "LOADING".equals(history.getToStatus()) + && "PDA-START-20".equals(history.getOperationId()))); + verify(repository, times(1)).createAssignment(20L, 9L, "operator", 9L, "operator", "CLAIMED"); + } + @Test void touchesTaskBeforeCompletingLastPartialItem() { LoadingPickTaskEntity task = task();