Commit 5a16d8337575a8de9d9396b06ff369f713e131d1

Authored by YunaiV
1 parent 2f4dfb69

✨ feat(mes): 添加库存混放规则校验及相关错误码

新增库存混放规则校验功能,确保在指定库位存放物料和批次时遵循配置的混放规则。同时,添加了多个相关的错误码以支持业务逻辑的处理。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -356,6 +356,13 @@ public interface ErrorCodeConstants {
356 356 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在");
357 357 ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足");
358 358 ErrorCode WM_TRANSACTION_TYPE_NOT_EXISTS = new ErrorCode(1_040_703_002, "库存事务类型不存在");
  359 + ErrorCode WM_TRANSACTION_WAREHOUSE_FROZEN = new ErrorCode(1_040_703_003, "仓库({})已被冻结");
  360 + ErrorCode WM_TRANSACTION_LOCATION_FROZEN = new ErrorCode(1_040_703_004, "库区({})已被冻结");
  361 + ErrorCode WM_TRANSACTION_AREA_FROZEN = new ErrorCode(1_040_703_005, "库位({})已被冻结");
  362 + ErrorCode WM_TRANSACTION_STOCK_FROZEN = new ErrorCode(1_040_703_006, "存放于({}/{}/{})下的物料已被冻结");
  363 + ErrorCode WM_TRANSACTION_BATCH_REQUIRED = new ErrorCode(1_040_703_007, "当前物料启用了批次管理,批次号不能为空");
  364 + ErrorCode WM_MATERIAL_STOCK_AREA_ITEM_MIXING_NOT_ALLOWED = new ErrorCode(1_040_703_008, "库位({})不允许物料混放,请选择其他库位");
  365 + ErrorCode WM_MATERIAL_STOCK_AREA_BATCH_MIXING_NOT_ALLOWED = new ErrorCode(1_040_703_009, "库位({})不允许批次混放,请选择其他库位");
359 366  
360 367 // ========== MES 仓库管理-到货通知单(1-040-704-000) ==========
361 368 ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
... ... @@ -29,6 +29,27 @@ public interface MesWmMaterialStockService {
29 29 MesWmMaterialStockDO getMaterialStock(Long id);
30 30  
31 31 /**
  32 + * 按组合键查询库存记录
  33 + *
  34 + * @param itemId 物料编号
  35 + * @param warehouseId 仓库编号
  36 + * @param locationId 库区编号
  37 + * @param areaId 库位编号
  38 + * @param batchId 批次编号
  39 + * @return 库存记录,不存在返回 null
  40 + */
  41 + MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId,
  42 + Long areaId, Long batchId);
  43 +
  44 + /**
  45 + * 查询指定库位的库存记录列表
  46 + *
  47 + * @param areaId 库位编号
  48 + * @return 库存记录列表
  49 + */
  50 + List<MesWmMaterialStockDO> getMaterialStockListByAreaId(Long areaId);
  51 +
  52 + /**
32 53 * 获得库存台账分页
33 54 *
34 55 * @param pageReqVO 分页参数
... ... @@ -97,10 +118,10 @@ public interface MesWmMaterialStockService {
97 118 * @param batchId 批次编号
98 119 * @param vendorId 供应商编号
99 120 * @param receiptTime 入库时间(为空则默认当前时间)
100   - * @return 库存记录编号
  121 + * @return 库存记录
101 122 */
102   - Long getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
103   - Long batchId, Long vendorId, LocalDateTime receiptTime);
  123 + MesWmMaterialStockDO getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
  124 + Long batchId, Long vendorId, LocalDateTime receiptTime);
104 125  
105 126 /**
106 127 * 更新库存数量
... ... @@ -111,4 +132,15 @@ public interface MesWmMaterialStockService {
111 132 */
112 133 void updateMaterialStockQuantity(Long materialStockId, BigDecimal quantity, boolean checkFlag);
113 134  
  135 + /**
  136 + * 库位混放规则校验
  137 + *
  138 + * 根据库位配置的物料和批次混放规则,检查是否允许在该库位存放指定物料/批次
  139 + *
  140 + * @param areaId 库位编号
  141 + * @param itemId 物料编号
  142 + * @param batchId 批次编号(可为 null)
  143 + */
  144 + void checkAreaMixingRule(Long areaId, Long itemId, Long batchId);
  145 +
114 146 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.materialstock;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjUtil;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
... ... @@ -9,9 +10,11 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMat
9 10 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
10 11 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
11 12 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
12 14 import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
13 15 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
14 16 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService;
  17 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
15 18 import jakarta.annotation.Resource;
16 19 import org.springframework.stereotype.Service;
17 20 import org.springframework.validation.annotation.Validated;
... ... @@ -22,8 +25,7 @@ import java.util.*;
22 25  
23 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
25   -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_INSUFFICIENT;
26   -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_NOT_EXISTS;
  28 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
