package cn.iocoder.yudao.module.mes.service.pro.scan;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventCreateReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.scan.MesProScanEventDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.scan.MesProScanEventMapper;
|
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
|
import org.junit.jupiter.api.*;
|
import org.springframework.test.util.ReflectionTestUtils;
|
import java.math.BigDecimal;
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
|
class MobileScanValidityTest {
|
private final MesProScanEventServiceImpl service=new MesProScanEventServiceImpl();
|
private final MesProScanEventMapper events=mock(MesProScanEventMapper.class);
|
private final MesProBagCodeMapper bags=mock(MesProBagCodeMapper.class);
|
private final MesProPalletMapper pallets=mock(MesProPalletMapper.class);
|
private final MesProBatchMapper batches=mock(MesProBatchMapper.class);
|
private final MesWmTransactionService transactions=mock(MesWmTransactionService.class);
|
private MesProScanEventCreateReqVO req;
|
@BeforeEach void setup(){
|
ReflectionTestUtils.setField(service,"eventMapper",events);
|
ReflectionTestUtils.setField(service,"bagCodeMapper",bags);
|
ReflectionTestUtils.setField(service,"palletMapper",pallets);
|
ReflectionTestUtils.setField(service,"batchMapper",batches);
|
ReflectionTestUtils.setField(service,"transactionService",transactions);
|
req=new MesProScanEventCreateReqVO();req.setEventId("new");req.setBagCode("123");
|
req.setQuantity(BigDecimal.ONE);req.setLocationId(2L);req.setAreaId(3L);
|
}
|
@Test void canceledBagDoesNotCreateStock(){
|
when(bags.selectByScanCodeForUpdate("123")).thenReturn(new MesProBagCodeDO().setStatus(30));
|
assertFailed("MES_SCAN_BAG_CANCELED");
|
}
|
@Test void canceledPalletDoesNotCreateStock(){
|
req.setScanType("PALLET");
|
when(pallets.selectByScanCodeForUpdate("123")).thenReturn(new MesProPalletDO().setStatus(20));
|
assertFailed("MES_SCAN_PALLET_CANCELED");
|
}
|
@Test void canceledBatchDoesNotCreateStock(){
|
req.setScanType("BATCH");
|
when(batches.selectByScanCodeForUpdate("123")).thenReturn(new MesProBatchDO().setId(2L).setStatus(40).setBagQuantity(1));
|
assertFailed("MES_SCAN_BATCH_CANCELED");
|
}
|
@Test void bagInCanceledBatchDoesNotCreateStock(){
|
when(bags.selectByScanCodeForUpdate("123")).thenReturn(new MesProBagCodeDO().setId(1L).setBatchId(2L).setStatus(20));
|
when(batches.selectByIdForUpdate(2L)).thenReturn(new MesProBatchDO().setId(2L).setStatus(40));
|
assertFailed("MES_SCAN_BATCH_CANCELED");
|
}
|
@Test void invalidTypeCannotFallThroughToBagInbound(){
|
req.setScanType("UNKNOWN");
|
assertThrows(ServiceException.class,()->service.createInbound(req));
|
verifyNoInteractions(events,bags,pallets,batches,transactions);
|
}
|
@Test void businessScanWritesCanonicalTraceCodeAndSameBagId(){
|
req.setBagCode("8888888888888888");
|
when(bags.selectByScanCodeForUpdate(req.getBagCode())).thenReturn(new MesProBagCodeDO()
|
.setId(1L).setCode("9999999999999999").setBusinessCode(req.getBagCode()).setBatchId(2L).setStatus(20));
|
when(batches.selectByIdForUpdate(2L)).thenReturn(new MesProBatchDO().setId(2L).setStatus(20).setCode("BATCH").setItemId(3L));
|
var warehouse=mock(cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService.class);
|
var wmBatch=mock(cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService.class);
|
ReflectionTestUtils.setField(service,"warehouseService",warehouse);
|
ReflectionTestUtils.setField(service,"mesWmBatchService",wmBatch);
|
when(warehouse.getWarehouseByCode(anyString())).thenReturn(new cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO().setId(4L));
|
when(wmBatch.getOrCreateByProBatch(any())).thenReturn(new cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO().setId(5L));
|
var result=service.createInbound(req);
|
assertEquals("SUCCESS",result.getStatus());
|
var tx=org.mockito.ArgumentCaptor.forClass(cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO.class);
|
verify(transactions).createTransaction(tx.capture());
|
assertEquals(1L,tx.getValue().getBagCodeId());
|
assertEquals("9999999999999999",tx.getValue().getBagCode());
|
assertEquals("8888888888888888",result.getBagCode());
|
}
|
@Test void palletBusinessScanUsesActualBagCountAndOriginalBatch(){
|
req.setScanType("PALLET");req.setBagCode("7777777777777777");
|
when(pallets.selectByScanCodeForUpdate(req.getBagCode())).thenReturn(new MesProPalletDO().setId(7L).setBatchId(2L).setStatus(0).setBagCount(25));
|
when(bags.selectPendingInboundCountByPalletId(7L)).thenReturn(25);
|
when(batches.selectByIdForUpdate(2L)).thenReturn(new MesProBatchDO().setId(2L).setStatus(20).setCode("BATCH").setItemId(3L));
|
assertWholeInbound(7L,25);
|
verify(pallets).markInbound(eq(7L),any());
|
}
|
@Test void batchBusinessScanUsesActualBagCountAndOriginalBatch(){
|
req.setScanType("BATCH");req.setBagCode("6666666666666666");
|
when(batches.selectByScanCodeForUpdate(req.getBagCode())).thenReturn(new MesProBatchDO().setId(2L).setStatus(20).setCode("BATCH").setItemId(3L).setBagQuantity(50));
|
when(bags.selectPendingInboundCountByBatchId(2L)).thenReturn(50);
|
assertWholeInbound(2L,50);
|
verify(batches).refreshInboundProgress(eq(2L),any(),any(),any());
|
}
|
@Test void partlyInboundPalletWritesOnlyPendingBags(){
|
req.setScanType("PALLET");
|
when(pallets.selectByScanCodeForUpdate("123")).thenReturn(new MesProPalletDO().setId(7L).setBatchId(2L).setStatus(10).setBagCount(25));
|
when(batches.selectByIdForUpdate(2L)).thenReturn(new MesProBatchDO().setId(2L).setStatus(20).setCode("BATCH").setItemId(3L));
|
when(bags.selectPendingInboundCountByPalletId(7L)).thenReturn(24);
|
assertWholeInbound(7L,24);
|
}
|
@Test void partlyInboundBatchIsNotRejectedByEarlierBagEvent(){
|
req.setScanType("BATCH");
|
when(batches.selectByScanCodeForUpdate("123")).thenReturn(new MesProBatchDO().setId(2L).setStatus(20).setInboundEventId(9L).setCode("BATCH").setItemId(3L).setBagQuantity(25));
|
when(bags.selectPendingInboundCountByBatchId(2L)).thenReturn(24);
|
assertWholeInbound(2L,24);
|
}
|
@Test void fullyInboundBatchDoesNotCreateAnotherStockTransaction(){
|
req.setScanType("BATCH");
|
when(batches.selectByScanCodeForUpdate("123")).thenReturn(new MesProBatchDO().setId(2L).setStatus(30).setCode("BATCH"));
|
assertFailed("MES_SCAN_NO_PENDING_BAGS");
|
}
|
private void assertWholeInbound(Long targetId,int quantity){
|
var warehouse=mock(cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService.class);
|
var wmBatch=mock(cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService.class);
|
ReflectionTestUtils.setField(service,"warehouseService",warehouse);
|
ReflectionTestUtils.setField(service,"mesWmBatchService",wmBatch);
|
when(warehouse.getWarehouseByCode(anyString())).thenReturn(new cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO().setId(4L));
|
when(wmBatch.getOrCreateByProBatch(any())).thenReturn(new cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO().setId(5L));
|
var result=service.createInbound(req);assertEquals("SUCCESS",result.getStatus());
|
assertEquals(req.getBagCode(),result.getBagCode());assertEquals(BigDecimal.valueOf(quantity),result.getQuantity());
|
var tx=org.mockito.ArgumentCaptor.forClass(cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO.class);
|
verify(transactions).createTransaction(tx.capture());assertEquals(targetId,tx.getValue().getBizLineId());
|
assertEquals("BATCH",tx.getValue().getBatchCode());assertEquals(BigDecimal.valueOf(quantity),tx.getValue().getQuantity());
|
}
|
private void assertFailed(String code){
|
MesProScanEventDO result=service.createInbound(req);
|
assertEquals("FAILED",result.getStatus());assertEquals(code,result.getErrorCode());
|
verify(events).insert(result);verify(events).updateById(result);verifyNoInteractions(transactions);
|
}
|
}
|