补充PDA装柜完成阶段诊断

This commit is contained in:
2026-08-24 20:47:13 +08:00
parent 360115de35
commit 015fc09091
2 changed files with 45 additions and 6 deletions
@@ -459,9 +459,11 @@ public class LoadingPickService {
for (LoadingPickItemMapper.InboundOwner owner : owners) {
LoadingInboundMapper.Snapshot snapshot = repository.inboundForUpdate(owner.tenantId(), owner.inboundId());
if (snapshot == null) throw conflict("PDA任务关联入库单不存在");
loadingDeliveryService.requirePdaCompletionReady(owner.tenantId(), owner.inboundId());
completionStage(taskId, "完成前业务门禁", () ->
loadingDeliveryService.requirePdaCompletionReady(owner.tenantId(), owner.inboundId()));
}
settlementService.settle(taskId, operatorId, operatorName);
completionStage(taskId, "拆单与库位结算", () ->
settlementService.settle(taskId, operatorId, operatorName));
if (!repository.allPlanItemsPicked(task.getLoadingPlanId())) {
throw conflict("柜次仍有未完成PDA拣货的箱数");
}
@@ -469,17 +471,32 @@ public class LoadingPickService {
throw conflict("PDA任务已经复核");
}
insertOperation(taskId, operationId, requestHash, "COMPLETE_LOADING", operatorId, operatorName);
loadingListService.finishFromPda(task.getLoadingPlanId(), taskId, operatorId, operatorName);
completionStage(taskId, "装柜计划完成", () ->
loadingListService.finishFromPda(task.getLoadingPlanId(), taskId, operatorId, operatorName));
repository.syncInboundProjections(taskId, operatorId, operatorName);
for (LoadingPickItemMapper.InboundOwner owner : owners) {
loadingDeliveryService.completeAfterPdaSettlement(owner.tenantId(), owner.inboundId(), operatorId,
operatorName, "PDA-" + operationId + '-' + owner.inboundId(), remark);
completionStage(taskId, "入库单状态完成", () ->
loadingDeliveryService.completeAfterPdaSettlement(owner.tenantId(), owner.inboundId(), operatorId,
operatorName, "PDA-" + operationId + '-' + owner.inboundId(), remark));
}
loadingListService.publishCompletedEvent(task.getLoadingPlanId());
completionStage(taskId, "完成事件发布", () ->
loadingListService.publishCompletedEvent(task.getLoadingPlanId()));
completeTruckAfterCommit(task.getContainerBookingId(), taskId, operatorId, operatorName);
return view(requiredTask(taskId), null);
}
private void completionStage(long taskId, String stage, Runnable action) {
try {
action.run();
} catch (BizException exception) {
throw exception;
} catch (RuntimeException exception) {
log.error("Unexpected PDA loading completion failure taskId={} stage={}", taskId, stage, exception);
throw new BizException(ResultCode.INTERNAL_ERROR,
"装柜完成在【" + stage + "】阶段处理异常,请联系管理员并提供请求编号");
}
}
private void completeTruckAfterCommit(long containerBookingId, long taskId,
long operatorId, String operatorName) {
Runnable completion = () -> {
@@ -585,6 +585,28 @@ class LoadingPickServiceTest {
verify(loadingListService, never()).publishCompletedEvent(anyLong());
}
@Test
void translatesUnexpectedSettlementFailureIntoActionableStageMessage() {
LoadingPickTaskEntity task = task();
when(repository.taskForUpdate(20L)).thenReturn(task);
when(repository.allTaskItemsResolved(20L)).thenReturn(true);
var owner = new LoadingPickItemMapper.InboundOwner(101L, 50L);
when(repository.inboundOwners(20L)).thenReturn(List.of(owner));
when(repository.inboundForUpdate(101L, 50L)).thenReturn(
new LoadingInboundMapper.Snapshot(50L, 101L, "LOADING", 7));
doThrow(new IllegalStateException("unexpected database failure"))
.when(settlementService).settle(20L, 9L, "operator");
assertThatThrownBy(() -> service.complete(20L,
new CompleteLoadingRequest(0, "complete-stage-error", "checked"), 9L, "operator"))
.isInstanceOf(BizException.class)
.hasMessageContaining("拆单与库位结算")
.hasMessageContaining("请求编号");
verify(repository, never()).approve(anyLong(), anyLong(), anyString(), anyString());
verify(loadingListService, never()).finishFromPda(anyLong(), anyLong(), anyLong(), anyString());
}
@Test
void atomicallySubmitsCompleteBatchAndReplaysSameResult() {
LoadingPickTaskEntity task = task();