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.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.module.mdm.api.category.MdmItemCategoryApi;
|
import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategoryRespDTO;
|
import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategorySaveReqDTO;
|
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 jakarta.annotation.Resource;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.util.*;
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 物料产品分类 Service 实现类
|
*
|
* 物料分类已统一由 MDM 管理,数据存储在 mdm_item_category 表。
|
* 本服务保留 MES 的分类接口,底层全部通过 {@link MdmItemCategoryApi} 读写 MDM 分类。
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesMdItemTypeServiceImpl implements MesMdItemTypeService {
|
|
/** MDM 物料类型:物料 */
|
private static final Integer MDM_ITEM_TYPE_MATERIAL = 1;
|
/** MDM 物料类型:产品 */
|
private static final Integer MDM_ITEM_TYPE_PRODUCT = 2;
|
/** MES 物料/产品标识:产品 */
|
private static final String ITEM_OR_PRODUCT_PRODUCT = "PRODUCT";
|
|
@Resource
|
private MdmItemCategoryApi mdmItemCategoryApi;
|
|
@Resource
|
@Lazy
|
private MesMdItemService itemService;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Long createItemType(MesMdItemTypeSaveReqVO createReqVO) {
|
// 校验父分类
|
validateParentItemType(createReqVO.getId(), createReqVO.getParentId());
|
// 写入 MDM 分类表
|
CommonResult<Long> result = mdmItemCategoryApi.createItemCategory(buildSaveDTO(createReqVO));
|
return result.getData();
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void updateItemType(MesMdItemTypeSaveReqVO updateReqVO) {
|
// 校验存在
|
validateItemTypeExists(updateReqVO.getId());
|
// 校验父分类
|
validateParentItemType(updateReqVO.getId(), updateReqVO.getParentId());
|
// 更新 MDM 分类表
|
MdmItemCategorySaveReqDTO updateDTO = buildSaveDTO(updateReqVO);
|
updateDTO.setId(updateReqVO.getId());
|
mdmItemCategoryApi.updateItemCategory(updateDTO);
|
}
|
|
private MdmItemCategorySaveReqDTO buildSaveDTO(MesMdItemTypeSaveReqVO reqVO) {
|
MdmItemCategorySaveReqDTO dto = new MdmItemCategorySaveReqDTO();
|
dto.setParentId(ObjUtil.defaultIfNull(reqVO.getParentId(), MesMdItemTypeDO.PARENT_ID_ROOT));
|
dto.setCode(reqVO.getCode());
|
dto.setName(reqVO.getName());
|
dto.setItemOrProduct(reqVO.getItemOrProduct());
|
dto.setItemType(convertMdmItemType(reqVO.getItemOrProduct()));
|
dto.setSort(ObjUtil.defaultIfNull(reqVO.getSort(), 0));
|
dto.setStatus(ObjUtil.defaultIfNull(reqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
|
dto.setRemark(reqVO.getRemark());
|
return dto;
|
}
|
|
/**
|
* MES 物料/产品标识 -> MDM 物料类型
|
*/
|
private Integer convertMdmItemType(String itemOrProduct) {
|
if (StrUtil.isBlank(itemOrProduct)) {
|
return null;
|
}
|
return ITEM_OR_PRODUCT_PRODUCT.equalsIgnoreCase(itemOrProduct)
|
? MDM_ITEM_TYPE_PRODUCT : MDM_ITEM_TYPE_MATERIAL;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteItemType(Long id) {
|
// 1.1 校验存在
|
validateItemTypeExists(id);
|
// 1.2 校验是否有物料
|
if (itemService.getItemCountByItemTypeId(id) > 0) {
|
throw exception(MD_ITEM_TYPE_EXITS_ITEM);
|
}
|
// 2. 删除(子分类、MDM 物料引用由 MDM 侧校验)
|
mdmItemCategoryApi.deleteItemCategory(id);
|
}
|
|
private void validateItemTypeExists(Long id) {
|
if (getItemType(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. 父分类不存在
|
MesMdItemTypeDO parentItemType = getItemType(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;
|
}
|
parentItemType = getItemType(parentId);
|
if (parentItemType == null) {
|
break;
|
}
|
}
|
}
|
|
@Override
|
public MesMdItemTypeDO getItemType(Long id) {
|
CommonResult<MdmItemCategoryRespDTO> result = mdmItemCategoryApi.getItemCategory(id);
|
return result.isSuccess() ? convertToMesDO(result.getData()) : null;
|
}
|
|
@Override
|
public MesMdItemTypeDO getItemTypeByCode(String code) {
|
CommonResult<MdmItemCategoryRespDTO> result = mdmItemCategoryApi.getItemCategoryByCode(code);
|
return result.isSuccess() ? convertToMesDO(result.getData()) : null;
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeList(MesMdItemTypeListReqVO listReqVO) {
|
List<MesMdItemTypeDO> list = getAllItemTypeList();
|
return list.stream()
|
.filter(itemType -> StrUtil.isBlank(listReqVO.getName())
|
|| StrUtil.contains(itemType.getName(), listReqVO.getName()))
|
.filter(itemType -> listReqVO.getStatus() == null
|
|| Objects.equals(listReqVO.getStatus(), itemType.getStatus()))
|
.sorted(Comparator.comparing(itemType -> ObjUtil.defaultIfNull(itemType.getSort(), 0)))
|
.toList();
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeList(Collection<Long> ids) {
|
if (CollUtil.isEmpty(ids)) {
|
return Collections.emptyList();
|
}
|
CommonResult<List<MdmItemCategoryRespDTO>> result = mdmItemCategoryApi.getItemCategoryList(ids);
|
return convertToMesDOList(result.isSuccess() ? result.getData() : null);
|
}
|
|
private List<MesMdItemTypeDO> getAllItemTypeList() {
|
CommonResult<List<MdmItemCategoryRespDTO>> result = mdmItemCategoryApi.getItemCategoryAllList();
|
return convertToMesDOList(result.isSuccess() ? result.getData() : null);
|
}
|
|
private List<MesMdItemTypeDO> convertToMesDOList(List<MdmItemCategoryRespDTO> list) {
|
if (CollUtil.isEmpty(list)) {
|
return new ArrayList<>();
|
}
|
return new ArrayList<>(list.stream().map(this::convertToMesDO).toList());
|
}
|
|
@Override
|
public List<MesMdItemTypeDO> getItemTypeChildrenList(Long parentId) {
|
List<MesMdItemTypeDO> allList = getAllItemTypeList();
|
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) {
|
if (dto == null) {
|
return null;
|
}
|
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());
|
mesDO.setRemark(dto.getRemark());
|
mesDO.setCreateTime(dto.getCreateTime());
|
return mesDO;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public MesMdItemTypeImportRespVO importItemTypeList(List<MesMdItemTypeImportExcelVO> importItemTypeList,
|
boolean updateSupport) {
|
// 1. 校验非空
|
if (CollUtil.isEmpty(importItemTypeList)) {
|
throw exception(MD_ITEM_TYPE_IMPORT_LIST_IS_EMPTY);
|
}
|
|
// 2. 逐行处理
|
MesMdItemTypeImportRespVO respVO = MesMdItemTypeImportRespVO.builder()
|
.createCodes(new ArrayList<>()).updateCodes(new ArrayList<>())
|
.failureCodes(new LinkedHashMap<>()).build();
|
List<MesMdItemTypeDO> allList = getAllItemTypeList();
|
AtomicInteger index = new AtomicInteger(1);
|
importItemTypeList.forEach(importItem -> {
|
int currentIndex = index.getAndIncrement();
|
String key = StrUtil.blankToDefault(importItem.getCode(), "第 " + currentIndex + " 行");
|
if (StrUtil.isBlank(importItem.getCode())) {
|
respVO.getFailureCodes().put(key, "分类编码不能为空");
|
return;
|
}
|
if (StrUtil.isBlank(importItem.getName())) {
|
respVO.getFailureCodes().put(key, "分类名称不能为空");
|
return;
|
}
|
if (StrUtil.isBlank(importItem.getItemOrProduct())) {
|
respVO.getFailureCodes().put(key, "物料/产品标识不能为空");
|
return;
|
}
|
// 2.1 解析父分类(为空则默认为根分类)
|
Long parentId = MesMdItemTypeDO.PARENT_ID_ROOT;
|
if (StrUtil.isNotBlank(importItem.getParentCode())) {
|
MesMdItemTypeDO parentItemType = allList.stream()
|
.filter(itemType -> Objects.equals(importItem.getParentCode(), itemType.getCode()))
|
.findFirst().orElse(null);
|
if (parentItemType == null) {
|
respVO.getFailureCodes().put(key, "父分类编码[" + importItem.getParentCode() + "]不存在");
|
return;
|
}
|
parentId = parentItemType.getId();
|
}
|
// 2.2 判断是否存在(同一父分类下编码唯一)
|
Long finalParentId = parentId;
|
MesMdItemTypeDO existItemType = allList.stream()
|
.filter(itemType -> Objects.equals(finalParentId, itemType.getParentId())
|
&& Objects.equals(importItem.getCode(), itemType.getCode()))
|
.findFirst().orElse(null);
|
try {
|
MdmItemCategorySaveReqDTO dto = new MdmItemCategorySaveReqDTO();
|
dto.setParentId(parentId);
|
dto.setCode(importItem.getCode());
|
dto.setName(importItem.getName());
|
dto.setItemOrProduct(importItem.getItemOrProduct());
|
dto.setItemType(convertMdmItemType(importItem.getItemOrProduct()));
|
dto.setSort(ObjUtil.defaultIfNull(importItem.getSort(), 0));
|
dto.setStatus(ObjUtil.defaultIfNull(importItem.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
|
dto.setRemark(importItem.getRemark());
|
if (existItemType == null) {
|
// 2.2.1 新增
|
dto.setId(null);
|
Long id = mdmItemCategoryApi.createItemCategory(dto).getData();
|
MesMdItemTypeDO created = new MesMdItemTypeDO();
|
created.setId(id);
|
created.setParentId(parentId);
|
created.setCode(importItem.getCode());
|
created.setName(importItem.getName());
|
created.setItemOrProduct(importItem.getItemOrProduct());
|
created.setSort(dto.getSort());
|
created.setStatus(dto.getStatus());
|
created.setRemark(importItem.getRemark());
|
allList.add(created);
|
respVO.getCreateCodes().add(importItem.getCode());
|
} else if (updateSupport) {
|
// 2.2.2 更新
|
dto.setId(existItemType.getId());
|
mdmItemCategoryApi.updateItemCategory(dto);
|
respVO.getUpdateCodes().add(importItem.getCode());
|
} else {
|
respVO.getFailureCodes().put(key, "分类编码已存在");
|
}
|
} catch (ServiceException e) {
|
respVO.getFailureCodes().put(key, e.getMessage());
|
}
|
});
|
return respVO;
|
}
|
|
}
|