27 29  
28 30 /**
29 31 * MES 库存台账 Service 实现类
... ... @@ -37,15 +39,27 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
37 39  
38 40 @Resource
39 41 private MesMdItemService itemService;
40   -
41 42 @Resource
42 43 private MesMdItemTypeService itemTypeService;
  44 + @Resource
  45 + private MesWmWarehouseAreaService areaService;
43 46  
44 47 @Override
45 48 public MesWmMaterialStockDO getMaterialStock(Long id) {
46 49 return materialStockMapper.selectById(id);
47 50 }
48 51  
  52 + @Override
  53 + public MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId,
  54 + Long areaId, Long batchId) {
  55 + return materialStockMapper.selectByCompositeKey(itemId, warehouseId, locationId, areaId, batchId);
  56 + }
  57 +
  58 + @Override
  59 + public List<MesWmMaterialStockDO> getMaterialStockListByAreaId(Long areaId) {
  60 + return materialStockMapper.selectList(MesWmMaterialStockDO::getAreaId, areaId);
  61 + }
  62 +
49 63 public MesWmMaterialStockDO validateMaterialStockExists(Long id) {
50 64 MesWmMaterialStockDO stock = materialStockMapper.selectById(id);
51 65 if (stock == null) {
... ... @@ -113,13 +127,13 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
113 127 }
114 128  
115 129 @Override
116   - public Long getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
117   - Long batchId, Long vendorId, LocalDateTime receiptTime) {
  130 + public MesWmMaterialStockDO getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
  131 + Long batchId, Long vendorId, LocalDateTime receiptTime) {
118 132 // 1. 查找已有库存记录
119 133 MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey(
120 134 itemId, warehouseId, locationId, areaId, batchId);
121 135 if (stock != null) {
122   - return stock.getId();
  136 + return stock;
123 137 }
124 138  
125 139 // 2. 不存在则新建
... ... @@ -133,7 +147,7 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
133 147 .frozenFlag(false)
134 148 .build();
135 149 materialStockMapper.insert(newStock);
136   - return newStock.getId();
  150 + return newStock;
137 151 }
138 152  
139 153 @Override
... ... @@ -145,4 +159,28 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
145 159 }
146 160 }
147 161  
  162 + @Override
  163 + public void checkAreaMixingRule(Long areaId, Long itemId, Long batchId) {
  164 + // 1.1 校验库位必须存在
  165 + MesWmWarehouseAreaDO area = areaService.validateWarehouseAreaExists(areaId);
  166 +
  167 + // 2. 查询当前库位上已有的库存记录
  168 + List<MesWmMaterialStockDO> stockList = getMaterialStockListByAreaId(areaId);
  169 + if (CollUtil.isEmpty(stockList)) {
  170 + return;
  171 + }
  172 + // 2.1 检查物料混放
  173 + if (Boolean.FALSE.equals(area.getAllowItemMixing()) && itemId != null) {
  174 + if (CollUtil.anyMatch(stockList, item -> ObjUtil.notEqual(itemId, item.getItemId()))) {
  175 + throw exception(WM_MATERIAL_STOCK_AREA_ITEM_MIXING_NOT_ALLOWED, area.getName());
  176 + }
  177 + }
  178 + // 2.2 检查批次混放
  179 + if (Boolean.FALSE.equals(area.getAllowBatchMixing()) && batchId != null) {
  180 + if (CollUtil.anyMatch(stockList, item -> ObjUtil.notEqual(batchId, item.getBatchId()))) {
  181 + throw exception(WM_MATERIAL_STOCK_AREA_BATCH_MIXING_NOT_ALLOWED, area.getName());
  182 + }
  183 + }
  184 + }
  185 +
148 186 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
... ... @@ -3,13 +3,22 @@ package cn.iocoder.yudao.module.mes.service.wm.transaction;
3 3 import cn.hutool.core.lang.Assert;
4 4 import cn.hutool.core.util.ObjUtil;
5 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
6 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
7 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
8 13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper;
9 14 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
10 16 import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
11 17 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
12 18 import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
  19 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
  21 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
13 22 import jakarta.annotation.Resource;
14 23 import org.springframework.stereotype.Service;
15 24 import org.springframework.transaction.annotation.Transactional;
... ... @@ -19,6 +28,9 @@ import java.math.BigDecimal;
19 28 import java.time.LocalDateTime;
20 29 import java.util.List;
21 30  
  31 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  32 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  33 +
22 34 /**
23 35 * MES 库存事务流水 Service 实现类
24 36 */
... ... @@ -28,11 +40,18 @@ public class MesWmTransactionServiceImpl implements MesWmTransactionService {
28 40  
29 41 @Resource
30 42 private MesWmTransactionMapper transactionMapper;
31   -
32 43 @Resource
33 44 private MesWmMaterialStockService materialStockService;
34 45 @Resource
35 46 private MesWmBatchService batchService;
  47 + @Resource
  48 + private MesMdItemService itemService;
  49 + @Resource
  50 + private MesWmWarehouseService warehouseService;
  51 + @Resource
  52 + private MesWmWarehouseLocationService locationService;
  53 + @Resource
  54 + private MesWmWarehouseAreaService areaService;
36 55  
37 56 @Override
38 57 @Transactional(rollbackFor = Exception.class)
... ... @@ -42,23 +61,23 @@ public class MesWmTransactionServiceImpl implements MesWmTransactionService {
42 61 Assert.notNull(typeEnum, "事务类型({}) 不存在", reqDTO.getType());
43 62 // 1.2 校验 quantity 正负号与事务方向一致(入库必须正数,出库必须负数)
44 63 boolean inbound = typeEnum.isInbound();
  64 + checkQuantity(reqDTO, inbound);
  65 + // 1.3 入库事务:批次号校验 + batchId/batchCode 互补
  66 + checkBatch(reqDTO, inbound);
  67 + // 1.4 入库事务:库位混放规则校验
45 68 if (inbound) {
46   - Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) > 0,
47   - "入库事务数量必须为正数,实际值: {}", reqDTO.getQuantity());
48   - } else {
49   - Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) < 0,
50   - "出库事务数量必须为负数,实际值: {}", reqDTO.getQuantity());
  69 + materialStockService.checkAreaMixingRule(reqDTO.getAreaId(), reqDTO.getItemId(), reqDTO.getBatchId());
