Commit 4b41c3c69230cc49913c7612f29bc5abfab69dc0

Authored by YunaiV
1 parent b444312e

✨ CRM:优化客户的 backlog 逻辑

yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
... ... @@ -174,15 +174,15 @@ public class CrmCustomerController {
174 174 return success(customerService.getPutPoolRemindCustomerCount(getLoginUserId()));
175 175 }
176 176  
177   - @GetMapping("/today-customer-count")
  177 + @GetMapping("/today-contact-count")
178 178 @Operation(summary = "获得今日需联系客户数量")
179 179 @PreAuthorize("@ss.hasPermission('crm:customer:query')")
180   - public CommonResult<Long> getTodayCustomerCount() {
181   - return success(customerService.getTodayCustomerCount(getLoginUserId()));
  180 + public CommonResult<Long> getTodayContactCustomerCount() {
  181 + return success(customerService.getTodayContactCustomerCount(getLoginUserId()));
182 182 }
183 183  
184   - @GetMapping("/follow-customer-count")
185   - @Operation(summary = "获得分配给我的客户数量")
  184 + @GetMapping("/follow-count")
  185 + @Operation(summary = "获得分配给我、待跟进的线索数量的客户数量")
186 186 @PreAuthorize("@ss.hasPermission('crm:customer:query')")
187 187 public CommonResult<Long> getFollowCustomerCount() {
188 188 return success(customerService.getFollowCustomerCount(getLoginUserId()));
... ... @@ -222,9 +222,9 @@ public class CrmCustomerController {
222 222 });
223 223 }
224 224  
225   - @GetMapping(value = "/list-all-simple")
  225 + @GetMapping(value = "/simple-list")
226 226 @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项")
227   - public CommonResult<List<CrmCustomerRespVO>> getSimpleDeptList() {
  227 + public CommonResult<List<CrmCustomerRespVO>> getCustomerSimpleList() {
228 228 CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO();
229 229 reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页
230 230 List<CrmCustomerDO> list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList();
... ... @@ -232,7 +232,6 @@ public class CrmCustomerController {
232 232 new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName())));
233 233 }
234 234  
235   - // TODO @puhui999:公海的导出,前端可以接下
236 235 @GetMapping("/export-excel")
237 236 @Operation(summary = "导出客户 Excel")
238 237 @PreAuthorize("@ss.hasPermission('crm:customer:export')")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
... ... @@ -49,11 +49,11 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
49 49 .set(CrmCustomerDO::getOwnerUserId, ownerUserId));
50 50 }
51 51  
52   - default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
  52 + default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) {
53 53 MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
54 54 // 拼接数据权限的查询条件
55 55 CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
56   - CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool());
  56 + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), pageReqVO.getPool());
57 57 // 拼接自身的查询条件
58 58 query.selectAll(CrmCustomerDO.class)
59 59 .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
... ... @@ -81,10 +81,10 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
81 81 return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
82 82 }
83 83  
84   - default List<CrmCustomerDO> selectBatchIds(Collection<Long> ids, Long userId) {
  84 + default List<CrmCustomerDO> selectBatchIds(Collection<Long> ids, Long ownerUserId) {
85 85 MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
86 86 // 拼接数据权限的查询条件
87   - CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, userId);
  87 + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, ownerUserId);
88 88 // 拼接自身的查询条件
89 89 query.selectAll(CrmCustomerDO.class).in(CrmCustomerDO::getId, ids).orderByDesc(CrmCustomerDO::getId);
90 90 return selectJoinList(CrmCustomerDO.class, query);
... ... @@ -96,8 +96,8 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
96 96  
97 97 default PageResult<CrmCustomerDO> selectPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
98 98 CrmCustomerPoolConfigDO poolConfig,
99   - Long userId) {
100   - final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, userId);
  99 + Long ownerUserId) {
  100 + final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, ownerUserId);
101 101 return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class));
102 102 }
103 103  
... ... @@ -110,11 +110,11 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
110 110  
111 111 private static MPJLambdaWrapperX<CrmCustomerDO> buildPutPoolRemindCustomerQuery(CrmCustomerPageReqVO pageReqVO,
112 112 CrmCustomerPoolConfigDO poolConfig,
113   - Long userId) {
  113 + Long ownerUserId) {
114 114 MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
115 115 // 拼接数据权限的查询条件
116 116 CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
117   - CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), null);
  117 + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), null);
118 118  
119 119 // 未锁定 + 未成交
120 120 query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false);
... ... @@ -164,11 +164,11 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
164 164 return selectList(query);
165 165 }
166 166  
167   - default Long selectTodayCustomerCount(Long userId) {
  167 + default Long selectCountByTodayContact(Long ownerUserId) {
168 168 MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
169 169 // 我负责的 + 非公海
170 170 CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
171   - CrmCustomerDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE);
  171 + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE);
172 172 // 今天需联系
173 173 LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
174 174 LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
... ... @@ -176,11 +176,11 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
176 176 return selectCount(query);
177 177 }
178 178  
179   - default Long selectFollowCustomerCount(Long userId) {
  179 + default Long selectCountByFollow(Long ownerUserId) {
180 180 MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
181 181 // 我负责的 + 非公海
182 182 CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
183   - CrmCustomerDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE);
  183 + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE);
