package cn.iocoder.yudao.module.crm.service.clue; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; 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.clue.vo.CrmCluePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; 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.time.LocalDateTime; import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.singleton; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_NOT_EXISTS; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_TRANSFORM_FAIL_ALREADY; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; /** * 线索 Service 实现类 * * @author Wanwan */ @Service @Validated public class CrmClueServiceImpl implements CrmClueService { @Resource private CrmClueMapper clueMapper; @Resource private CrmCustomerService customerService; @Resource private CrmPermissionService crmPermissionService; @Resource private CrmFollowUpRecordService followUpRecordService; @Resource private AdminUserApi adminUserApi; @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_CREATE_SUB_TYPE, bizNo = "{{#clue.id}}", success = CRM_CLUE_CREATE_SUCCESS) public Long createClue(CrmClueSaveReqVO createReqVO) { // 1.1 校验关联数据 validateRelationDataExists(createReqVO); // 1.2 校验负责人是否存在 adminUserApi.validateUser(createReqVO.getOwnerUserId()); // 2. 插入线索 CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class); clueMapper.insert(clue); // 3. 创建数据权限 CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CLUE.getType()) .setBizId(clue.getId()).setUserId(clue.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()); crmPermissionService.createPermission(createReqBO); // 4. 记录操作日志上下文 LogRecordContext.putVariable("clue", clue); return clue.getId(); } @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = CRM_CLUE_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER) public void updateClue(CrmClueSaveReqVO updateReq) { Assert.notNull(updateReq.getId(), "线索编号不能为空"); // 1.1 校验线索是否存在 CrmClueDO oldClue = validateClueExists(updateReq.getId()); // 1.2 校验关联数据 validateRelationDataExists(updateReq); // 2. 更新线索 CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class); clueMapper.updateById(updateObj); // 3. 记录操作日志上下文 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmCustomerSaveReqVO.class)); LogRecordContext.putVariable("clueName", oldClue.getName()); } private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { // 校验负责人 if (Objects.nonNull(reqVO.getOwnerUserId()) && Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()))) { throw exception(USER_NOT_EXISTS); } } @Override @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}}", success = CRM_CLUE_FOLLOW_UP_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) public void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { // 校验线索是否存在 CrmClueDO oldClue = validateClueExists(id); // 更新线索 clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); // 3. 记录操作日志上下文 LogRecordContext.putVariable("clueName", oldClue.getName()); } @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_DELETE_SUB_TYPE, bizNo = "{{#id}}", success = CRM_CLUE_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteClue(Long id) { // 1. 校验存在 CrmClueDO clue = validateClueExists(id); // 2. 删除 clueMapper.deleteById(id); // 3. 删除数据权限 crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CLUE.getType(), id); // 4. 删除跟进 followUpRecordService.deleteFollowUpRecordByBiz(CrmBizTypeEnum.CRM_CLUE.getType(), id); // 5. 记录操作日志上下文 LogRecordContext.putVariable("clueName", clue.getName()); } @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", success = CRM_CLUE_TRANSFER_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { // 1 校验线索是否存在 CrmClueDO clue = validateClueExists(reqVO.getId()); // 2.1 数据权限转移 crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CLUE.getType(), reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置新的负责人 clueMapper.updateById(new CrmClueDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("clue", clue); } @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSLATE_SUB_TYPE, bizNo = "{{#id}}", success = CRM_CLUE_TRANSLATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void transformClue(Long id, Long userId) { // 1.1 校验线索都存在 CrmClueDO clue = validateClueExists(id); // 1.2 存在已经转化的 if (clue.getTransformStatus()) { throw exception(CLUE_TRANSFORM_FAIL_ALREADY); } // 2.1 遍历线索(未转化的线索),创建对应的客户 Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); // 2.2 更新线索 clueMapper.updateById(new CrmClueDO().setId(id).setTransformStatus(Boolean.TRUE).setCustomerId(customerId)); // 2.3 复制跟进记录 List followUpRecords = followUpRecordService.getFollowUpRecordByBiz( CrmBizTypeEnum.CRM_CLUE.getType(), singleton(clue.getId())); if (CollUtil.isNotEmpty(followUpRecords)) { followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, record -> BeanUtils.toBean(record, CrmFollowUpCreateReqBO.class) .setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()).setBizId(customerId))); } // 3. 记录操作日志上下文 LogRecordContext.putVariable("clueName", clue.getName()); } private CrmClueDO validateClueExists(Long id) { CrmClueDO crmClueDO = clueMapper.selectById(id); if (crmClueDO == null) { throw exception(CLUE_NOT_EXISTS); } return crmClueDO; } @Override @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmClueDO getClue(Long id) { return clueMapper.selectById(id); } @Override public PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId) { return clueMapper.selectPage(pageReqVO, userId); } @Override public Long getFollowClueCount(Long userId) { return clueMapper.selectCountByFollow(userId); } }