@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.crm.service.clue;
import cn.hutool.core.collection.CollUtil ;
import cn.hutool.core.collection.ListUtil ;
import cn.hutool.core.lang.Assert ;
import cn.hutool.core.util.ObjectUtil ;
import cn.hutool.core.util.StrUtil ;
import cn.iocoder.yudao.framework.common.pojo.PageResult ;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils ;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils ;
import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO ;
import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO ;
@ -19,7 +22,11 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService ;
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO ;
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService ;
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO ;
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 ;
@ -29,11 +36,12 @@ import java.util.Collection;
import java.util.List ;
import java.util.Objects ;
import java.util.Set ;
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.convertSet ;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId ;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.* ;
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.* ;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS ;
/**
@ -58,29 +66,50 @@ public class CrmClueServiceImpl implements CrmClueService {
private AdminUserApi adminUserApi ;
@Override
// TODO @min: 补充相关几个方法的操作日志;
@Transactional ( rollbackFor = Exception . class )
@LogRecord ( type = CRM_LEADS_TYPE , subType = CRM_LEADS_CREATE_SUB_TYPE , bizNo = " {{#clue.id}} " ,
success = CRM_LEADS_CREATE_SUCCESS )
public Long createClue ( CrmClueSaveReqVO createReqVO ) {
// 校验关联数据
// 1. 校验关联数据
validateRelationDataExists ( createReqVO ) ;
// 插入
// 2. 插入
CrmClueDO clue = BeanUtils . toBean ( createReqVO , CrmClueDO . class ) ;
clueMapper . insert ( clue ) ;
// 返回
// 3. 创建数据权限
CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO ( )
. setBizType ( CrmBizTypeEnum . CRM_LEADS . getType ( ) )
. setBizId ( clue . getId ( ) )
// 设置当前操作的人为负责人
. setUserId ( getLoginUserId ( ) )
. setLevel ( CrmPermissionLevelEnum . OWNER . getLevel ( ) ) ;
crmPermissionService . createPermission ( createReqBO ) ;
// 4. 记录操作日志上下文
LogRecordContext . putVariable ( " clue " , clue ) ;
return clue . getId ( ) ;
}
@Override
@Transactional ( rollbackFor = Exception . class )
@LogRecord ( type = CRM_LEADS_TYPE , subType = CRM_LEADS_UPDATE_SUB_TYPE , bizNo = " {{#updateReqVO.id}} " ,
success = CRM_LEADS_UPDATE_SUCCESS )
@CrmPermission ( bizType = CrmBizTypeEnum . CRM_LEADS , bizId = " #updateReqVO.id " , level = CrmPermissionLevelEnum . WRITE )
public void updateClue ( CrmClueSaveReqVO updateReqVO ) {
// 校验线索是否存在
validateClueExists ( updateReqVO . getId ( ) ) ;
// 校验关联数据
Assert . notNull ( updateReqVO . getId ( ) , " 线索编号不能为空 " ) ;
// 1. 校验线索是否存在
CrmClueDO oldClue = validateClueExists ( updateReqVO . getId ( ) ) ;
// 2. 校验关联数据
validateRelationDataExists ( updateReqVO ) ;
// 更新
// 3. 更新
CrmClueDO updateObj = BeanUtils . toBean ( updateReqVO , CrmClueDO . class ) ;
clueMapper . updateById ( updateObj ) ;
// 3. 记录操作日志上下文
LogRecordContext . putVariable ( DiffParseFunction . OLD_OBJECT , BeanUtils . toBean ( oldClue , CrmCustomerSaveReqVO . class ) ) ;
LogRecordContext . putVariable ( " clueName " , oldClue . getName ( ) ) ;
}
@Override
@ -89,20 +118,30 @@ public class CrmClueServiceImpl implements CrmClueService {
}
@Override
@Transactional ( rollbackFor = Exception . class )
@LogRecord ( type = CRM_LEADS_TYPE , subType = CRM_LEADS_DELETE_SUB_TYPE , bizNo = " {{#id}} " ,
success = CRM_LEADS_DELETE_SUCCESS )
@CrmPermission ( bizType = CrmBizTypeEnum . CRM_LEADS , bizId = " #id " , level = CrmPermissionLevelEnum . OWNER )
public void deleteClue ( Long id ) {
// 校验存在
validateClueExists ( id ) ;
// 删除
// 1. 校验存在
CrmClueDO clue = validateClueExists( id ) ;
// 2. 删除
clueMapper . deleteById ( id ) ;
// 删除数据权限
// 3. 删除数据权限
crmPermissionService . deletePermission ( CrmBizTypeEnum . CRM_LEADS . getType ( ) , id ) ;
// 4. 记录操作日志上下文
LogRecordContext . putVariable ( " clueName " , clue . getName ( ) ) ;
}
private void validateClueExists ( Long id ) {
if ( clueMapper . selectById ( id ) = = null ) {
private CrmClueDO validateClueExists ( Long id ) {
CrmClueDO crmClueDO = clueMapper . selectById ( id ) ;
if ( crmClueDO = = null ) {
throw exception ( CLUE_NOT_EXISTS ) ;
}
return crmClueDO ;
}
@Override
@ -145,29 +184,24 @@ public class CrmClueServiceImpl implements CrmClueService {
List < CrmClueDO > clues = getClueList ( clueIds , userId ) ;
if ( CollUtil . isEmpty ( clues ) | | ObjectUtil . notEqual ( clues . size ( ) , clueIds . size ( ) ) ) {
clueIds . removeAll ( convertSet ( clues , CrmClueDO : : getId ) ) ;
// TODO @min: 可以使用 StrUtil.join(",", clueIds) 简化这种常见操作
throw exception ( CLUE_ANY_CLUE_NOT_EXISTS , clueIds . stream ( ) . map ( String : : valueOf ) . collect ( Collectors . joining ( " , " ) ) ) ;
throw exception ( CLUE_ANY_CLUE_NOT_EXISTS , StrUtil . join ( " , " , clueIds ) ) ;
}
// 过滤出未转化的客户
// TODO @min: 1) 存在已经转化的, 直接提示哈。避免操作的用户, 以为都转化成功了; 2) 常见的过滤逻辑, 可以使用 CollectionUtils. filterList()
List < CrmClueDO > unTransformClues = clues . stream ( )
. filter ( clue - > ObjectUtil . notEqual ( Boolean . TRUE , clue . getTransformStatus ( ) ) ) . toList ( ) ;
// 传入的线索中包含已经转化的情况,抛出业务异常
if ( ObjectUtil . notEqual ( clues . size ( ) , unTransformClues . size ( ) ) ) {
// TODO @min: 可以使用 StrUtil.join(",", clueIds) 简化这种常见操作
clueIds . removeAll ( convertSet ( unTransformClues , CrmClueDO : : getId ) ) ;
throw exception ( CLUE_ANY_CLUE_ALREADY_TRANSLATED , clueIds . stream ( ) . map ( String : : valueOf ) . collect ( Collectors . joining ( " , " ) ) ) ;
// 存在已经转化的,直接提示哈。避免操作的用户,以为都转化成功了
List < CrmClueDO > translatedClues = CollectionUtils. filterList( clues ,
clue - > ObjectUtil . equal ( Boolean . TRUE , clue . getTransformStatus ( ) ) ) ;
if ( CollUtil . isNotEmpty ( translatedClues ) ) {
throw exception ( CLUE_ANY_CLUE_ALREADY_TRANSLATED , StrUtil . join ( " , " , convertSet ( translatedClues , CrmClueDO : : getId ) ) ) ;
}
// 遍历线索(未转化的线索),创建对应的客户
unTransformClues . forEach ( clue - > {
reqVO . getIds ( ) . forEach ( id - > {
// 1. 创建客户
CrmCustomerSaveReqVO customerSaveReqVO = BeanUtils . toBean ( clue , CrmCustomerSaveReqVO . class ) . setId ( null ) ;
CrmCustomerSaveReqVO customerSaveReqVO = BeanUtils . toBean ( id , CrmCustomerSaveReqVO . class ) . setId ( null ) ;
Long customerId = customerService . createCustomer ( customerSaveReqVO , userId ) ;
// TODO @puhui999: 如果有跟进记录, 需要一起转过去; 提问: 艿艿这里是复制线索所有的跟进吗? 还是直接把线索相关的跟进 bizType、bizId 全改为关联客户?
// 2. 更新线索
clueMapper . updateById ( new CrmClueDO ( ) . setId ( clue . getId ( ) )
clueMapper . updateById ( new CrmClueDO ( ) . setId ( id )
. setTransformStatus ( Boolean . TRUE ) . setCustomerId ( customerId ) ) ;
} ) ;
}