feat: observe outbound allocation without changing legacy
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package com.ruoyi.out.outStockout.service.impl;
|
||||
|
||||
import com.ruoyi.algorithm.shadow.OutboundShadowObservation;
|
||||
import com.ruoyi.algorithm.shadow.ShadowObservationGateway;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.out.outStockout.domain.OutStockout;
|
||||
import com.ruoyi.out.outStockout.mapper.OutStockoutMapper;
|
||||
import com.ruoyi.out.outStockoutDetail.domain.OutStockoutDetail;
|
||||
import com.ruoyi.out.outStockoutDetail.service.IOutStockoutDetailService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class OutStockoutServiceImplShadowTest {
|
||||
@Mock
|
||||
private OutStockoutMapper outStockoutMapper;
|
||||
@Mock
|
||||
private IOutStockoutDetailService outStockoutDetailService;
|
||||
@Mock
|
||||
private ShadowObservationGateway shadowObservationGateway;
|
||||
@InjectMocks
|
||||
private OutStockoutServiceImpl service;
|
||||
|
||||
private OutStockoutDetail pendingDetail;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
pendingDetail = new OutStockoutDetail();
|
||||
pendingDetail.setStockoutDetailId("DETAIL-1");
|
||||
pendingDetail.setQuantity(BigDecimal.TEN);
|
||||
pendingDetail.setAllotQuantity(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingShadowProjectStillRunsAutoAllotAndPreservesLegacyWarning() {
|
||||
prepareAutoAllot();
|
||||
OutboundShadowObservation missingProject = OutboundShadowObservation.unavailable(
|
||||
"W01", "DETAIL-1", "SKIPPED_MISSING_PROJECT", "missing project");
|
||||
when(shadowObservationGateway.planProjectOutbound("DETAIL-1")).thenReturn(missingProject);
|
||||
doAnswer(invocation -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, String> parameters = invocation.getArgument(0);
|
||||
parameters.put("v_result", "20");
|
||||
parameters.put("v_resultmsg", "LEGACY-WARNING");
|
||||
return null;
|
||||
}).when(outStockoutMapper).autoAllot(any());
|
||||
|
||||
AjaxResult result = service.autoAllot("OUT-1");
|
||||
|
||||
assertThat(result.get(AjaxResult.MSG_TAG)).isEqualTo(",DETAIL-1LEGACY-WARNING");
|
||||
InOrder order = inOrder(shadowObservationGateway, outStockoutMapper);
|
||||
order.verify(shadowObservationGateway).planProjectOutbound("DETAIL-1");
|
||||
order.verify(outStockoutMapper).autoAllot(any());
|
||||
order.verify(shadowObservationGateway).compareOutbound(missingProject, "20");
|
||||
verify(outStockoutMapper, times(1)).autoAllot(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shadowExceptionStillRunsAutoAllotAndPreservesLegacySuccess() {
|
||||
prepareAutoAllot();
|
||||
when(shadowObservationGateway.planProjectOutbound("DETAIL-1"))
|
||||
.thenThrow(new IllegalStateException("shadow unavailable"));
|
||||
doAnswer(invocation -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, String> parameters = invocation.getArgument(0);
|
||||
parameters.put("v_result", "10");
|
||||
parameters.put("v_resultmsg", "ok");
|
||||
return null;
|
||||
}).when(outStockoutMapper).autoAllot(any());
|
||||
|
||||
AjaxResult result = service.autoAllot("OUT-1");
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
verify(shadowObservationGateway).planProjectOutbound("DETAIL-1");
|
||||
verify(outStockoutMapper, times(1)).autoAllot(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingShadowStockStillRunsManualAllotOncePerSelectedStock() {
|
||||
OutboundShadowObservation missingStock = OutboundShadowObservation.unavailable(
|
||||
"W01", "DETAIL-1", "SKIPPED_MISSING_STOCK", "missing stock");
|
||||
when(shadowObservationGateway.planExactStockOutbound("DETAIL-1", "STOCK-1"))
|
||||
.thenReturn(missingStock);
|
||||
when(shadowObservationGateway.planExactStockOutbound("DETAIL-1", "STOCK-2"))
|
||||
.thenReturn(missingStock);
|
||||
doAnswer(invocation -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, String> parameters = invocation.getArgument(0);
|
||||
parameters.put("v_result", "10");
|
||||
parameters.put("v_resultString", "ok");
|
||||
return null;
|
||||
}).when(outStockoutMapper).manualAllot(any());
|
||||
|
||||
AjaxResult result = service.manualAllot(new String[]{"STOCK-1", "STOCK-2"}, "DETAIL-1");
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
verify(outStockoutMapper, times(2)).manualAllot(any());
|
||||
verify(shadowObservationGateway).planExactStockOutbound("DETAIL-1", "STOCK-1");
|
||||
verify(shadowObservationGateway).planExactStockOutbound("DETAIL-1", "STOCK-2");
|
||||
verify(shadowObservationGateway, times(2)).compareOutbound(missingStock, "10");
|
||||
}
|
||||
|
||||
private void prepareAutoAllot() {
|
||||
OutStockout bill = new OutStockout();
|
||||
bill.setStatus("2");
|
||||
when(outStockoutMapper.selectOutStockoutByStockoutId("OUT-1")).thenReturn(bill);
|
||||
when(outStockoutDetailService.selectOutStockoutDetailList(any()))
|
||||
.thenReturn(List.of(pendingDetail));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user