云
2 天以前 ac2e2b5af3726ee64dc37c3ebf26989a0346f22a
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java
@@ -3,17 +3,25 @@
import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductProduceStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import cn.iocoder.yudao.module.mes.service.wm.productreceipt.MesWmProductReceiptService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
@@ -51,7 +59,19 @@
    @MockitoBean
    private MesWmProductProduceDetailService productProduceDetailService;
    @MockitoBean
    private MesWmProductProduceLineMapper produceLineMapper;
    @MockitoBean
    private MesProWorkOrderService workOrderService;
    @MockitoBean
    private MesProWorkOrderProcessService workOrderProcessService;
    @MockitoBean
    private MesProRouteProductService routeProductService;
    @MockitoBean
    private MesProRouteProcessService routeProcessService;
    @MockitoBean
    private MesWmProductReceiptService productReceiptService;
    @MockitoBean
    private MesMdItemService itemService;
    @MockitoBean
    private MesWmBatchService batchService;
    @MockitoBean
@@ -86,6 +106,11 @@
        when(warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE)).thenReturn(wh);
        when(locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION)).thenReturn(loc);
        when(areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA)).thenReturn(area);
        mockNotLastProcess();
        MesMdItemDO item = new MesMdItemDO();
        item.setId(itemId);
        item.setMdmItemId(itemId);
        when(itemService.validateItemExists(any())).thenReturn(item);
        // mock: 通过 sourceLineId 直接定位 PENDING 产出行
        MesWmProductProduceLineDO pendingLine = MesWmProductProduceLineDO.builder()
@@ -94,8 +119,7 @@
                .batchId(batchId).batchCode(batchCode)
                .qualityStatus(MesWmQualityStatusEnum.PENDING.getStatus())
                .build();
        when(productProduceLineService.validateProductProduceLineExists(sourceLineId))
                .thenReturn(pendingLine);
        when(produceLineMapper.selectByIdForUpdate(sourceLineId)).thenReturn(pendingLine);
        // mock: finishProductProduce 内部查行和明细(用于创建库存事务)
        MesWmProductProduceLineDO qualifiedLine = MesWmProductProduceLineDO.builder()
@@ -113,9 +137,9 @@
        // mock: finishProductProduce 中按行查明细
        MesWmProductProduceDetailDO qualifiedDetail = MesWmProductProduceDetailDO.builder()
                .lineId(100L).quantity(BigDecimal.valueOf(80)).build();
                .lineId(100L).quantity(BigDecimal.valueOf(80)).warehouseId(whId).build();
        MesWmProductProduceDetailDO unqualifiedDetail = MesWmProductProduceDetailDO.builder()
                .lineId(101L).quantity(BigDecimal.valueOf(20)).build();
                .lineId(101L).quantity(BigDecimal.valueOf(20)).warehouseId(whId).build();
        when(productProduceDetailService.getProductProduceDetailListByLineId(100L))
                .thenReturn(ListUtil.of(qualifiedDetail));
        when(productProduceDetailService.getProductProduceDetailListByLineId(101L))
@@ -147,8 +171,8 @@
        MesWmProductProduceDO updatedProduce = productProduceMapper.selectById(produce.getId());
        assertEquals(MesWmProductProduceStatusEnum.FINISHED.getStatus(), updatedProduce.getStatus());
        // 断言 5:创建了库存事务
        verify(wmTransactionService, times(2)).createTransaction(any());
        // 断言 5:只为合格品行创建库存事务(不合格品不计入可用库存)
        verify(wmTransactionService, times(1)).createTransaction(any());
    }
    @Test
@@ -172,6 +196,7 @@
        when(warehouseService.getWarehouseByCode(any())).thenReturn(wh);
        when(locationService.getWarehouseLocationByCode(any())).thenReturn(loc);
        when(areaService.getWarehouseAreaByCode(any())).thenReturn(area);
        mockNotLastProcess();
        // mock: 通过 sourceLineId 直接定位 PENDING 产出行
        MesWmProductProduceLineDO pendingLine = MesWmProductProduceLineDO.builder()
@@ -179,8 +204,7 @@
                .itemId(itemId).quantity(BigDecimal.valueOf(50))
                .qualityStatus(MesWmQualityStatusEnum.PENDING.getStatus())
                .build();
        when(productProduceLineService.validateProductProduceLineExists(sourceLineId))
                .thenReturn(pendingLine);
        when(produceLineMapper.selectByIdForUpdate(sourceLineId)).thenReturn(pendingLine);
        // mock: finishProductProduce 查行和明细
        MesWmProductProduceLineDO qualifiedLine = MesWmProductProduceLineDO.builder()
@@ -245,9 +269,8 @@
        when(locationService.getWarehouseLocationByCode(any())).thenReturn(loc);
        when(areaService.getWarehouseAreaByCode(any())).thenReturn(area);
        // mock: validateProductProduceLineExists 抛异常
        when(productProduceLineService.validateProductProduceLineExists(sourceLineId))
                .thenThrow(new ServiceException(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS));
        // mock: 产出行不存在
        when(produceLineMapper.selectByIdForUpdate(sourceLineId)).thenReturn(null);
        // 调用,应该抛异常
        ServiceException ex = assertThrows(ServiceException.class, () ->
@@ -256,4 +279,11 @@
        assertEquals(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS.getCode(), ex.getCode());
    }
    /** 末道工序返回非当前工序,避免测试走到确切末道工序的仓库校验分支 */
    private void mockNotLastProcess() {
        MesProWorkOrderProcessDO lastProcess = new MesProWorkOrderProcessDO();
        lastProcess.setProcessId(-1L);
        when(workOrderProcessService.getLastWorkOrderProcessByWorkOrderId(any())).thenReturn(lastProcess);
    }
}