From af7e00c9a0f29de9e4d67101246d3a2e94bcc3b3 Mon Sep 17 00:00:00 2001 From: zgw <13623675548@163.com> Date: Thu, 3 Sep 2026 16:46:54 +0800 Subject: [PATCH] fix: close shadow activity on legacy failures --- .../api/service/impl/ToWmsServiceImpl.java | 10 ++++-- .../service/impl/OutStockoutServiceImpl.java | 18 ++++++---- .../impl/ToWmsServiceImplShadowTest.java | 23 +++++++++++++ .../OutStockoutServiceImplShadowTest.java | 34 +++++++++++++++++++ 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java index da99219..3438487 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java @@ -420,10 +420,14 @@ public class ToWmsServiceImpl implements IToWmsService { try { shadowCompletion = shadowObservationGateway.observeInbound(taskNo, inJob.getTrayCode()); } catch (RuntimeException exception) { - log.warn("Inbound shadow submission failed open for task {}: {}", - taskNo, exception.getMessage()); + // Shadow admission is best-effort; Legacy continues unchanged. + } + try { + mydoJobMapper.allotInJobSpace(map); + } catch (RuntimeException | Error legacyFailure) { + shadowCompletion.fail(legacyFailure); + throw legacyFailure; } - mydoJobMapper.allotInJobSpace(map); String legacyResultCode = map.get("v_result").toString(); if (!"10".equals(legacyResultCode)) { shadowCompletion.complete(legacyResultCode, null); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImpl.java index a286d22..dfeb911 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImpl.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImpl.java @@ -202,7 +202,12 @@ public class OutStockoutServiceImpl implements IOutStockoutService map.put("v_resultmsg", null); OutboundShadowCompletion shadowCompletion = observeProjectOutboundShadow(detail.getStockoutDetailId()); - outStockoutMapper.autoAllot(map); + try { + outStockoutMapper.autoAllot(map); + } catch (RuntimeException | Error legacyFailure) { + shadowCompletion.fail(legacyFailure); + throw legacyFailure; + } shadowCompletion.complete(map.get("v_result")); if (!"10".equals(map.get("v_result"))){ stringBuilder.append(",").append(detail.getStockoutDetailId()+map.get("v_resultmsg")); @@ -232,7 +237,12 @@ public class OutStockoutServiceImpl implements IOutStockoutService map.put("v_stock_id", stock); OutboundShadowCompletion shadowCompletion = observeExactStockOutboundShadow(stockoutDetailId, stock); - outStockoutMapper.manualAllot(map); + try { + outStockoutMapper.manualAllot(map); + } catch (RuntimeException | Error legacyFailure) { + shadowCompletion.fail(legacyFailure); + throw legacyFailure; + } shadowCompletion.complete(map.get("v_result")); //toWcsService.pushOutMydoJob(); if (!"10".equals(map.get("v_result"))){ @@ -249,8 +259,6 @@ public class OutStockoutServiceImpl implements IOutStockoutService try { return shadowObservationGateway.observeProjectOutbound(stockoutDetailId); } catch (RuntimeException exception) { - log.warn("Project outbound shadow submission failed open for detail {}: {}", - stockoutDetailId, exception.getMessage()); return OutboundShadowCompletion.rejected(); } } @@ -259,8 +267,6 @@ public class OutStockoutServiceImpl implements IOutStockoutService try { return shadowObservationGateway.observeExactStockOutbound(stockoutDetailId, stockId); } catch (RuntimeException exception) { - log.warn("Exact-stock shadow submission failed open for detail {} stock {}: {}", - stockoutDetailId, stockId, exception.getMessage()); return OutboundShadowCompletion.rejected(); } } diff --git a/ruoyi-admin/src/test/java/com/ruoyi/api/service/impl/ToWmsServiceImplShadowTest.java b/ruoyi-admin/src/test/java/com/ruoyi/api/service/impl/ToWmsServiceImplShadowTest.java index 2319601..f827721 100644 --- a/ruoyi-admin/src/test/java/com/ruoyi/api/service/impl/ToWmsServiceImplShadowTest.java +++ b/ruoyi-admin/src/test/java/com/ruoyi/api/service/impl/ToWmsServiceImplShadowTest.java @@ -17,9 +17,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.util.HashMap; 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.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,6 +50,9 @@ class ToWmsServiceImplShadowTest { beforeLegacy = inboundJob("TRAY-1", null); legacyResult = inboundJob("TRAY-1", "SPACE-LEGACY"); when(mydoJobMapper.selectInJobByTaskNo("TASK-1")).thenReturn(beforeLegacy, legacyResult); + } + + private void prepareSuccessfulLegacyAllocation() { doAnswer(invocation -> { @SuppressWarnings("unchecked") HashMap parameters = invocation.getArgument(0); @@ -58,6 +64,7 @@ class ToWmsServiceImplShadowTest { @Test void submitsObservationBeforeLegacyAndReturnsTheReloadedLegacyJob() { + prepareSuccessfulLegacyAllocation(); when(shadowObservationGateway.observeInbound("TASK-1", "TRAY-1")) .thenReturn(shadowCompletion); @@ -75,6 +82,7 @@ class ToWmsServiceImplShadowTest { @Test void shadowExceptionCannotSkipOrReplaceLegacyAllocation() { + prepareSuccessfulLegacyAllocation(); when(shadowObservationGateway.observeInbound("TASK-1", "TRAY-1")) .thenThrow(new IllegalStateException("shadow unavailable")); @@ -85,6 +93,21 @@ class ToWmsServiceImplShadowTest { verify(mydoJobMapper, times(1)).allotInJobSpace(any()); } + @Test + void legacyExceptionClosesShadowActivityAndEscapesUnchanged() { + IllegalStateException legacyFailure = new IllegalStateException("legacy database failure"); + when(shadowObservationGateway.observeInbound("TASK-1", "TRAY-1")) + .thenReturn(shadowCompletion); + doThrow(legacyFailure).when(mydoJobMapper).allotInJobSpace(any()); + + assertThatThrownBy(() -> service.requestEnterByTaskNo(request)) + .isSameAs(legacyFailure); + + verify(shadowCompletion, times(1)).fail(legacyFailure); + verify(shadowCompletion, never()).complete(any(), any()); + verify(mydoJobMapper, times(1)).allotInJobSpace(any()); + } + private MydoJob inboundJob(String trayNo, String cargoSpaceId) { MydoJob job = new MydoJob(); job.setInOrOut("10"); diff --git a/ruoyi-admin/src/test/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImplShadowTest.java b/ruoyi-admin/src/test/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImplShadowTest.java index c7935fc..e2824d7 100644 --- a/ruoyi-admin/src/test/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImplShadowTest.java +++ b/ruoyi-admin/src/test/java/com/ruoyi/out/outStockout/service/impl/OutStockoutServiceImplShadowTest.java @@ -20,10 +20,13 @@ import java.util.HashMap; 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.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -94,6 +97,22 @@ class OutStockoutServiceImplShadowTest { verify(outStockoutMapper, times(1)).autoAllot(any()); } + @Test + void autoAllotLegacyExceptionClosesShadowActivityAndEscapesUnchanged() { + IllegalStateException legacyFailure = new IllegalStateException("legacy database failure"); + prepareAutoAllot(); + when(shadowObservationGateway.observeProjectOutbound("DETAIL-1")) + .thenReturn(shadowCompletion); + doThrow(legacyFailure).when(outStockoutMapper).autoAllot(any()); + + assertThatThrownBy(() -> service.autoAllot("OUT-1")) + .isSameAs(legacyFailure); + + verify(shadowCompletion, times(1)).fail(legacyFailure); + verify(shadowCompletion, never()).complete(any()); + verify(outStockoutMapper, times(1)).autoAllot(any()); + } + @Test void missingShadowStockStillRunsManualAllotOncePerSelectedStock() { OutboundShadowCompletion firstCompletion = mock(OutboundShadowCompletion.class); @@ -120,6 +139,21 @@ class OutStockoutServiceImplShadowTest { verify(secondCompletion).complete("10"); } + @Test + void manualAllotLegacyErrorClosesShadowActivityAndEscapesUnchanged() { + AssertionError legacyFailure = new AssertionError("legacy fatal failure"); + when(shadowObservationGateway.observeExactStockOutbound("DETAIL-1", "STOCK-1")) + .thenReturn(shadowCompletion); + doThrow(legacyFailure).when(outStockoutMapper).manualAllot(any()); + + assertThatThrownBy(() -> service.manualAllot(new String[]{"STOCK-1"}, "DETAIL-1")) + .isSameAs(legacyFailure); + + verify(shadowCompletion, times(1)).fail(legacyFailure); + verify(shadowCompletion, never()).complete(any()); + verify(outStockoutMapper, times(1)).manualAllot(any()); + } + private void prepareAutoAllot() { OutStockout bill = new OutStockout(); bill.setStatus("2");