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; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum; 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; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; 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; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; /** * CRM 产品 Service 实现类 * * 改造说明:产品数据统一使用 MDM 主数据管理(itemType=2 产品类型) * - 创建、更新操作通过 MDM API 进行 * - 查询操作从 MDM 获取数据 * - CRM 产品表保留用于权限管理 * * @author ZanGe丶 */ @Service @Validated public class CrmProductServiceImpl implements CrmProductService { @Resource(name = "crmProductMapper") private CrmProductMapper productMapper; @Resource private CrmProductCategoryService productCategoryService; @Resource private CrmPermissionService permissionService; @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}}", success = CRM_PRODUCT_CREATE_SUCCESS) public Long createProduct(CrmProductSaveReqVO createReqVO) { // 1. 校验产品 adminUserApi.validateUserList(Collections.singleton(createReqVO.getOwnerUserId())); validateProductNoDuplicate(null, createReqVO.getNo()); validateProductCategoryExists(createReqVO.getCategoryId()); // 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); // 4. 插入数据权限 permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(product.getOwnerUserId()) .setBizType(CrmBizTypeEnum.CRM_PRODUCT.getType()).setBizId(product.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 5. 记录操作日志上下文 LogRecordContext.putVariable("productId", product.getId()); return product.getId(); } @Override @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = CRM_PRODUCT_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateProduct(CrmProductSaveReqVO updateReqVO) { // 1. 校验产品 updateReqVO.setOwnerUserId(null); // 不修改负责人 CrmProductDO crmProductDO = validateProductExists(updateReqVO.getId()); validateProductNoDuplicate(updateReqVO.getId(), updateReqVO.getNo()); validateProductCategoryExists(updateReqVO.getCategoryId()); // 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); // 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) { // 如果本地不存在,创建一个同步记录 product = convertToCrmProduct(item); productMapper.insert(product); } return product; } private void validateProductNoDuplicate(Long id, String no) { MdmItemRespDTO item = mdmItemApi.getItemByCode(no).getCheckedData(); if (item == null || item.getId().equals(id)) { return; } throw exception(PRODUCT_NO_EXISTS); } private void validateProductCategoryExists(Long categoryId) { CrmProductCategoryDO category = productCategoryService.getProductCategory(categoryId); if (category == null) { throw exception(PRODUCT_CATEGORY_NOT_EXISTS); } } @Override @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#id}}", success = CRM_PRODUCT_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) 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) { // 从 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 getProductPage(CrmProductPageReqVO pageReqVO) { // 从 MDM 获取产品分页数据 cn.iocoder.yudao.framework.common.pojo.PageResult mdmPageResult = mdmItemApi.getItemPage(MdmItemTypeEnum.PRODUCT.getType(), null, pageReqVO.getPageNo(), pageReqVO.getPageSize()).getCheckedData(); // 转换为 CRM 产品 List list = mdmPageResult.getList().stream() .map(this::convertToCrmProduct) .collect(Collectors.toList()); return new PageResult<>(list, mdmPageResult.getTotal()); } @Override public Long getProductByCategoryId(Long categoryId) { return mdmItemApi.getItemCountByCategoryId(categoryId).getCheckedData(); } @Override public List getProductListByStatus(Integer status) { // 从 MDM 获取产品数据 List items = mdmItemApi.getItemListByStatus(status).getCheckedData(); // 过滤产品类型并转换 return items.stream() .filter(item -> MdmItemTypeEnum.PRODUCT.getType().equals(item.getItemType())) .map(this::convertToCrmProduct) .collect(Collectors.toList()); } @Override public List validProductList(Collection ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } List items = mdmItemApi.getItemList(ids).getCheckedData(); Map itemMap = convertMap(items, MdmItemRespDTO::getId); List result = new ArrayList<>(); for (Long id : ids) { MdmItemRespDTO item = itemMap.get(id); if (item == null) { throw exception(PRODUCT_NOT_EXISTS); } if (CrmProductStatusEnum.isDisable(item.getStatus())) { throw exception(PRODUCT_NOT_ENABLE, item.getName()); } result.add(convertToCrmProduct(item)); } return result; } @Override public List getProductList(Collection ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } List 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; } }