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 allBoms = productBomMapper.selectAll(); // 1.2 构建邻接表:parent -> Set Map> 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 getProductBomPage(MesMdProductBomPageReqVO pageReqVO) { return productBomMapper.selectPage(pageReqVO); } @Override public List getProductBomListByItemId(Long itemId) { return productBomMapper.selectByItemId(itemId); } @Override public List getProductBomListByItemIds(Collection itemIds) { return productBomMapper.selectByItemIds(itemIds); } @Override public void deleteProductBomByItemId(Long itemId) { productBomMapper.deleteByItemId(itemId); } }