2026-07-02 fce7a8df22ab7b5b0be0fb5151c40abbfbab6be8
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.service.product;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
@@ -14,6 +15,11 @@
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemCreateReqDTO;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemUpdateReqDTO;
import cn.iocoder.yudao.module.mdm.enums.MdmItemTypeEnum;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
@@ -23,10 +29,8 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@@ -36,6 +40,11 @@
/**
 * CRM 产品 Service 实现类
 *
 * 改造说明:产品数据统一使用 MDM 主数据管理(itemType=2 产品类型)
 * - 创建、更新操作通过 MDM API 进行
 * - 查询操作从 MDM 获取数据
 * - CRM 产品表保留用于权限管理
 *
 * @author ZanGe丶
 */
@@ -54,6 +63,9 @@
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private MdmItemApi mdmItemApi;
    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_CREATE_SUB_TYPE, bizNo = "{{#productId}}",
@@ -64,16 +76,38 @@
        validateProductNoDuplicate(null, createReqVO.getNo());
        validateProductCategoryExists(createReqVO.getCategoryId());
        // 2. 插入产品
        CrmProductDO product = BeanUtils.toBean(createReqVO, CrmProductDO.class);
        // 2. 通过 MDM API 创建产品
        MdmItemCreateReqDTO createReqDTO = new MdmItemCreateReqDTO();
        createReqDTO.setCode(createReqVO.getNo());
        createReqDTO.setName(createReqVO.getName());
        createReqDTO.setBarCode(createReqVO.getNo()); // 使用编码作为条码
        createReqDTO.setCategoryId(createReqVO.getCategoryId());
        createReqDTO.setUnitMeasureId(createReqVO.getUnit() != null ? createReqVO.getUnit().longValue() : null);
        createReqDTO.setItemType(MdmItemTypeEnum.PRODUCT.getType()); // 产品类型
        createReqDTO.setStatus(createReqVO.getStatus() != null ? createReqVO.getStatus() : CommonStatusEnum.ENABLE.getStatus());
        createReqDTO.setSalesPrice(createReqVO.getPrice());
        createReqDTO.setRemark(createReqVO.getDescription());
        Long itemId = mdmItemApi.createItem(createReqDTO).getCheckedData();
        // 3. 插入本地产品记录(用于权限管理)
        CrmProductDO product = new CrmProductDO();
        product.setId(itemId);
        product.setName(createReqVO.getName());
        product.setNo(createReqVO.getNo());
        product.setUnit(createReqVO.getUnit());
        product.setPrice(createReqVO.getPrice());
        product.setStatus(createReqVO.getStatus());
        product.setCategoryId(createReqVO.getCategoryId());
        product.setDescription(createReqVO.getDescription());
        product.setOwnerUserId(createReqVO.getOwnerUserId());
        productMapper.insert(product);
        // 3. 插入数据权限
        // 4. 插入数据权限
        permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(product.getOwnerUserId())
                .setBizType(CrmBizTypeEnum.CRM_PRODUCT.getType()).setBizId(product.getId())
                .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
        // 4. 记录操作日志上下文
        // 5. 记录操作日志上下文
        LogRecordContext.putVariable("productId", product.getId());
        return product.getId();
    }