184 184 // 未跟进
185 185 query.eq(CrmClueDO::getFollowUpStatus, false);
186 186 return selectCount(query);
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
... ... @@ -114,6 +114,22 @@ public interface CrmCustomerService {
114 114 Long getPutPoolRemindCustomerCount(Long userId);
115 115  
116 116 /**
  117 + * 获得今日需联系客户数量
  118 + *
  119 + * @param userId 用户编号
  120 + * @return 提醒数量
  121 + */
  122 + Long getTodayContactCustomerCount(Long userId);
  123 +
  124 + /**
  125 + * 获得分配给我的客户数量
  126 + *
  127 + * @param userId 用户编号
  128 + * @return 提醒数量
  129 + */
  130 + Long getFollowCustomerCount(Long userId);
  131 +
  132 + /**
117 133 * 校验客户是否存在
118 134 *
119 135 * @param customerId 客户 id
... ... @@ -168,7 +184,7 @@ public interface CrmCustomerService {
168 184 *
169 185 * @param ids 要领取的客户编号数组
170 186 * @param ownerUserId 负责人
171   - * @param isReceive 是/否领取
  187 + * @param isReceive 是/否领取;true - 领取;false - 分配
172 188 */
173 189 void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
174 190  
... ... @@ -179,20 +195,4 @@ public interface CrmCustomerService {
179 195 */
180 196 int autoPutCustomerPool();
181 197  
182   - /**
183   - * 获得今日需联系客户数量
184   - *
185   - * @param userId 用户编号
186   - * @return 提醒数量
187   - */
188   - Long getTodayCustomerCount(Long userId);
189   -
190   - /**
191   - * 获得分配给我的客户数量
192   - *
193   - * @param userId 用户编号
194   - * @return 提醒数量
195   - */
196   - Long getFollowCustomerCount(Long userId);
197   -
198 198 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
... ... @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
18 18 import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
19 19 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
20 20 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
21   -import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils;
22 21 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
23 22 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
24 23 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
... ... @@ -191,23 +190,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
191 190 LogRecordContext.putVariable("customerName", customer.getName());
192 191 }
193 192  
194   - /**
195   - * 校验客户是否被引用
196   - *
197   - * @param id 客户编号
198   - */
199   - private void validateCustomerReference(Long id) {
200   - if (contactService.getContactCountByCustomerId(id) > 0) {
201   - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTACT.getName());
202   - }
203   - if (businessService.getBusinessCountByCustomerId(id) > 0) {
204   - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_BUSINESS.getName());
205   - }
206   - if (contractService.getContractCountByCustomerId(id) > 0) {
207   - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTRACT.getName());
208   - }
209   - }
210   -
211 193 @Override
212 194 @Transactional(rollbackFor = Exception.class)
213 195 @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}",
... ... @@ -336,13 +318,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
336 318 LogRecordContext.putVariable("isUpdate", isUpdate);
337 319 }
338 320  
339   - private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
340   - // 校验客户名称不能为空
341   - if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
342   - throw exception(CUSTOMER_CREATE_NAME_NOT_NULL);
343   - }
344   - }
345   -
346 321 // ==================== 公海相关操作 ====================
347 322  
348 323 @Override
... ... @@ -371,18 +346,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
371 346 @Override
372 347 @Transactional(rollbackFor = Exception.class)
373 348 public void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive) {
374   - if (!isReceive && !CrmPermissionUtils.isCrmAdmin()) { // 只有管理员可以分配
375   - throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.CRM_CUSTOMER.getName());
376   - }
377   -
378 349 // 1.1 校验存在
379 350 List<CrmCustomerDO> customers = customerMapper.selectBatchIds(ids);
380 351 if (customers.size() != ids.size()) {
381 352 throw exception(CUSTOMER_NOT_EXISTS);
382 353 }
383   - // 1.2. 校验负责人是否存在
  354 + // 1.2 校验负责人是否存在
384 355 adminUserApi.validateUserList(singletonList(ownerUserId));
385   - // 1.3. 校验状态
  356 + // 1.3 校验状态
386 357 customers.forEach(customer -> {
387 358 // 校验是否已有负责人
388 359 validateCustomerOwnerExists(customer, false);
... ... @@ -513,17 +484,41 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
513 484 }
514 485  
515 486 @Override
516   - public Long getTodayCustomerCount(Long userId) {
517   - return customerMapper.selectTodayCustomerCount(userId);
  487 + public Long getTodayContactCustomerCount(Long userId) {
  488 + return customerMapper.selectCountByTodayContact(userId);
518 489 }
519 490  
520 491 @Override
521 492 public Long getFollowCustomerCount(Long userId) {
522   - return customerMapper.selectFollowCustomerCount(userId);
  493 + return customerMapper.selectCountByFollow(userId);
523 494 }
524 495  
525 496 // ======================= 校验相关 =======================
526 497  
  498 + private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
  499 + // 校验客户名称不能为空
  500 + if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
  501 + throw exception(CUSTOMER_CREATE_NAME_NOT_NULL);
  502 + }
  503 + }
  504 +
  505 + /**
  506 + * 校验客户是否被引用
  507 + *
  508 + * @param id 客户编号
  509 + */
  510 + private void validateCustomerReference(Long id) {
  511 + if (contactService.getContactCountByCustomerId(id) > 0) {
  512 + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTACT.getName());
  513 + }
  514 + if (businessService.getBusinessCountByCustomerId(id) > 0) {
  515 + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_BUSINESS.getName());
  516 + }
  517 + if (contractService.getContractCountByCustomerId(id) > 0) {
  518 + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTRACT.getName());
  519 + }
  520 + }
  521 +
527 522 /**
528 523 * 校验客户是否存在
529 524 *
... ...