diff --git a/firstleg/src/main/java/com/baiyue/firstleg/split/service/SplitPreloadService.java b/firstleg/src/main/java/com/baiyue/firstleg/split/service/SplitPreloadService.java index 97fba7bb1..89e12cbb3 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/split/service/SplitPreloadService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/split/service/SplitPreloadService.java @@ -79,11 +79,18 @@ public class SplitPreloadService { SplitActionResponse replay = claimOrReplay(tenantId, inboundId, operatorId, START_CONFIRMING, key); if (replay != null) return replay; InboundSnapshot inbound = requireInbound(tenantId, inboundId); - requireStatus(inbound, "INBOUNDED", "仅待分柜订单可以提交预装清单确认"); + boolean loading = "LOADING".equals(inbound.processStatus()); + if (loading) { + // Starting a real loading task advances the inbound before its preload + // confirmation is submitted; retain the linked-container hard gate. + loadingModelBridge.requireStarted(tenantId, inboundId); + } else { + requireStatus(inbound, "INBOUNDED", "仅待分柜订单可以提交预装清单确认"); + } PreloadPlanEntity plan = requirePlan(tenantId, inboundId); if (PreloadStatus.CONFIRMING.equals(plan.getStatus())) { return complete(tenantId, inboundId, operatorId, START_CONFIRMING, key, - new SplitActionResponse("INBOUNDED", response(plan))); + new SplitActionResponse(loading ? "LOADING" : "INBOUNDED", response(plan))); } if (!PreloadStatus.PENDING.equals(plan.getStatus()) || repository.changePlanStatus(tenantId, inboundId, PreloadStatus.PENDING, @@ -91,7 +98,8 @@ public class SplitPreloadService { throw concurrent(); } return complete(tenantId, inboundId, operatorId, START_CONFIRMING, key, - new SplitActionResponse("INBOUNDED", response(repository.findPlan(tenantId, inboundId)))); + new SplitActionResponse(loading ? "LOADING" : "INBOUNDED", + response(repository.findPlan(tenantId, inboundId)))); } @Transactional diff --git a/firstleg/src/test/java/com/baiyue/firstleg/split/service/SplitPreloadServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/split/service/SplitPreloadServiceTest.java index c9f434fab..4ed1d210d 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/split/service/SplitPreloadServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/split/service/SplitPreloadServiceTest.java @@ -21,6 +21,7 @@ import java.math.BigDecimal; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -72,4 +73,36 @@ class SplitPreloadServiceTest { verify(loadingModelBridge).requireStarted(10, 20); verify(repository).beginLoading(10, 20, 7, 4); } + + @Test + void startsPreloadConfirmationAfterLoadingBeginsWithLinkedContainerGate() { + when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString())).thenReturn(true); + when(repository.findInbound(10, 20)).thenReturn(new InboundSnapshot(20L, 10L, "LOADING", 5)); + PreloadPlanEntity plan = new PreloadPlanEntity(); + plan.setTenantId(10L); plan.setInboundId(20L); plan.setStatus("PENDING"); plan.setVersion(3); + plan.setItemsJson("[]"); + when(repository.findPlan(10, 20)).thenReturn(plan); + org.mockito.Mockito.doNothing().when(loadingModelBridge).requireStarted(10, 20); + when(repository.changePlanStatus(10, 20, "PENDING", "CONFIRMING", 7, "admin", 3)).thenReturn(1); + + SplitActionResponse result = service.startConfirming(10, 20, 7, "admin", "k4", + new ConfirmPreloadRequest(3)); + + assertThat(result.mainStatus()).isEqualTo("LOADING"); + verify(loadingModelBridge).requireStarted(10, 20); + verify(repository).changePlanStatus(10, 20, "PENDING", "CONFIRMING", 7, "admin", 3); + } + + @Test + void rejectsLoadingPreloadConfirmationWhenLinkedContainersHaveNotStarted() { + when(repository.claimOperation(anyLong(), anyLong(), anyLong(), anyString(), anyString())).thenReturn(true); + when(repository.findInbound(10, 20)).thenReturn(new InboundSnapshot(20L, 10L, "LOADING", 5)); + org.mockito.Mockito.doThrow(new IllegalStateException("not started")) + .when(loadingModelBridge).requireStarted(10, 20); + + assertThatThrownBy(() -> service.startConfirming(10, 20, 7, "admin", "k5", + new ConfirmPreloadRequest(3))) + .isInstanceOf(IllegalStateException.class) + .hasMessage("not started"); + } }