fix: classify equivalent outbound no-stock results

This commit is contained in:
zgw
2026-09-15 10:56:11 +08:00
parent 8dbdd411bf
commit acc6994385
3 changed files with 152 additions and 1 deletions

View File

@@ -211,6 +211,43 @@ class ShadowPlanningEngineTest {
eq(SNAPSHOT.synchronizedAt()), eq("ABC123"), eq("LEGACY_10"), any());
}
@Test
void outboundComparisonMatchesWhenBothPlannersReportNoInventory() {
ShadowInputMapper mapper = mock(ShadowInputMapper.class);
when(mapper.insertComparison(any(), any(), any(), any(Long.class),
any(Instant.class), any(), any(), any())).thenReturn(1);
ShadowPlanningEngine engine = engine(mock(SchedulingFacade.class), mapper);
OutboundShadowObservation observation = OutboundShadowObservation.unavailable(
SNAPSHOT, "DETAIL-1", "ERROR_STOCK_NOT_FOUND", "no matching inventory");
engine.compareOutbound(observation, "3");
verify(mapper).insertComparison(any(), eq("01"), eq("OUTBOUND_COMPARE"), eq(42L),
eq(SNAPSHOT.synchronizedAt()), eq("ABC123"), eq("MATCH_NO_INVENTORY"),
argThat(reason -> reason.contains("shadow=ERROR_STOCK_NOT_FOUND")
&& reason.contains("legacy=3")));
}
@Test
void outboundComparisonDoesNotMatchNoInventoryAgainstTechnicalOrDifferentOutcomes() {
ShadowInputMapper mapper = mock(ShadowInputMapper.class);
when(mapper.insertComparison(any(), any(), any(), any(Long.class),
any(Instant.class), any(), any(), any())).thenReturn(1);
ShadowPlanningEngine engine = engine(mock(SchedulingFacade.class), mapper);
OutboundShadowObservation technical = OutboundShadowObservation.unavailable(
SNAPSHOT, "DETAIL-1", "ERROR_TECHNICAL", "database failure");
OutboundShadowObservation noInventory = OutboundShadowObservation.unavailable(
SNAPSHOT, "DETAIL-2", "ERROR_STOCK_NOT_FOUND", "no matching inventory");
engine.compareOutbound(technical, "3");
engine.compareOutbound(noInventory, "10");
verify(mapper).insertComparison(any(), eq("01"), eq("OUTBOUND_COMPARE"), eq(42L),
eq(SNAPSHOT.synchronizedAt()), eq("ABC123"), eq("LEGACY_3"), any());
verify(mapper).insertComparison(any(), eq("01"), eq("OUTBOUND_COMPARE"), eq(42L),
eq(SNAPSHOT.synchronizedAt()), eq("ABC123"), eq("LEGACY_10"), any());
}
@Test
void inboundComparisonRetainsRequiredEvidenceWhenUnicodeReasonIsOversized() {
ShadowInputMapper mapper = mock(ShadowInputMapper.class);