@@ -89,26 +123,47 @@
        validateProductNoDuplicate(updateReqVO.getId(), updateReqVO.getNo());
        validateProductCategoryExists(updateReqVO.getCategoryId());
        // 2. 更新产品
        // 2. 通过 MDM API 更新产品
        MdmItemUpdateReqDTO updateReqDTO = new MdmItemUpdateReqDTO();
        updateReqDTO.setId(updateReqVO.getId());
        updateReqDTO.setCode(updateReqVO.getNo());
        updateReqDTO.setName(updateReqVO.getName());
        updateReqDTO.setBarCode(updateReqVO.getNo());
        updateReqDTO.setCategoryId(updateReqVO.getCategoryId());
        updateReqDTO.setUnitMeasureId(updateReqVO.getUnit() != null ? updateReqVO.getUnit().longValue() : null);
        updateReqDTO.setItemType(MdmItemTypeEnum.PRODUCT.getType());
        updateReqDTO.setStatus(updateReqVO.getStatus());
        updateReqDTO.setSalesPrice(updateReqVO.getPrice());
        updateReqDTO.setRemark(updateReqVO.getDescription());
        mdmItemApi.updateItem(updateReqDTO);
        // 3. 更新本地产品记录
        CrmProductDO updateObj = BeanUtils.toBean(updateReqVO, CrmProductDO.class);
        productMapper.updateById(updateObj);
        // 3. 记录操作日志上下文
        // 4. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(crmProductDO, CrmProductSaveReqVO.class));
    }
    private CrmProductDO validateProductExists(Long id) {
        // 从 MDM 校验
        MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData();
        if (item == null) {
            throw exception(PRODUCT_NOT_EXISTS);
        }
        // 从本地获取 CRM 产品记录
        CrmProductDO product = productMapper.selectById(id);
        if (product == null) {
            throw exception(PRODUCT_NOT_EXISTS);
            // 如果本地不存在,创建一个同步记录
            product = convertToCrmProduct(item);
            productMapper.insert(product);
        }
        return product;
    }
    private void validateProductNoDuplicate(Long id, String no) {
        CrmProductDO product = productMapper.selectByNo(no);
        if (product == null
                || product.getId().equals(id)) {
        MdmItemRespDTO item = mdmItemApi.getItemByCode(no).getCheckedData();
        if (item == null || item.getId().equals(id)) {
            return;
        }
        throw exception(PRODUCT_NO_EXISTS);
@@ -128,29 +183,65 @@
    public void deleteProduct(Long id) {
        // 校验存在
        validateProductExists(id);
        // 删除
        // 通过 MDM API 删除(更新状态为禁用)
        mdmItemApi.updateItemStatus(id, CommonStatusEnum.DISABLE.getStatus());
        // 删除本地记录
        productMapper.deleteById(id);
    }
    @Override
    @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.READ)
    public CrmProductDO getProduct(Long id) {
        return productMapper.selectById(id);
        // 从 MDM 获取产品数据
        MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData();
        if (item == null || !MdmItemTypeEnum.PRODUCT.getType().equals(item.getItemType())) {
            return null;
        }
        // 获取本地 CRM 产品记录(用于权限)
        CrmProductDO product = productMapper.selectById(id);
        if (product == null) {
            // 同步创建本地记录
            product = convertToCrmProduct(item);
            productMapper.insert(product);
        } else {
            // 更新本地记录的数据
            product.setName(item.getName());
            product.setNo(item.getCode());
            product.setPrice(item.getSalesPrice());
            product.setStatus(item.getStatus());
            product.setCategoryId(item.getCategoryId());
            product.setDescription(item.getRemark());
        }
        return product;
    }
    @Override
    public PageResult<CrmProductDO> getProductPage(CrmProductPageReqVO pageReqVO) {
        return productMapper.selectPage(pageReqVO);
        // 从 MDM 获取产品分页数据
        cn.iocoder.yudao.framework.common.pojo.PageResult<MdmItemRespDTO> mdmPageResult =
                mdmItemApi.getItemPage(MdmItemTypeEnum.PRODUCT.getType(), null,
                        pageReqVO.getPageNo(), pageReqVO.getPageSize()).getCheckedData();
        // 转换为 CRM 产品
        List<CrmProductDO> list = mdmPageResult.getList().stream()
                .map(this::convertToCrmProduct)
                .collect(Collectors.toList());
        return new PageResult<>(list, mdmPageResult.getTotal());
    }
    @Override
    public Long getProductByCategoryId(Long categoryId) {
        return productMapper.selectCountByCategoryId(categoryId);
        return mdmItemApi.getItemCountByCategoryId(categoryId).getCheckedData();
    }
    @Override
    public List<CrmProductDO> getProductListByStatus(Integer status) {
        return productMapper.selectListByStatus(status);
        // 从 MDM 获取产品数据
        List<MdmItemRespDTO> items = mdmItemApi.getItemListByStatus(status).getCheckedData();
        // 过滤产品类型并转换
        return items.stream()
                .filter(item -> MdmItemTypeEnum.PRODUCT.getType().equals(item.getItemType()))
                .map(this::convertToCrmProduct)
                .collect(Collectors.toList());
    }
    @Override
@@ -158,18 +249,20 @@
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<CrmProductDO> list = productMapper.selectByIds(ids);
        Map<Long, CrmProductDO> productMap = convertMap(list, CrmProductDO::getId);
        List<MdmItemRespDTO> items = mdmItemApi.getItemList(ids).getCheckedData();
        Map<Long, MdmItemRespDTO> itemMap = convertMap(items, MdmItemRespDTO::getId);
        List<CrmProductDO> result = new ArrayList<>();
        for (Long id : ids) {
            CrmProductDO product = productMap.get(id);
            if (productMap.get(id) == null) {
            MdmItemRespDTO item = itemMap.get(id);
            if (item == null) {
                throw exception(PRODUCT_NOT_EXISTS);
            }
            if (CrmProductStatusEnum.isDisable(product.getStatus())) {
                throw exception(PRODUCT_NOT_ENABLE, product.getName());
            if (CrmProductStatusEnum.isDisable(item.getStatus())) {
                throw exception(PRODUCT_NOT_ENABLE, item.getName());
            }
            result.add(convertToCrmProduct(item));
        }
        return list;
        return result;
    }
    @Override
@@ -177,7 +270,27 @@
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return productMapper.selectByIds(ids);
        List<MdmItemRespDTO> items = mdmItemApi.getItemList(ids).getCheckedData();
        return items.stream()
                .filter(item -> MdmItemTypeEnum.PRODUCT.getType().equals(item.getItemType()))
                .map(this::convertToCrmProduct)
                .collect(Collectors.toList());
    }
    /**
     * 将 MDM 物料转换为 CRM 产品
     */
    private CrmProductDO convertToCrmProduct(MdmItemRespDTO item) {
        CrmProductDO product = new CrmProductDO();
        product.setId(item.getId());
        product.setName(item.getName());
        product.setNo(item.getCode());
        product.setUnit(item.getUnitMeasureId() != null ? item.getUnitMeasureId().intValue() : null);
        product.setPrice(item.getSalesPrice());
        product.setStatus(item.getStatus());
        product.setCategoryId(item.getCategoryId());
        product.setDescription(item.getRemark());
        return product;
    }
}