51 70 }
52   - // 1.3 batchId / batchCode 互补
53   - completeBatchInfo(reqDTO);
54 71  
55 72 // 2.1 获取或创建库存记录
56   - Long materialStockId = materialStockService.getOrCreateMaterialStock(
  73 + MesWmMaterialStockDO materialStock = materialStockService.getOrCreateMaterialStock(
57 74 reqDTO.getItemId(), reqDTO.getWarehouseId(), reqDTO.getLocationId(), reqDTO.getAreaId(),
58 75 reqDTO.getBatchId(), reqDTO.getVendorId(), reqDTO.getReceiptTime());
59   - // 2.2 更新库存数量
  76 + // 2.2 冻结校验(仓库、库区、库位、库存记录)
  77 + checkFrozen(reqDTO, materialStock);
  78 + // 2.3 更新库存数量
60 79 boolean checkFlag = ObjUtil.defaultIfNull(reqDTO.getCheckFlag(), true);
61   - materialStockService.updateMaterialStockQuantity(materialStockId, reqDTO.getQuantity(), checkFlag);
  80 + materialStockService.updateMaterialStockQuantity(materialStock.getId(), reqDTO.getQuantity(), checkFlag);
62 81  
63 82 // 3. 插入事务流水
64 83 MesWmTransactionDO transaction = MesWmTransactionDO.builder()
... ... @@ -66,7 +85,7 @@ public class MesWmTransactionServiceImpl implements MesWmTransactionService {
66 85 .itemId(reqDTO.getItemId()).batchId(reqDTO.getBatchId()).batchCode(reqDTO.getBatchCode())
67 86 .warehouseId(reqDTO.getWarehouseId()).locationId(reqDTO.getLocationId()).areaId(reqDTO.getAreaId())
68 87 .bizType(reqDTO.getBizType()).bizId(reqDTO.getBizId()).bizCode(reqDTO.getBizCode()).bizLineId(reqDTO.getBizLineId())
69   - .materialStockId(materialStockId).relatedTransactionId(reqDTO.getRelatedTransactionId())
  88 + .materialStockId(materialStock.getId()).relatedTransactionId(reqDTO.getRelatedTransactionId())
70 89 .build();
71 90 transactionMapper.insert(transaction);
72 91 return transaction.getId();
... ... @@ -78,30 +97,79 @@ public class MesWmTransactionServiceImpl implements MesWmTransactionService {
78 97 reqDTOs.forEach(this::createTransaction);
79 98 }
80 99  
  100 + // ==================== 私有校验方法 ====================
  101 +
81 102 /**
82   - * batchId / batchCode 互补:有 batchId 无 batchCode 时,查出 batchCode;反之亦然。
83   - *
84   - * @param reqDTO 事务请求 DTO
  103 + * 校验数量正负号与事务方向一致
85 104 */
86   - private void completeBatchInfo(MesWmTransactionSaveReqDTO reqDTO) {
87   - if (reqDTO.getBatchId() != null && StrUtil.isNotEmpty(reqDTO.getBatchCode())) {
88   - return;
  105 + private void checkQuantity(MesWmTransactionSaveReqDTO reqDTO, boolean inbound) {
  106 + if (inbound) {
  107 + Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) > 0,
  108 + "入库事务数量必须为正数,实际值: {}", reqDTO.getQuantity());
  109 + } else {
  110 + Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) < 0,
  111 + "出库事务数量必须为负数,实际值: {}", reqDTO.getQuantity());
89 112 }
90   - // 情况一:有 batchId,补 batchCode
91   - if (reqDTO.getBatchId() != null) {
  113 + }
  114 +
  115 + /**
  116 + * 批次校验:batchId/batchCode 互补 + 入库时批次号必填检查
  117 + *
  118 + * @param reqDTO 事务请求 DTO
  119 + * @param inbound 是否入库
  120 + */
  121 + private void checkBatch(MesWmTransactionSaveReqDTO reqDTO, boolean inbound) {
  122 + // 1. batchId / batchCode 互补
  123 + if (reqDTO.getBatchId() != null && StrUtil.isEmpty(reqDTO.getBatchCode())) {
92 124 MesWmBatchDO batch = batchService.getBatch(reqDTO.getBatchId());
93 125 if (batch != null) {
94 126 reqDTO.setBatchCode(batch.getCode());
95 127 }
96   - return;
97   - }
98   - // 情况二:有 batchCode,补 batchId
99   - if (StrUtil.isNotEmpty(reqDTO.getBatchCode())) {
  128 + } else if (StrUtil.isNotEmpty(reqDTO.getBatchCode()) && reqDTO.getBatchId() == null) {
100 129 MesWmBatchDO batch = batchService.getBatchByCode(reqDTO.getBatchCode());
101 130 if (batch != null) {
102 131 reqDTO.setBatchId(batch.getId());
103 132 }
104 133 }
  134 + // 2. 入库时:启用批次管理的物料,必须传递批次号
  135 + if (inbound) {
  136 + MesMdItemDO item = itemService.getItem(reqDTO.getItemId());
  137 + if (item != null && Boolean.TRUE.equals(item.getBatchFlag())) {
  138 + if (StrUtil.isEmpty(reqDTO.getBatchCode()) && reqDTO.getBatchId() == null) {
  139 + throw exception(WM_TRANSACTION_BATCH_REQUIRED);
  140 + }
  141 + }
  142 + }
  143 + }
  144 +
  145 + /**
  146 + * 冻结校验:检查仓库、库区、库位、库存记录是否被冻结
  147 + *
  148 + * @param reqDTO 事务请求 DTO
  149 + * @param materialStock 库存记录
  150 + */
  151 + private void checkFrozen(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO materialStock) {
  152 + // 1.1 检查仓库冻结
  153 + MesWmWarehouseDO warehouse = warehouseService.validateWarehouseExists(reqDTO.getWarehouseId());
  154 + if (Boolean.TRUE.equals(warehouse.getFrozen())) {
  155 + throw exception(WM_TRANSACTION_WAREHOUSE_FROZEN, warehouse.getName());
  156 + }
  157 + // 1.2 检查库区冻结
  158 + MesWmWarehouseLocationDO location = locationService.validateWarehouseLocationExists(reqDTO.getLocationId());
  159 + if (Boolean.TRUE.equals(location.getFrozen())) {
  160 + throw exception(WM_TRANSACTION_LOCATION_FROZEN, location.getName());
  161 + }
  162 + // 1.3 检查库位冻结
  163 + MesWmWarehouseAreaDO area = areaService.validateWarehouseAreaExists(reqDTO.getAreaId());
  164 + if (Boolean.TRUE.equals(area.getFrozen())) {
  165 + throw exception(WM_TRANSACTION_AREA_FROZEN, area.getName());
  166 + }
  167 +
  168 + // 2. 检查库存记录冻结
  169 + if (Boolean.TRUE.equals(materialStock.getFrozenFlag())) {
  170 + throw exception(WM_TRANSACTION_STOCK_FROZEN,
  171 + warehouse.getName(), location.getName(), area.getName());
  172 + }
105 173 }
106 174  
107 175 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
... ... @@ -85,6 +85,7 @@ public class MesWmTransactionSaveReqDTO {
85 85 /**
86 86 * 库位 ID
87 87 */
  88 + @NotNull(message = "库位 ID 不能为空")
88 89 private Long areaId;
89 90  
90 91 // ===== 台账补充字段(入库时用于初始化 MesWmMaterialStockDO) =====
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java
... ... @@ -39,6 +39,7 @@ public class MesWmWarehouseAreaServiceImpl implements MesWmWarehouseAreaService
39 39 @Lazy
40 40 private MesMdWorkstationService workstationService;
41 41 @Resource
  42 + @Lazy
42 43 private MesWmMaterialStockService materialStockService;
43 44 @Resource
44 45 @Lazy
... ...