From 69a974ef02f1ce829dbf20acb9fca72199c12862 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 19 Feb 2024 22:47:28 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=96=20CRM=EF=BC=9A=E7=BA=BF=E7=B4=A2?= =?UTF-8?q?=E7=9A=84=E8=B7=9F=E8=BF=9B=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 3 +- .../module/crm/enums/LogRecordConstants.java | 26 +-- .../crm/enums/common/CrmBizTypeEnum.java | 2 +- .../admin/clue/CrmClueController.java | 22 ++- .../operatelog/CrmOperateLogController.java | 2 +- .../crm/convert/clue/CrmClueConvert.java | 22 --- .../crm/dal/mysql/clue/CrmClueMapper.java | 15 +- .../crm/service/clue/CrmClueService.java | 18 +- .../crm/service/clue/CrmClueServiceImpl.java | 154 +++++++----------- .../CrmFollowUpRecordServiceImpl.java | 4 +- .../bo/CrmPermissionTransferReqBO.java | 4 + 11 files changed, 109 insertions(+), 163 deletions(-) delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/clue/CrmClueConvert.java diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index aa09b2032..29909cf4f 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -16,8 +16,7 @@ public interface ErrorCodeConstants { // ========== 线索管理 1-020-001-000 ========== ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); - ErrorCode CLUE_NOT_EXISTS_ANY = new ErrorCode(1_020_001_001, "线索【{}】不存在"); - ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_002, "线索【{}】已经转化过了,请勿重复转化"); + ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_001, "线索已经转化过了,请勿重复转化"); // ========== 商机管理 1-020-002-000 ========== ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java index 98a66d2c9..6ed048f66 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java @@ -8,19 +8,21 @@ package cn.iocoder.yudao.module.crm.enums; */ public interface LogRecordConstants { - // ======================= CRM_LEADS 线索 ======================= + // ======================= CRM_CLUE 线索 ======================= - String CRM_LEADS_TYPE = "CRM 线索"; - String CRM_LEADS_CREATE_SUB_TYPE = "创建线索"; - String CRM_LEADS_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; - String CRM_LEADS_UPDATE_SUB_TYPE = "更新线索"; - String CRM_LEADS_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; - String CRM_LEADS_DELETE_SUB_TYPE = "删除线索"; - String CRM_LEADS_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; - String CRM_LEADS_TRANSFER_SUB_TYPE = "转移线索"; - String CRM_LEADS_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_LEADS_TRANSLATE_SUB_TYPE = "线索转化为客户"; - String CRM_LEADS_TRANSLATE_SUCCESS = "将线索【{{#clue.name}}】转化为客户"; + String CRM_CLUE_TYPE = "CRM 线索"; + String CRM_CLUE_CREATE_SUB_TYPE = "创建线索"; + String CRM_CLUE_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; + String CRM_CLUE_UPDATE_SUB_TYPE = "更新线索"; + String CRM_CLUE_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; + String CRM_CLUE_DELETE_SUB_TYPE = "删除线索"; + String CRM_CLUE_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; + String CRM_CLUE_TRANSFER_SUB_TYPE = "转移线索"; + String CRM_CLUE_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_CLUE_TRANSLATE_SUB_TYPE = "线索转化为客户"; + String CRM_CLUE_TRANSLATE_SUCCESS = "将线索【{{#clueName}}】转化为客户"; + String CRM_CLUE_FOLLOW_UP_SUB_TYPE = "线索跟进"; + String CRM_CLUE_FOLLOW_UP_SUCCESS = "线索跟进【{{#clueName}}】"; // ======================= CRM_CUSTOMER 客户 ======================= diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java index f0784cab2..8402ad288 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java @@ -17,7 +17,7 @@ import java.util.Arrays; @Getter public enum CrmBizTypeEnum implements IntArrayValuable { - CRM_LEADS(1, "线索"), + CRM_CLUE(1, "线索"), CRM_CUSTOMER(2, "客户"), CRM_CONTACT(3, "联系人"), CRM_BUSINESS(4, "商机"), diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java index 726afc549..044b39d34 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java @@ -9,7 +9,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueRespVO; +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.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; @@ -36,7 +39,8 @@ import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -151,18 +155,18 @@ public class CrmClueController { @PutMapping("/transform") @Operation(summary = "线索转化为客户") - @Parameter(name = "ids", description = "线索编号数组", required = true) + @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('crm:clue:update')") - public CommonResult transformClue(@RequestParam("ids") List ids) { - clueService.transformClue(ids, getLoginUserId()); + public CommonResult transformClue(@RequestParam("id") Long id) { + clueService.transformClue(id, getLoginUserId()); return success(Boolean.TRUE); } - @GetMapping("/follow-leads-count") - @Operation(summary = "获得分配给我的线索数量") + @GetMapping("/follow-count") + @Operation(summary = "获得分配给我的、待跟进的线索数量") @PreAuthorize("@ss.hasPermission('crm:clue:query')") - public CommonResult getFollowLeadsCount() { - return success(clueService.getFollowLeadsCount(getLoginUserId())); + public CommonResult getFollowClueCount() { + return success(clueService.getFollowClueCount(getLoginUserId())); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java index 982ad3c0b..e048d85d8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java @@ -41,7 +41,7 @@ public class CrmOperateLogController { private static final Map BIZ_TYPE_MAP = new HashMap<>(); static { - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_LEADS.getType(), CRM_LEADS_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CLUE.getType(), CRM_CLUE_TYPE); BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CUSTOMER.getType(), CRM_CUSTOMER_TYPE); BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTACT.getType(), CRM_CONTACT_TYPE); BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_BUSINESS.getType(), CRM_BUSINESS_TYPE); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/clue/CrmClueConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/clue/CrmClueConvert.java deleted file mode 100644 index 39e607bcb..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/clue/CrmClueConvert.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.crm.convert.clue; - -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - -/** - * 线索 Convert - * - * @author Wanwan - */ -@Mapper -public interface CrmClueConvert { - - CrmClueConvert INSTANCE = Mappers.getMapper(CrmClueConvert.class); - - @Mapping(target = "bizId", source = "reqVO.id") - CrmPermissionTransferReqBO convert(CrmClueTransferReqVO reqVO, Long userId); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java index 0a23295cc..9d1cae206 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; @@ -22,16 +21,10 @@ import java.util.List; @Mapper public interface CrmClueMapper extends BaseMapperX { - default int updateOwnerUserIdById(Long id, Long ownerUserId) { - return update(new LambdaUpdateWrapper() - .eq(CrmClueDO::getId, id) - .set(CrmClueDO::getOwnerUserId, ownerUserId)); - } - default PageResult selectPage(CrmCluePageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_LEADS.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), CrmClueDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); // 拼接自身的查询条件 query.selectAll(CrmClueDO.class) @@ -50,16 +43,16 @@ public interface CrmClueMapper extends BaseMapperX { default List selectBatchIds(Collection ids, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_LEADS.getType(), ids, userId); + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), ids, userId); query.selectAll(CrmClueDO.class).in(CrmClueDO::getId, ids).orderByDesc(CrmClueDO::getId); // 拼接自身的查询条件 return selectJoinList(CrmClueDO.class, query); } - default Long selectFollowLeadsCount(Long userId) { + default Long selectCountByFollow(Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 - CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_LEADS.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), CrmClueDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); // 未跟进 + 未转化 query.eq(CrmClueDO::getFollowUpStatus, false) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java index 26245bc9c..b84c6d51c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java @@ -5,9 +5,9 @@ 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.dal.dataobject.clue.CrmClueDO; -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; import jakarta.validation.Valid; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -36,9 +36,11 @@ public interface CrmClueService { /** * 更新线索相关的跟进信息 * - * @param clueUpdateFollowUpReqBO 信息 + * @param id 编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 */ - void updateClueFollowUp(CrmUpdateFollowUpReqBO clueUpdateFollowUpReqBO); + void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); /** * 删除线索 @@ -83,17 +85,17 @@ public interface CrmClueService { /** * 线索转化为客户 * - * @param ids 线索编号数组 + * @param id 线索编号 * @param userId 用户编号 */ - void transformClue(List ids, Long userId); + void transformClue(Long id, Long userId); /** - * 获得分配给我的线索数量 + * 获得分配给我的、待跟进的线索数量 * * @param userId 用户编号 - * @return 提醒数量 + * @return 数量 */ - Long getFollowLeadsCount(Long userId); + Long getFollowClueCount(Long userId); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index ee7721593..935524948 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -3,15 +3,12 @@ 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.extra.spring.SpringUtil; 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.CrmCustomerSaveReqVO; -import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert; 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; @@ -25,6 +22,7 @@ import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; 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.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; @@ -37,12 +35,13 @@ import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; -import java.util.Map; 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.*; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +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; @@ -60,18 +59,18 @@ public class CrmClueServiceImpl implements CrmClueService { @Resource private CrmCustomerService customerService; - @Resource private CrmPermissionService crmPermissionService; @Resource private CrmFollowUpRecordService followUpRecordService; + @Resource private AdminUserApi adminUserApi; @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_CREATE_SUB_TYPE, bizNo = "{{#clue.id}}", - success = CRM_LEADS_CREATE_SUCCESS) + @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); @@ -84,7 +83,7 @@ public class CrmClueServiceImpl implements CrmClueService { clueMapper.insert(clue); // 3. 创建数据权限 - CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_LEADS.getType()) + CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CLUE.getType()) .setBizId(clue.getId()).setUserId(clue.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()); crmPermissionService.createPermission(createReqBO); @@ -95,9 +94,9 @@ public class CrmClueServiceImpl implements CrmClueService { @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 = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER) + @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 校验线索是否存在 @@ -114,15 +113,25 @@ public class CrmClueServiceImpl implements CrmClueService { 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_LEADS_TYPE, subType = CRM_LEADS_UPDATE_SUB_TYPE, bizNo = "{{#updateReq.bizId}", - success = CRM_LEADS_UPDATE_SUCCESS) - public void updateClueFollowUp(CrmUpdateFollowUpReqBO updateReq) { + @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(updateReq.getBizId()); + CrmClueDO oldClue = validateClueExists(id); // 更新 - clueMapper.updateById(BeanUtils.toBean(updateReq, CrmClueDO.class).setId(updateReq.getBizId())); + clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) + .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); // 3. 记录操作日志上下文 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmUpdateFollowUpReqBO.class)); @@ -131,9 +140,9 @@ 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) + @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); @@ -142,28 +151,29 @@ public class CrmClueServiceImpl implements CrmClueService { clueMapper.deleteById(id); // 3. 删除数据权限 - crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_LEADS.getType(), id); + crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CLUE.getType(), id); // 4. 删除跟进 - followUpRecordService.deleteFollowUpRecordByBiz(CrmBizTypeEnum.CRM_LEADS.getType(), id); + followUpRecordService.deleteFollowUpRecordByBiz(CrmBizTypeEnum.CRM_CLUE.getType(), id); - // 记录操作日志上下文 + // 5. 记录操作日志上下文 LogRecordContext.putVariable("clueName", clue.getName()); } @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_LEADS_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @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(CrmClueConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_LEADS.getType())); + crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CLUE.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置新的负责人 - clueMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + clueMapper.updateById(new CrmClueDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("clue", clue); @@ -171,69 +181,32 @@ public class CrmClueServiceImpl implements CrmClueService { @Override @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#ids", level = CrmPermissionLevelEnum.OWNER) - public void transformClue(List ids, Long userId) { + @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 校验线索都存在 - List clues = getClueList(ids, userId); - if (CollUtil.isEmpty(clues) || ObjectUtil.notEqual(clues.size(), ids.size())) { - ids.removeAll(convertSet(clues, CrmClueDO::getId)); - throw exception(CLUE_NOT_EXISTS_ANY, ids); - } - // 1.2 存在已经转化的,直接提示哈。避免操作的用户,以为都转化成功了 - List translatedClues = filterList(clues, - clue -> ObjectUtil.equal(Boolean.TRUE, clue.getTransformStatus())); - if (CollUtil.isNotEmpty(translatedClues)) { - throw exception(CLUE_TRANSFORM_FAIL_ALREADY, convertSet(translatedClues, CrmClueDO::getId)); + CrmClueDO clue = validateClueExists(id); + // 1.2 存在已经转化的 + if (clue.getTransformStatus()) { + throw exception(CLUE_TRANSFORM_FAIL_ALREADY); } // 2.1 遍历线索(未转化的线索),创建对应的客户 - clues.forEach(clue -> { - Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); - clue.setCustomerId(customerId); - }); + Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); // 2.2 更新线索 - clueMapper.updateBatch(convertList(clues, clue -> new CrmClueDO().setId(clue.getId()) - .setTransformStatus(Boolean.TRUE).setCustomerId(clue.getCustomerId()))); + clueMapper.updateById(new CrmClueDO().setId(id).setTransformStatus(Boolean.TRUE).setCustomerId(customerId)); // 2.3 复制跟进记录 - copyFollowUpRecords(clues); - - // 3. 记录操作日志 - for (CrmClueDO clue : clues) { - getSelf().translateCustomerLog(clue); - } - } - - /** - * 线索被转换客户后,需要将线索的跟进记录,复制到客户上 - * - * @param clues 被转化的线索 - */ - private void copyFollowUpRecords(List clues) { List followUpRecords = followUpRecordService.getFollowUpRecordByBiz( - CrmBizTypeEnum.CRM_LEADS.getType(), convertSet(clues, CrmClueDO::getId)); - if (CollUtil.isEmpty(followUpRecords)) { - return; + 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))); } - // 创建跟进 - Map clueMap = convertMap(clues, CrmClueDO::getId); - followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, followUpRecord -> - BeanUtils.toBean(followUpRecord, CrmFollowUpCreateReqBO.class).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) - .setBizId(clueMap.get(followUpRecord.getBizId()).getCustomerId()))); - } - @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSLATE_SUB_TYPE, bizNo = "{{#clue.id}}", - success = CRM_LEADS_TRANSLATE_SUCCESS) - public void translateCustomerLog(CrmClueDO clue) { - // 记录操作日志上下文 - LogRecordContext.putVariable("clue", clue); - } - - private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { - // 校验负责人 - if (Objects.nonNull(reqVO.getOwnerUserId()) && - Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()))) { - throw exception(USER_NOT_EXISTS); - } + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("clueName", clue.getName()); } private CrmClueDO validateClueExists(Long id) { @@ -245,7 +218,7 @@ public class CrmClueServiceImpl implements CrmClueService { } @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.READ) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmClueDO getClue(Long id) { return clueMapper.selectById(id); } @@ -263,18 +236,9 @@ public class CrmClueServiceImpl implements CrmClueService { return clueMapper.selectPage(pageReqVO, userId); } - /** - * 获得自身的代理对象,解决 AOP 生效问题 - * - * @return 自己 - */ - private CrmClueServiceImpl getSelf() { - return SpringUtil.getBean(getClass()); - } - @Override - public Long getFollowLeadsCount(Long userId) { - return clueMapper.selectFollowLeadsCount(userId); + public Long getFollowClueCount(Long userId) { + return clueMapper.selectCountByFollow(userId); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java index 88f0b887c..5cfdbb1dc 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java @@ -79,8 +79,8 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_BUSINESS.getType(), followUpRecord.getBizType())) { // 更新商机跟进信息 businessService.updateBusinessFollowUpBatch(Collections.singletonList(updateFollowUpReqBO)); } - if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_LEADS.getType(), followUpRecord.getBizType())) { // 更新线索跟进信息 - clueService.updateClueFollowUp(updateFollowUpReqBO); + if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CLUE.getType(), followUpRecord.getBizType())) { // 更新线索跟进信息 + clueService.updateClueFollowUp(followUpRecord.getId(), followUpRecord.getNextTime(), followUpRecord.getContent()); } if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CONTACT.getType(), followUpRecord.getBizType())) { // 更新联系人跟进信息 contactService.updateContactFollowUpBatch(Collections.singletonList(updateFollowUpReqBO)); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java index 0e5933c0c..52f8a977a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.crm.service.permission.bo; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import lombok.AllArgsConstructor; import lombok.Data; import jakarta.validation.constraints.NotNull; +import lombok.NoArgsConstructor; /** * 数据权限转移 Request BO @@ -13,6 +15,8 @@ import jakarta.validation.constraints.NotNull; * @author HUIHUI */ @Data +@NoArgsConstructor +@AllArgsConstructor public class CrmPermissionTransferReqBO { /**