2 天以前 3be684af887afe4c0e45f281cc53adfef6f12b78
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package cn.iocoder.yudao.module.mes.service.md.item;
 
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductBomMapper;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.util.*;
 
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap2;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/**
 * MES 产品BOM Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class MesMdProductBomServiceImpl implements MesMdProductBomService {
 
    @Resource
    private MesMdProductBomMapper productBomMapper;
 
    @Resource
    @Lazy // 避免循环依赖
    private MesMdItemService itemService;
 
    @Override
    public Long createProductBom(MesMdProductBomSaveReqVO createReqVO) {
        // 1.1 校验数据
        validateProductBomSaveData(createReqVO);
        // 1.2 校验不能形成闭环
        if (hasBomCycle(createReqVO.getItemId(), createReqVO.getBomItemId())) {
            throw exception(MD_PRODUCT_BOM_CIRCULAR);
        }
 
        // 2. 插入
        MesMdProductBomDO productBom = BeanUtils.toBean(createReqVO, MesMdProductBomDO.class);
        productBomMapper.insert(productBom);
        return productBom.getId();
    }
 
    @Override
    public void updateProductBom(MesMdProductBomSaveReqVO updateReqVO) {
        // 1.1 校验存在
        validateProductBomExists(updateReqVO.getId());
        // 1.2 校验数据
        validateProductBomSaveData(updateReqVO);
 
        // 更新
        MesMdProductBomDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductBomDO.class);
        productBomMapper.updateById(updateObj);
    }
 
    private void validateProductBomSaveData(MesMdProductBomSaveReqVO reqVO) {
        // 校验物料产品存在
        validateItemExists(reqVO.getItemId());
        // 校验BOM物料存在
        validateItemExists(reqVO.getBomItemId());
        // 校验不能自引用
        if (reqVO.getItemId().equals(reqVO.getBomItemId())) {
            throw exception(MD_PRODUCT_BOM_SELF_REFERENCE);
        }
    }
 
    @Override
    public void deleteProductBom(Long id) {
        // 校验存在
        validateProductBomExists(id);
        // 删除
        productBomMapper.deleteById(id);
    }
 
    private void validateProductBomExists(Long id) {
        if (productBomMapper.selectById(id) == null) {
            throw exception(MD_PRODUCT_BOM_NOT_EXISTS);
        }
    }
 
    private void validateItemExists(Long itemId) {
        if (itemService.getItem(itemId) == null) {
            throw exception(MD_ITEM_NOT_EXISTS);
        }
    }
 
    /**
     * 检测新增边 (itemId -> bomItemId) 后,BOM 图是否存在闭环
     *
     * @param itemId 父物料编号
     * @param bomItemId BOM子物料编号
     * @return 是否存在闭环
     */
    private boolean hasBomCycle(Long itemId, Long bomItemId) {
        // 1.1 获取所有已有的 BOM 记录
        List<MesMdProductBomDO> allBoms = productBomMapper.selectAll();
        // 1.2 构建邻接表:parent -> Set<child>
        Map<Long, Set<Long>> graph = convertMultiMap2(allBoms,
                MesMdProductBomDO::getItemId, MesMdProductBomDO::getBomItemId);
        // 1.3  添加待新增的边
        graph.computeIfAbsent(itemId, k -> new HashSet<>()).add(bomItemId);
        // 2. DFS 检测环
        for (Long node : graph.keySet()) {
            if (CollectionUtils.dfs(node, graph)) {
                return true;
            }
        }
        return false;
    }
 
    @Override
    public MesMdProductBomDO getProductBom(Long id) {
        return productBomMapper.selectById(id);
    }
 
    @Override
    public PageResult<MesMdProductBomDO> getProductBomPage(MesMdProductBomPageReqVO pageReqVO) {
        return productBomMapper.selectPage(pageReqVO);
    }
 
    @Override
    public List<MesMdProductBomDO> getProductBomListByItemId(Long itemId) {
        return productBomMapper.selectByItemId(itemId);
    }
 
    @Override
    public List<MesMdProductBomDO> getProductBomListByItemIds(Collection<Long> itemIds) {
        return productBomMapper.selectByItemIds(itemIds);
    }
 
    @Override
    public void deleteProductBomByItemId(Long itemId) {
        productBomMapper.deleteByItemId(itemId);
    }
 
}