Commit cd28128e42f8883e55e8a7a0d50f339fa930d43e
Committed by
Gitee
!859 feat: CRM-backlog-待进入公海的客户
Merge pull request !859 from dhb52/crm-msg
Showing
5 changed files
with
97 additions
and
3 deletions
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
| ... | ... | @@ -26,8 +26,8 @@ public interface ErrorCodeConstants { |
| 26 | 26 | |
| 27 | 27 | // ========== 联系人管理 1-020-003-000 ========== |
| 28 | 28 | ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); |
| 29 | - ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode( 1_020_003_001, "联系人商机关联不存在"); | |
| 30 | - ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode( 1_020_003_002, "联系人已关联合同,不能删除"); | |
| 29 | + ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在"); | |
| 30 | + ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); | |
| 31 | 31 | |
| 32 | 32 | // ========== 回款 1-020-004-000 ========== |
| 33 | 33 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); |
| ... | ... | @@ -80,7 +80,8 @@ public interface ErrorCodeConstants { |
| 80 | 80 | ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_011_000, "商机状态不存在"); |
| 81 | 81 | |
| 82 | 82 | // ========== 客户公海规则设置 1_020_012_000 ========== |
| 83 | - ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_000, "客户限制配置不存在"); | |
| 83 | + ErrorCode CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_020_012_000, "客户公海配置不存在或未启用"); | |
| 84 | + ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); | |
| 84 | 85 | |
| 85 | 86 | // ========== 跟进记录 1_020_013_000 ========== |
| 86 | 87 | ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
| ... | ... | @@ -36,11 +36,13 @@ import java.util.List; |
| 36 | 36 | import java.util.Map; |
| 37 | 37 | import java.util.stream.Stream; |
| 38 | 38 | |
| 39 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 39 | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 40 | 41 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 41 | 42 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 42 | 43 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 43 | 44 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 45 | +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED; | |
| 44 | 46 | |
| 45 | 47 | @Tag(name = "管理后台 - CRM 客户") |
| 46 | 48 | @RestController |
| ... | ... | @@ -118,6 +120,35 @@ public class CrmCustomerController { |
| 118 | 120 | return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); |
| 119 | 121 | } |
| 120 | 122 | |
| 123 | + | |
| 124 | + @GetMapping("/put-in-pool-remind-page") | |
| 125 | + @Operation(summary = "获得待进入公海客户分页") | |
| 126 | + @PreAuthorize("@ss.hasPermission('crm:customer:query')") | |
| 127 | + public CommonResult<PageResult<CrmCustomerRespVO>> getPutInPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { | |
| 128 | + // 获取公海配置 | |
| 129 | + CrmCustomerPoolConfigDO poolConfigDO = customerPoolConfigService.getCustomerPoolConfig(); | |
| 130 | + if (ObjUtil.isNull(poolConfigDO) | |
| 131 | + || Boolean.FALSE.equals(poolConfigDO.getEnabled()) | |
| 132 | + || Boolean.FALSE.equals(poolConfigDO.getNotifyEnabled()) | |
| 133 | + ) { | |
| 134 | + throw exception(CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED); | |
| 135 | + } | |
| 136 | + | |
| 137 | + // 1. 查询客户分页 | |
| 138 | + PageResult<CrmCustomerDO> pageResult = customerService.getPutInPoolRemindCustomerPage(pageVO, poolConfigDO, getLoginUserId()); | |
| 139 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 140 | + return success(PageResult.empty(pageResult.getTotal())); | |
| 141 | + } | |
| 142 | + | |
| 143 | + // 2. 拼接数据 | |
| 144 | + Map<Long, Long> poolDayMap = getPoolDayMap(pageResult.getList()); // 客户界面,需要查看距离进入公海的时间 | |
| 145 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | |
| 146 | + convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId()))); | |
| 147 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | |
| 148 | + | |
| 149 | + return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); | |
| 150 | + } | |
| 151 | + | |
| 121 | 152 | /** |
| 122 | 153 | * 获取距离进入公海的时间 |
| 123 | 154 | * | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
| ... | ... | @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; |
| 8 | 8 | import cn.iocoder.yudao.module.crm.controller.admin.backlog.vo.CrmTodayCustomerPageReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 11 | +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | |
| 11 | 12 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| 12 | 13 | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; |
| 13 | 14 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| ... | ... | @@ -107,4 +108,55 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> { |
| 107 | 108 | .isNotNull(CrmCustomerDO::getOwnerUserId)); |
| 108 | 109 | } |
| 109 | 110 | |
| 111 | + default PageResult<CrmCustomerDO> selectPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO, | |
| 112 | + CrmCustomerPoolConfigDO poolConfigDO, | |
| 113 | + Long userId) { | |
| 114 | + MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>(); | |
| 115 | + // 拼接数据权限的查询条件 | |
| 116 | + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), | |
| 117 | + CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), null); | |
| 118 | + | |
| 119 | + // 拼接自身的查询条件 | |
| 120 | + query.selectAll(CrmCustomerDO.class); | |
| 121 | + | |
| 122 | + // 未跟进放入公海天数 | |
| 123 | + final Integer contactExpireDays = poolConfigDO.getContactExpireDays(); | |
| 124 | + // 未成交放入公海天数 | |
| 125 | + final Integer dealExpireDays = poolConfigDO.getDealExpireDays(); | |
| 126 | + // 提前提醒天数 | |
| 127 | + final Integer notifyDays = poolConfigDO.getNotifyDays(); | |
| 128 | + | |
| 129 | + // 未成交提醒日期区间 | |
| 130 | + // dealExpireDays 开始提醒 | |
| 131 | + LocalDateTime startDealRemindDate = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()) | |
| 132 | + .minusDays(dealExpireDays); | |
| 133 | + // dealExpireDays - notifyDays 结束提醒 | |
| 134 | + LocalDateTime endDealRemindDate = LocalDateTimeUtil.endOfDay(LocalDateTime.now()) | |
| 135 | + .minusDays(Math.max(dealExpireDays - notifyDays, 0)); | |
| 136 | + | |
| 137 | + // 未跟进提醒日期区间 | |
| 138 | + // contactExpireDays 开始提醒 | |
| 139 | + LocalDateTime startContactRemindDate = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()) | |
| 140 | + .minusDays(contactExpireDays); | |
| 141 | + // contactExpireDays - notifyDays 结束提醒 | |
| 142 | + LocalDateTime endContactRemindDate = LocalDateTimeUtil.endOfDay(LocalDateTime.now()) | |
| 143 | + .minusDays(Math.max(contactExpireDays - notifyDays, 0)); | |
| 144 | + | |
| 145 | + query | |
| 146 | + // 1.1 未成交放入公海提醒 | |
| 147 | + .eq(CrmCustomerDO::getDealStatus, false) | |
| 148 | + .between(CrmCustomerDO::getCreateTime, startDealRemindDate, endDealRemindDate) | |
| 149 | + .or() | |
| 150 | + // 1.2 未跟进放入公海提醒 | |
| 151 | + // 1.2.1 ContactLastTime 为空 | |
| 152 | + .isNull(CrmCustomerDO::getContactLastTime) | |
| 153 | + .between(CrmCustomerDO::getCreateTime, startContactRemindDate, endContactRemindDate) | |
| 154 | + .or() | |
| 155 | + // 1.2.2 ContactLastTime 不为空 | |
| 156 | + .between(CrmCustomerDO::getContactLastTime, startContactRemindDate, endContactRemindDate) | |
| 157 | + ; | |
| 158 | + | |
| 159 | + return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); | |
| 160 | + } | |
| 161 | + | |
| 110 | 162 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageR |
| 6 | 6 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 9 | +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | |
| 9 | 10 | import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; |
| 10 | 11 | import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; |
| 11 | 12 | import jakarta.validation.Valid; |
| ... | ... | @@ -134,4 +135,7 @@ public interface CrmCustomerService { |
| 134 | 135 | */ |
| 135 | 136 | int customerAutoPutPoolBySystem(); |
| 136 | 137 | |
| 138 | + PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, | |
| 139 | + CrmCustomerPoolConfigDO poolConfigDO, | |
| 140 | + Long loginUserId); | |
| 137 | 141 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
| ... | ... | @@ -387,6 +387,12 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { |
| 387 | 387 | return customerMapper.selectPage(pageReqVO, userId); |
| 388 | 388 | } |
| 389 | 389 | |
| 390 | + public PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO, | |
| 391 | + CrmCustomerPoolConfigDO poolConfigDO, | |
| 392 | + Long userId) { | |
| 393 | + return customerMapper.selectPutInPoolRemindCustomerPage(pageReqVO, poolConfigDO, userId); | |
| 394 | + } | |
| 395 | + | |
| 390 | 396 | // ======================= 校验相关 ======================= |
| 391 | 397 | |
| 392 | 398 | /** | ... | ... |