package cn.iocoder.yudao.module.mes.service.pro.bagcode;
|
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
|
import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.*;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
|
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.mysql.pro.bagcode.MesProBagCodeMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeReplaceMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
|
import cn.iocoder.yudao.module.mes.dal.redis.MesCodeRedisDAO;
|
import cn.iocoder.yudao.module.mes.framework.qrcode.MesProQrLabelBuilder;
|
import cn.iocoder.yudao.module.mes.framework.qrcode.QrCodeImageUtils;
|
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
|
import cn.hutool.extra.qrcode.QrCodeUtil;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.ArgumentCaptor;
|
import org.springframework.test.util.ReflectionTestUtils;
|
import java.util.Collection;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.concurrent.atomic.AtomicLong;
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
|
class BagBusinessCodeTest {
|
private final MesProBagCodeServiceImpl service = new MesProBagCodeServiceImpl();
|
private final MesProBagCodeMapper bags = mock(MesProBagCodeMapper.class);
|
private final MesCodeRedisDAO codes = mock(MesCodeRedisDAO.class);
|
private final MesMdmItemService items = mock(MesMdmItemService.class);
|
private final MesProBatchMapper batches = mock(MesProBatchMapper.class);
|
private final MesProBagCodeReplaceMapper replacements = mock(MesProBagCodeReplaceMapper.class);
|
private final MdmUnitMeasureApi units = mock(MdmUnitMeasureApi.class);
|
|
@BeforeEach void setup() {
|
ReflectionTestUtils.setField(service, "bagCodeMapper", bags);
|
ReflectionTestUtils.setField(service, "codeRedisDao", codes);
|
ReflectionTestUtils.setField(service, "mdmItemService", items);
|
ReflectionTestUtils.setField(service, "batchMapper", batches);
|
ReflectionTestUtils.setField(service, "replaceMapper", replacements);
|
ReflectionTestUtils.setField(service, "unitMeasureApi", units);
|
when(items.validateItemExists(1L)).thenReturn(new MesMdmItemDO().setId(1L).setUnitMeasureId(2L));
|
AtomicLong sequence = new AtomicLong(1000000000000000L);
|
when(codes.generate()).thenAnswer(invocation -> String.valueOf(sequence.incrementAndGet()));
|
when(codes.allocateBagNoStart(anyInt(), any())).thenReturn(1);
|
}
|
|
@Test void rawGenerationCreatesDistinctPairsInSameRecords() {
|
MesProBagCodeRawGenerateReqVO req = new MesProBagCodeRawGenerateReqVO();
|
req.setItemId(1L); req.setCount(2);
|
service.generateRawBagCodes(req);
|
assertDistinctPairs(2);
|
}
|
|
@Test void dataPackageGenerationCreatesBusinessCodes() {
|
when(units.getUnitMeasure(2L)).thenReturn(CommonResult.success(new MdmUnitMeasureRespDTO().setType("吨")));
|
MesProBagCodeGenerateReqVO req = new MesProBagCodeGenerateReqVO();
|
req.setItemId(1L); req.setBagCount(2);
|
service.generateBagCodes(req);
|
assertDistinctPairs(2);
|
}
|
|
@Test @SuppressWarnings({"unchecked", "rawtypes"}) void automaticPalletCarriesVariety() {
|
var pallets=mock(cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper.class);
|
ReflectionTestUtils.setField(service,"palletMapper",pallets);
|
when(units.getUnitMeasure(2L)).thenReturn(CommonResult.success(new MdmUnitMeasureRespDTO().setType("2千克")));
|
var req=new MesProBagCodeGenerateReqVO();req.setItemId(1L);req.setPalletCount(1);
|
service.generateBagCodes(req);
|
ArgumentCaptor<Collection<cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO>> saved=ArgumentCaptor.forClass((Class)Collection.class);
|
verify(pallets).insertBatch(saved.capture());assertEquals(1L,saved.getValue().iterator().next().getItemId());
|
}
|
|
@Test void replacementIssuesNewPairInsteadOfReusingOldBusinessCode() {
|
when(batches.selectByIdForUpdate(2L)).thenReturn(new MesProBatchDO().setId(2L).setStatus(20));
|
when(bags.selectListByIdsForUpdate(List.of(1L))).thenReturn(List.of(new MesProBagCodeDO()
|
.setId(1L).setBatchId(2L).setStatus(10).setCode("9999999999999999").setBusinessCode("8888888888888888")));
|
when(bags.cancelById(eq(1L), eq(10), eq(30), any(), any())).thenReturn(1);
|
MesProBagCodeReplaceReqVO req = new MesProBagCodeReplaceReqVO();
|
req.setBatchId(2L); req.setOldIds(List.of(1L)); req.setReason("破损");
|
service.replaceBagCodes(req);
|
assertDistinctPairs(1);
|
}
|
|
@Test void supplementationLocksAndNeverChangesExistingCode() {
|
when(bags.selectListByIdsForUpdate(List.of(1L, 2L))).thenReturn(List.of(
|
new MesProBagCodeDO().setId(1L).setStatus(10),
|
new MesProBagCodeDO().setId(2L).setStatus(20).setBusinessCode("8888888888888888")));
|
assertEquals(1, service.generateBusinessCodes(List.of(2L, 1L, 1L)));
|
ArgumentCaptor<MesProBagCodeDO> update = ArgumentCaptor.forClass(MesProBagCodeDO.class);
|
verify(bags).updateById(update.capture());
|
assertEquals(1L, update.getValue().getId());
|
assertNull(update.getValue().getCode());
|
assertNotNull(update.getValue().getBusinessCode());
|
when(bags.selectListByIdsForUpdate(List.of(1L))).thenReturn(List.of(update.getValue().setStatus(10)));
|
assertEquals(0, service.generateBusinessCodes(List.of(1L)));
|
verify(codes, times(1)).generate();
|
}
|
|
@Test void canceledOrMissingBagCannotBeSupplemented() {
|
when(bags.selectListByIdsForUpdate(List.of(1L))).thenReturn(List.of(new MesProBagCodeDO().setId(1L).setStatus(30)));
|
assertThrows(ServiceException.class, () -> service.generateBusinessCodes(List.of(1L)));
|
assertThrows(ServiceException.class, () -> service.generateBusinessCodes(List.of(2L)));
|
verifyNoInteractions(codes);
|
verify(bags, never()).updateById(any(MesProBagCodeDO.class));
|
}
|
|
@Test void publicLookupUsesTraceColumnAndInternalLookupUsesBoth() {
|
service.getBagCodeByCode("1111111111111111");
|
verify(bags).selectByCode("1111111111111111");
|
service.getBagCodeByScanCode("2222222222222222");
|
verify(bags).selectByScanCode("2222222222222222");
|
}
|
|
@Test void businessQrEncodesStoredValueAndRejectsMissingCode() {
|
var label = MesProQrLabelBuilder.buildBagBusinessCodeLabel(new MesProBagCodeDO()
|
.setCode("9999999999999999").setBusinessCode("8888888888888888"));
|
assertEquals("8888888888888888", QrCodeUtil.decode(QrCodeImageUtils.createQrLabel(label.getCode(), label.getFileName())));
|
assertThrows(ServiceException.class, () -> MesProQrLabelBuilder.buildBagBusinessCodeLabel(new MesProBagCodeDO()));
|
}
|
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
private void assertDistinctPairs(int count) {
|
ArgumentCaptor<Collection<MesProBagCodeDO>> saved = ArgumentCaptor.forClass((Class) Collection.class);
|
verify(bags).insertBatch(saved.capture());
|
assertEquals(count, saved.getValue().size());
|
var values = new HashSet<String>();
|
for (MesProBagCodeDO bag : saved.getValue()) {
|
assertTrue(bag.getBusinessCode().matches("[0-9]{16}"));
|
assertTrue(values.add(bag.getCode())); assertTrue(values.add(bag.getBusinessCode()));
|
}
|
}
|
}
|