云
2026-10-25 d54fbc9d4f8981fa0f7f613b33a28a8cd4f764ea
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
@@ -2,27 +2,33 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportExcelVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportReqVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportRespVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
import cn.iocoder.yudao.module.mdm.dal.mysql.brand.MdmBrandMapper;
import cn.iocoder.yudao.module.mdm.dal.mysql.category.MdmItemCategoryMapper;
import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemBatchConfigMapper;
import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
import cn.iocoder.yudao.module.mdm.dal.mysql.unit.MdmUnitMeasureMapper;
import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
import cn.iocoder.yudao.module.mes.api.item.MesMdItemApi;
import cn.iocoder.yudao.module.mes.api.item.MesMdItemTypeApi;
import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO;
import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -33,12 +39,13 @@
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
/**
 * MDM 物料主数据 Service 实现类
 *
 * @author 芋道源码
 * @author 超级管理员
 */
@Service
@Validated
@@ -55,14 +62,17 @@
    private MdmBrandService brandService;
    @Resource
    private MdmItemCategoryMapper itemCategoryMapper;
    @Resource
    private MdmUnitMeasureMapper unitMeasureMapper;
    @Resource
    private MdmBrandMapper brandMapper;
    @Resource
    @Lazy
    private MesMdItemApi mesMdItemApi;
    @Resource
    private MdmItemBatchConfigMapper itemBatchConfigMapper;
    @Resource
    private MesMdItemTypeApi mesMdItemTypeApi;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -77,9 +87,11 @@
        // 保存批次配置(如果有)
        saveBatchConfig(item.getId(), createReqVO);
        // 始终同步到 MES
        createReqVO.setId(item.getId());
        syncItemToMes(createReqVO);
        // 勾选同步时,同步到 MES
        if (Boolean.TRUE.equals(createReqVO.getSyncMes())) {
            createReqVO.setId(item.getId());
            syncItemToMes(createReqVO);
        }
        return item.getId();
    }
@@ -98,8 +110,12 @@
        // 保存批次配置(如果有)
        saveBatchConfig(updateReqVO.getId(), updateReqVO);
        // 始终同步到 MES
        syncItemToMes(updateReqVO);
        // 根据同步开关决定:打开则同步到 MES,关闭则取消同步(从 MES 删除)
        if (Boolean.TRUE.equals(updateReqVO.getSyncMes())) {
            syncItemToMes(updateReqVO);
        } else {
            mesMdItemApi.deleteItem(updateReqVO.getId());
        }
    }
    private void validateItemSaveData(MdmItemSaveReqVO reqVO) {
@@ -127,8 +143,11 @@
        // 解析分类 id -> code(使用 MDM 本地分类服务)
        String itemTypeCode = null;
        if (reqVO.getCategoryId() != null) {
            CommonResult<MesMdItemTypeRespDTO> itemType = mesMdItemTypeApi.getItemType(reqVO.getCategoryId());
            itemTypeCode = itemType.getData().getCode();
            MdmItemCategoryDO category = itemCategoryService.getItemCategory(reqVO.getCategoryId());
            if (category == null) {
                throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS);
            }
            itemTypeCode = category.getCode();
        }
        // 组装同步 DTO
        MesMdItemSyncReqDTO syncReqDTO = new MesMdItemSyncReqDTO();
@@ -143,6 +162,7 @@
        syncReqDTO.setMaxStock(reqVO.getMaxStock());
        syncReqDTO.setHighValue(reqVO.getIsHighValue());
        syncReqDTO.setBatchFlag(reqVO.getIsBatchManaged());
        syncReqDTO.setStatus(reqVO.getStatus());
        syncReqDTO.setRemark(reqVO.getRemark());
        // 批次配置字段
        syncReqDTO.setProduceDateFlag(reqVO.getProduceDateFlag());
