package cn.iocoder.yudao.module.mes.service.md.item;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.mdm.api.category.MdmItemCategoryApi;
|
import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategoryRespDTO;
|
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.type.MesMdItemTypeImportExcelVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.type.MesMdItemTypeImportRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.type.MesMdItemTypeListReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.type.MesMdItemTypeSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemTypeMapper;
|
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.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 物料产品分类 Service 实现类
|
*
|
* 兼容层实现:数据存储在 mes_md_item_type 表,但优先从 MDM 分类 API 获取
|
* 实际分类数据已迁移到 mdm_item_category 表
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesMdItemTypeServiceImpl implements MesMdItemTypeService {
|
|
@Resource
|
private MdmItemCategoryApi mdmItemCategoryApi;
|
|
@Resource
|
private MesMdItemTypeMapper itemTypeMapper;
|
|
@Resource
|
@Lazy
|
private MesMdItemService itemService;
|
|
@Override
|
public Long createItemType(MesMdItemTypeSaveReqVO createReqVO) {
|
// 校验数据
|
validateItemTypeSaveData(createReqVO);
|
|
// 插入到本地表(保持兼容)
|
MesMdItemTypeDO itemType = BeanUtils.toBean(createReqVO, MesMdItemTypeDO.class);
|
itemTypeMapper.insert(itemType);
|
return itemType.getId();
|
}
|
|
@Override
|
public void updateItemType(MesMdItemTypeSaveReqVO updateReqVO) {
|
// 校验存在
|
validateItemTypeExists(updateReqVO.getId());
|
// 校验数据
|
validateItemTypeSaveData(updateReqVO);
|
|
// 更新本地表
|
MesMdItemTypeDO updateObj = BeanUtils.toBean(updateReqVO, MesMdItemTypeDO.class);
|
itemTypeMapper.updateById(updateObj);
|
}
|
|
private void validateItemTypeSaveData(MesMdItemTypeSaveReqVO reqVO) {
|
// 校验父分类编号的有效性
|
validateParentItemType(reqVO.getId(), reqVO.getParentId());
|
// 校验分类名称的唯一性
|
validateItemTypeNameUnique(reqVO.getId(), reqVO.getParentId(), reqVO.getName());
|
// 校验分类编码的唯一性
|
validateItemTypeCodeUnique(reqVO.getId(), reqVO.getParentId(), reqVO.getCode());
|
}
|
|
@Override
|
public void deleteItemType(Long id) {
|
// 1.1 校验存在
|
validateItemTypeExists(id);
|
// 1.2 校验是否有子分类
|
if (itemTypeMapper.selectCountByParentId(id) > 0) {
|
throw exception(MD_ITEM_TYPE_EXITS_CHILDREN);
|
}
|
// 1.3 校验是否有物料
|
if (itemService.getItemCountByItemTypeId(id) > 0) {
|
throw exception(MD_ITEM_TYPE_EXITS_ITEM);
|
}
|
|
// 2. 删除
|
itemTypeMapper.deleteById(id);
|
}
|
|
private void validateItemTypeExists(Long id) {
|
// 优先从 MDM 获取
|
CommonResult<MdmItemCategoryRespDTO> result = mdmItemCategoryApi.getItemCategory(id);
|
if (result.isSuccess() && result.getData() != null) {
|
return;
|
}
|
// 回退到本地表
|
if (itemTypeMapper.selectById(id) == null) {
|
throw exception(MD_ITEM_TYPE_NOT_EXISTS);
|
}
|
}
|
|
private void validateParentItemType(Long id, Long parentId) {
|
if (parentId == null || MesMdItemTypeDO.PARENT_ID_ROOT.equals(parentId)) {
|
return;
|
}
|
// 1. 不能设置自己为父分类
|
if (Objects.equals(id, parentId)) {
|
throw exception(MD_ITEM_TYPE_PARENT_ERROR);
|
}
|
// 2. 父分类不存在 - 优先从 MDM 获取
|
CommonResult<MdmItemCategoryRespDTO> result = mdmItemCategoryApi.getItemCategory(parentId);
|
MesMdItemTypeDO parentItemType = null;
|
if (result.isSuccess() && result.getData() != null) {
|
parentItemType = convertToMesDO(result.getData());
|
} else {
|
parentItemType = itemTypeMapper.selectById(parentId);
|
}
|
if (parentItemType == null) {
|
throw exception(MD_ITEM_TYPE_PARENT_NOT_EXITS);
|
}
|
// 3. 递归校验父分类,如果父分类是自己的子分类,则报错,避免形成环路
|
if (id == null) {
|
return;
|
}
|
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
parentId = parentItemType.getParentId();
|
if (Objects.equals(id, parentId)) {
|
throw exception(MD_ITEM_TYPE_PARENT_IS_CHILD);
|
}
|
if (parentId == null || MesMdItemTypeDO.PARENT_ID_ROOT.equals(parentId)) {
|
break;
|
}
|
// 继续查找父级
|
CommonResult<MdmItemCategoryRespDTO> parentResult = mdmItemCategoryApi.getItemCategory(parentId);
|
if (parentResult.isSuccess() && parentResult.getData() != null) {
|
parentItemType = convertToMesDO(parentResult.getData());
|
} else {
|
parentItemType = itemTypeMapper.selectById(parentId);
|
}
|
if (parentItemType == null) {
|
break;
|
}
|
}
|
}
|
|
private void validateItemTypeNameUnique(Long id, Long parentId, String name) {
|
MesMdItemTypeDO itemType = itemTypeMapper.selectByParentIdAndName(parentId, name);
|
if (itemType == null) {
|
return;
|
}
|
if (ObjUtil.notEqual(itemType.getId(), id)) {
|
throw exception(MD_ITEM_TYPE_NAME_DUPLICATE);
|
}
|
}
|
|
private void validateItemTypeCodeUnique(Long id, Long parentId, String code) {
|
MesMdItemTypeDO itemType = itemTypeMapper.selectByParentIdAndCode(parentId, code);
|
if (itemType == null) {
|
return;
|
}
|
if (ObjUtil.notEqual(itemType.getId(), id)) {
|
throw exception(MD_ITEM_TYPE_CODE_DUPLICATE);
|
}
|
}
|
|
@Override
|
public MesMdItemTypeDO getItemType(Long id) {
|
// 优先从 MDM 获取
|
CommonResult<MdmItemCategoryRespDTO> result = mdmItemCategoryApi.getItemCategory(id);
|
if (result.isSuccess() && result.getData() != null) {
|
return convertToMesDO(result.getData());
|
}
|
// 回退到本地表
|
return itemTypeMapper.selectById(id);
|
}
|
|
@Override
|
public MesMdItemTypeDO getItemTypeByCode(String code) {
|
// 从本地表查
|
return itemTypeMapper.selectByCode(code);
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeList(MesMdItemTypeListReqVO listReqVO) {
|
// 从本地表查
|
return itemTypeMapper.selectList(listReqVO);
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeList(Collection<Long> ids) {
|
if (CollUtil.isEmpty(ids)) {
|
return Collections.emptyList();
|
}
|
return itemTypeMapper.selectByIds(ids);
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeChildrenList(Long parentId) {
|
List<MesMdItemTypeDO> allList = itemTypeMapper.selectList();
|
List<MesMdItemTypeDO> result = new ArrayList<>();
|
collectItemTypeChildren(result, parentId, allList);
|
return result;
|
}
|
|
private void collectItemTypeChildren(List<MesMdItemTypeDO> result, Long parentId, List<MesMdItemTypeDO> allList) {
|
for (MesMdItemTypeDO itemType : allList) {
|
if (Objects.equals(itemType.getParentId(), parentId)) {
|
result.add(itemType);
|
collectItemTypeChildren(result, itemType.getId(), allList);
|
}
|
}
|
}
|
|
/**
|
* 转换 MDM 分类 DTO 为 MES DO
|
*/
|
private MesMdItemTypeDO convertToMesDO(MdmItemCategoryRespDTO dto) {
|
MesMdItemTypeDO mesDO = new MesMdItemTypeDO();
|
mesDO.setId(dto.getId());
|
mesDO.setCode(dto.getCode());
|
mesDO.setName(dto.getName());
|
mesDO.setParentId(dto.getParentId());
|
mesDO.setItemOrProduct(dto.getItemOrProduct());
|
mesDO.setSort(dto.getSort());
|
mesDO.setStatus(dto.getStatus());
|
return mesDO;
|
}
|
|
@Override
|
@org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
|
public MesMdItemTypeImportRespVO importItemTypeList(List<MesMdItemTypeImportExcelVO> importList, Boolean isUpdateSupport) {
|
if (CollUtil.isEmpty(importList)) {
|
throw exception(MD_ITEM_TYPE_IMPORT_LIST_IS_EMPTY);
|
}
|
MesMdItemTypeImportRespVO respVO = MesMdItemTypeImportRespVO.builder()
|
.createList(new ArrayList<>()).updateList(new ArrayList<>())
|
.failureList(new LinkedHashMap<>()).build();
|
|
// 1. 建立编码 -> ID 映射(现有分类 + 本次新建分类),用于解析"父分类编码"列
|
Map<String, Long> codeIdMap = new HashMap<>();
|
for (MesMdItemTypeDO itemType : itemTypeMapper.selectList()) {
|
codeIdMap.put(itemType.getCode(), itemType.getId());
|
}
|
Map<String, Long> importedCodeIdMap = new HashMap<>();
|
|
// 2. 遍历导入
|
for (MesMdItemTypeImportExcelVO importVO : importList) {
|
// 2.1 基础校验
|
if (StrUtil.isBlank(importVO.getCode()) || StrUtil.isBlank(importVO.getName())) {
|
respVO.getFailureList().put(StrUtil.blankToDefault(importVO.getName(), importVO.getCode()), "分类编码和分类名称不能为空");
|
continue;
|
}
|
// 2.2 解析父分类 ID
|
Long parentId = MesMdItemTypeDO.PARENT_ID_ROOT;
|
if (StrUtil.isNotBlank(importVO.getParentCode())) {
|
Long pid = importedCodeIdMap.get(importVO.getParentCode()) != null
|
? importedCodeIdMap.get(importVO.getParentCode())
|
: codeIdMap.get(importVO.getParentCode());
|
if (pid == null) {
|
respVO.getFailureList().put(importVO.getName(), "父分类编码不存在:" + importVO.getParentCode());
|
continue;
|
}
|
parentId = pid;
|
}
|
|
// 2.3 已存在(按编码判断)
|
MesMdItemTypeDO existByCode = itemTypeMapper.selectByCode(importVO.getCode());
|
if (existByCode != null) {
|
if (!Boolean.TRUE.equals(isUpdateSupport)) {
|
respVO.getFailureList().put(importVO.getName(), "分类编码已存在");
|
continue;
|
}
|
MesMdItemTypeDO updateObj = BeanUtils.toBean(importVO, MesMdItemTypeDO.class);
|
updateObj.setId(existByCode.getId());
|
updateObj.setParentId(parentId);
|
itemTypeMapper.updateById(updateObj);
|
respVO.getUpdateList().add(importVO.getName());
|
} else {
|
// 2.4 校验同一父分类下名称唯一
|
MesMdItemTypeDO existByName = itemTypeMapper.selectByParentIdAndName(parentId, importVO.getName());
|
if (existByName != null) {
|
respVO.getFailureList().put(importVO.getName(), "同一父分类下已存在该名称的分类");
|
continue;
|
}
|
// 2.5 校验同一父分类下编码唯一
|
MesMdItemTypeDO existByParentCode = itemTypeMapper.selectByParentIdAndCode(parentId, importVO.getCode());
|
if (existByParentCode != null) {
|
respVO.getFailureList().put(importVO.getName(), "同一父分类下已存在该编码的分类");
|
continue;
|
}
|
// 2.6 新增
|
MesMdItemTypeDO newObj = BeanUtils.toBean(importVO, MesMdItemTypeDO.class);
|
newObj.setParentId(parentId);
|
itemTypeMapper.insert(newObj);
|
respVO.getCreateList().add(importVO.getName());
|
importedCodeIdMap.put(importVO.getCode(), newObj.getId());
|
}
|
}
|
return respVO;
|
}
|
|
}
|