Commit 5d8ca19b175019fb5b45e6084f98bd6288e8c09c
1 parent
6e005f46
feat: CRM-backlog-待进入公海的客户
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,8 +26,8 @@ public interface ErrorCodeConstants { | ||
| 26 | 26 | ||
| 27 | // ========== 联系人管理 1-020-003-000 ========== | 27 | // ========== 联系人管理 1-020-003-000 ========== |
| 28 | ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); | 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 | // ========== 回款 1-020-004-000 ========== | 32 | // ========== 回款 1-020-004-000 ========== |
| 33 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); | 33 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); |
| @@ -80,7 +80,8 @@ public interface ErrorCodeConstants { | @@ -80,7 +80,8 @@ public interface ErrorCodeConstants { | ||
| 80 | ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_011_000, "商机状态不存在"); | 80 | ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_011_000, "商机状态不存在"); |
| 81 | 81 | ||
| 82 | // ========== 客户公海规则设置 1_020_012_000 ========== | 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 | // ========== 跟进记录 1_020_013_000 ========== | 86 | // ========== 跟进记录 1_020_013_000 ========== |
| 86 | ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); | 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,11 +36,13 @@ import java.util.List; | ||
| 36 | import java.util.Map; | 36 | import java.util.Map; |
| 37 | import java.util.stream.Stream; | 37 | import java.util.stream.Stream; |
| 38 | 38 | ||
| 39 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 40 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 41 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 41 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 42 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 42 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 43 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 43 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 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 | @Tag(name = "管理后台 - CRM 客户") | 47 | @Tag(name = "管理后台 - CRM 客户") |
| 46 | @RestController | 48 | @RestController |
| @@ -118,6 +120,35 @@ public class CrmCustomerController { | @@ -118,6 +120,35 @@ public class CrmCustomerController { | ||
| 118 | return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); | 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,6 +8,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; | ||
| 8 | import cn.iocoder.yudao.module.crm.controller.admin.backlog.vo.CrmTodayCustomerPageReqVO; | 8 | import cn.iocoder.yudao.module.crm.controller.admin.backlog.vo.CrmTodayCustomerPageReqVO; |
| 9 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; | 9 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; |
| 10 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 10 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 11 | +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | ||
| 11 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | 12 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| 12 | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; | 13 | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; |
| 13 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 14 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| @@ -107,4 +108,55 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> { | @@ -107,4 +108,55 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> { | ||
| 107 | .isNotNull(CrmCustomerDO::getOwnerUserId)); | 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 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageR | ||
| 6 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; | 6 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; |
| 7 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; | 7 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; |
| 8 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 8 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 9 | +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | ||
| 9 | import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; | 10 | import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; |
| 10 | import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; | 11 | import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; |
| 11 | import jakarta.validation.Valid; | 12 | import jakarta.validation.Valid; |
| @@ -134,4 +135,7 @@ public interface CrmCustomerService { | @@ -134,4 +135,7 @@ public interface CrmCustomerService { | ||
| 134 | */ | 135 | */ |
| 135 | int customerAutoPutPoolBySystem(); | 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,6 +387,12 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||
| 387 | return customerMapper.selectPage(pageReqVO, userId); | 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 | /** |