@@ -184,6 +204,35 @@
        mesMdItemApi.deleteItem(id);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateItemSync(Long id, Boolean sync) {
        // 校验存在
        MdmItemDO item = validateItemExists(id);
        if (Boolean.TRUE.equals(sync)) {
            // 同步到 MES:从 DB 读取完整物料数据组装后走 syncItemToMes
            MdmItemSaveReqVO reqVO = BeanUtils.toBean(item, MdmItemSaveReqVO.class);
            // DO 字段名为 highValue,与 VO 的 isHighValue 不自动匹配,手动补齐
            reqVO.setIsHighValue(item.getHighValue());
            // 补齐批次属性配置
            MdmItemBatchConfigDO config = itemBatchConfigMapper.selectOne(
                    MdmItemBatchConfigDO::getItemId, id);
            if (config != null) {
                reqVO.setProduceDateFlag(config.getProduceDateFlag());
                reqVO.setExpireDateFlag(config.getExpireDateFlag());
                reqVO.setReceiptDateFlag(config.getReceiptDateFlag());
                reqVO.setVendorFlag(config.getVendorFlag());
                reqVO.setPurchaseOrderCodeFlag(config.getPurchaseOrderCodeFlag());
                reqVO.setLotNumberFlag(config.getLotNumberFlag());
                reqVO.setQualityStatusFlag(config.getQualityStatusFlag());
            }
            syncItemToMes(reqVO);
        } else {
            // 取消同步:从 MES 删除该物料(MES 无此物料时内部为空操作)
            mesMdItemApi.deleteItem(id);
        }
    }
    /**
     * 校验物料未被业务引用(销售、采购、生产、质检、库存等)
     *
@@ -207,6 +256,111 @@
        }
        // 逐个删除(复用单条删除逻辑,保持校验)
        ids.forEach(this::deleteItem);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MdmItemImportRespVO importItemList(List<MdmItemImportExcelVO> importItems,
                                              MdmItemImportReqVO importReqVO) {
        // 1. 校验非空(以物料编码作为导入主键)
        importItems = filterList(importItems, item -> StrUtil.isNotBlank(item.getCode()));
        if (CollUtil.isEmpty(importItems)) {
            throw exception(MDM_ITEM_IMPORT_LIST_IS_EMPTY);
        }
        // 2. 逐条处理
        MdmItemImportRespVO respVO = MdmItemImportRespVO.builder()
                .createItemCodes(new ArrayList<>())
                .updateItemCodes(new ArrayList<>())
                .failureItemCodes(new LinkedHashMap<>())
                .build();
        importItems.forEach(importItem -> {
            try {
                // 2.1 解析外键:分类 / 主单位 / 辅单位 / 品牌(按名称解析)
                Long categoryId = resolveCategoryId(importItem.getCategoryName());
                Long unitMeasureId = resolveUnitMeasureId(importItem.getUnitMeasureName());
                Long unitMeasureId2 = resolveUnitMeasureId(importItem.getUnitMeasureName2());
                Long unitMeasureId3 = resolveUnitMeasureId(importItem.getUnitMeasureName3());
                Long brandId = resolveBrandId(importItem.getBrandName());
                // 2.2 判断是否存在(按编码唯一)
                MdmItemDO existItem = itemMapper.selectByCode(importItem.getCode());
                if (existItem == null) {
                    // 2.2.1 新增
                    MdmItemDO item = BeanUtils.toBean(importItem, MdmItemDO.class)
                            .setCategoryId(categoryId)
                            .setUnitMeasureId(unitMeasureId)
                            .setUnitMeasureId2(unitMeasureId2)
                            .setUnitMeasureId3(unitMeasureId3)
                            .setBrandId(brandId);
                    if (item.getStatus() == null) {
                        item.setStatus(CommonStatusEnum.ENABLE.getStatus());
                    }
                    itemMapper.insert(item);
                    respVO.getCreateItemCodes().add(importItem.getCode());
                    return;
                }
                // 2.2.2 已存在,判断是否允许更新
                if (!importReqVO.getUpdateSupport()) {
                    respVO.getFailureItemCodes().put(importItem.getCode(),
                            StrUtil.format(MDM_ITEM_CODE_EXISTS.getMsg(), importItem.getCode()));
                    return;
                }
                MdmItemDO updateItem = BeanUtils.toBean(importItem, MdmItemDO.class)
                        .setId(existItem.getId())
                        .setCategoryId(categoryId)
                        .setUnitMeasureId(unitMeasureId)
                        .setUnitMeasureId2(unitMeasureId2)
                        .setUnitMeasureId3(unitMeasureId3)
                        .setBrandId(brandId);
                itemMapper.updateById(updateItem);
                respVO.getUpdateItemCodes().add(importItem.getCode());
            } catch (ServiceException ex) {
                respVO.getFailureItemCodes().put(importItem.getCode(), ex.getMessage());
            }
        });
        return respVO;
    }
    /**
     * 按名称解析物料分类编号
     */
    private Long resolveCategoryId(String categoryName) {
        if (StrUtil.isBlank(categoryName)) {
            return null;
        }
        MdmItemCategoryDO category = itemCategoryMapper.selectByName(categoryName);
        if (category == null) {
            throw exception(MDM_ITEM_IMPORT_CATEGORY_NOT_EXISTS, categoryName);
        }
        return category.getId();
    }
    /**
     * 按名称解析计量单位编号
     */
    private Long resolveUnitMeasureId(String unitMeasureName) {
        if (StrUtil.isBlank(unitMeasureName)) {
            return null;
        }
        MdmUnitMeasureDO unitMeasure = unitMeasureMapper.selectByName(unitMeasureName);
        if (unitMeasure == null) {
            throw exception(MDM_ITEM_IMPORT_UNIT_NOT_EXISTS, unitMeasureName);
        }
        return unitMeasure.getId();
    }
    /**
     * 按名称解析品牌编号
     */
    private Long resolveBrandId(String brandName) {
        if (StrUtil.isBlank(brandName)) {
            return null;
        }
        MdmBrandDO brand = brandMapper.selectByName(brandName);
        if (brand == null) {
            throw exception(MDM_ITEM_IMPORT_BRAND_NOT_EXISTS, brandName);
        }
        return brand.getId();
    }
    @Override
@@ -332,6 +486,12 @@
        return itemMapper.selectByCode(code);
    }
    @Override
    public List<MdmItemDO> getItemSimpleList() {
        return itemMapper.selectList(MdmItemDO::getStatus,
                cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus());
    }
    /**
     * 保存批次配置(到 MDM 本地表)
     */
@@ -379,4 +539,4 @@
        }
    }
}
}