云
2026-10-25 d54fbc9d4f8981fa0f7f613b33a28a8cd4f764ea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package cn.iocoder.yudao.module.mes.service.qc.support;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
 
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS;
 
/**
 * 质检单据物料 ID 解析器
 *
 * 质检单据的物料 ID 存在两套来源:质检/仓储单据使用 mdm_item.id,PRO 工单/任务使用 mes_md_item.id。
 * 统一在此解析:先按 mdm_item.id 查询,未命中的再按 mes_md_item.id → mdm_item.id 映射查询。
 */
@Service
public class MesQcItemResolver {
 
    @Resource
    private MesMdItemService mesMdItemService;
    @Resource
    private MdmItemApi mdmItemApi;
 
    /**
     * 批量查询物料信息,返回以调用方传入的物料 ID 为 key 的结果
     */
    public Map<Long, MdmItemRespDTO> getItemMap(Collection<Long> itemIds) {
        if (CollUtil.isEmpty(itemIds)) {
            return Collections.emptyMap();
        }
        Set<Long> ids = new HashSet<>();
        itemIds.forEach(id -> {
            if (id != null) {
                ids.add(id);
            }
        });
        if (ids.isEmpty()) {
            return Collections.emptyMap();
        }
        // 1. 先按 mdm_item.id 直接查询(质检/仓储单据)
        Map<Long, MdmItemRespDTO> result = new HashMap<>(mdmItemApi.getItemMap(ids));
        // 2. 未命中的再按 mes_md_item.id → mdm_item.id 解析(PRO 工单/任务)
        Set<Long> missingIds = new HashSet<>(ids);
        missingIds.removeAll(result.keySet());
        if (missingIds.isEmpty()) {
            return result;
        }
        Map<Long, MesMdItemDO> mesItemMap = mesMdItemService.getItemMap(missingIds);
        Map<Long, Long> idToMdmId = new HashMap<>();
        missingIds.forEach(id -> {
            MesMdItemDO mesItem = mesItemMap.get(id);
            if (mesItem != null && mesItem.getMdmItemId() != null) {
                idToMdmId.put(id, mesItem.getMdmItemId());
            }
        });
        if (idToMdmId.isEmpty()) {
            return result;
        }
        Map<Long, MdmItemRespDTO> fallbackMap = mdmItemApi.getItemMap(idToMdmId.values());
        idToMdmId.forEach((id, mdmId) -> {
            MdmItemRespDTO item = fallbackMap.get(mdmId);
            if (item != null) {
                result.put(id, item);
            }
        });
        return result;
    }
 
    /**
     * 校验物料存在(兼容两套 ID)
     */
    public void validateItemExists(Long itemId) {
        if (itemId == null) {
            return;
        }
        if (!getItemMap(Collections.singleton(itemId)).containsKey(itemId)) {
            throw exception(MD_ITEM_NOT_EXISTS);
        }
    }
 
}