mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-19 03:30:06 +08:00
✨ CRM:优化客户的过期到公海的逻辑
This commit is contained in:
parent
3e6524932b
commit
b444312ea8
@ -45,6 +45,8 @@ public interface LogRecordConstants {
|
|||||||
String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}";
|
String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}";
|
||||||
String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE = "更新客户成交状态";
|
String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE = "更新客户成交状态";
|
||||||
String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS = "更新了客户【{{#customerName}}】的成交状态为【{{#dealStatus ? '已成交' : '未成交'}}】";
|
String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS = "更新了客户【{{#customerName}}】的成交状态为【{{#dealStatus ? '已成交' : '未成交'}}】";
|
||||||
|
String CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE = "客户跟进";
|
||||||
|
String CRM_CUSTOMER_FOLLOW_UP_SUCCESS = "客户跟进【{{#customerName}}】";
|
||||||
|
|
||||||
// ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 =======================
|
// ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 =======================
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
|
|||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
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.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 线索")
|
@Tag(name = "管理后台 - 线索")
|
||||||
@RestController
|
@RestController
|
||||||
@ -93,11 +94,11 @@ public class CrmClueController {
|
|||||||
return success(buildClueDetail(clue));
|
return success(buildClueDetail(clue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CrmClueRespVO buildClueDetail(CrmClueDO clue) {
|
private CrmClueRespVO buildClueDetail(CrmClueDO clue) {
|
||||||
if (clue == null) {
|
if (clue == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return buildClueDetailList(Collections.singletonList(clue)).get(0);
|
return buildClueDetailList(singletonList(clue)).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
|
@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
@ -15,7 +15,6 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
|||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService;
|
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService;
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
||||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
@ -40,13 +39,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
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.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.*;
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED;
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - CRM 客户")
|
@Tag(name = "管理后台 - CRM 客户")
|
||||||
@ -123,6 +120,7 @@ public class CrmCustomerController {
|
|||||||
@Operation(summary = "获得客户分页")
|
@Operation(summary = "获得客户分页")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
||||||
public CommonResult<PageResult<CrmCustomerRespVO>> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
|
public CommonResult<PageResult<CrmCustomerRespVO>> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
|
||||||
|
customerService.autoPutCustomerPool();
|
||||||
// 1. 查询客户分页
|
// 1. 查询客户分页
|
||||||
PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId());
|
PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId());
|
||||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||||
@ -159,45 +157,21 @@ public class CrmCustomerController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @芋艿:需要 review 下
|
@GetMapping("/put-pool-remind-page")
|
||||||
@GetMapping("/put-in-pool-remind-page")
|
|
||||||
@Operation(summary = "获得待进入公海客户分页")
|
@Operation(summary = "获得待进入公海客户分页")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
||||||
public CommonResult<PageResult<CrmCustomerRespVO>> getPutInPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
|
public CommonResult<PageResult<CrmCustomerRespVO>> getPutPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
|
||||||
// 获取公海配置 TODO @dbh52:合并到 getPutInPoolRemindCustomerPage 会更合适哈;
|
|
||||||
CrmCustomerPoolConfigDO poolConfigDO = customerPoolConfigService.getCustomerPoolConfig();
|
|
||||||
if (ObjUtil.isNull(poolConfigDO)
|
|
||||||
|| Boolean.FALSE.equals(poolConfigDO.getEnabled())
|
|
||||||
|| Boolean.FALSE.equals(poolConfigDO.getNotifyEnabled())) {
|
|
||||||
throw exception(CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 查询客户分页
|
// 1. 查询客户分页
|
||||||
PageResult<CrmCustomerDO> pageResult = customerService.getPutInPoolRemindCustomerPage(pageVO, poolConfigDO, getLoginUserId());
|
PageResult<CrmCustomerDO> pageResult = customerService.getPutPoolRemindCustomerPage(pageVO, getLoginUserId());
|
||||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
|
||||||
return success(PageResult.empty(pageResult.getTotal()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 拼接数据
|
// 2. 拼接数据
|
||||||
return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal()));
|
return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/put-in-pool-remind-count")
|
@GetMapping("/put-pool-remind-count")
|
||||||
@Operation(summary = "获得待进入公海客户数量")
|
@Operation(summary = "获得待进入公海客户数量")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
@PreAuthorize("@ss.hasPermission('crm:customer:query')")
|
||||||
public CommonResult<Long> getPutInPoolRemindCustomerCount() {
|
public CommonResult<Long> getPutPoolRemindCustomerCount() {
|
||||||
// 获取公海配置
|
return success(customerService.getPutPoolRemindCustomerCount(getLoginUserId()));
|
||||||
CrmCustomerPoolConfigDO poolConfigDO = customerPoolConfigService.getCustomerPoolConfig();
|
|
||||||
if (ObjUtil.isNull(poolConfigDO)
|
|
||||||
|| Boolean.FALSE.equals(poolConfigDO.getEnabled())
|
|
||||||
|| Boolean.FALSE.equals(poolConfigDO.getNotifyEnabled())) {
|
|
||||||
throw exception(CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED);
|
|
||||||
}
|
|
||||||
CrmCustomerPageReqVO pageVO = new CrmCustomerPageReqVO()
|
|
||||||
.setPool(null)
|
|
||||||
.setContactStatus(CrmCustomerPageReqVO.CONTACT_TODAY)
|
|
||||||
.setSceneType(CrmSceneTypeEnum.OWNER.getType());
|
|
||||||
return success(customerService.getPutInPoolRemindCustomerCount(pageVO, poolConfigDO, getLoginUserId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/today-customer-count")
|
@GetMapping("/today-customer-count")
|
||||||
@ -225,24 +199,26 @@ public class CrmCustomerController {
|
|||||||
if (poolConfig == null || !poolConfig.getEnabled()) {
|
if (poolConfig == null || !poolConfig.getEnabled()) {
|
||||||
return MapUtil.empty();
|
return MapUtil.empty();
|
||||||
}
|
}
|
||||||
|
list = CollectionUtils.filterList(list, customer -> {
|
||||||
|
// 特殊:如果没负责人,则说明已经在公海,不用计算
|
||||||
|
if (customer.getOwnerUserId() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 已成交 or 已锁定,不进入公海
|
||||||
|
return !customer.getDealStatus() && !customer.getLockStatus();
|
||||||
|
});
|
||||||
return convertMap(list, CrmCustomerDO::getId, customer -> {
|
return convertMap(list, CrmCustomerDO::getId, customer -> {
|
||||||
// TODO 芋艿:这样计算,貌似有点问题
|
|
||||||
// 1.1 未成交放入公海天数
|
// 1.1 未成交放入公海天数
|
||||||
long dealExpireDay = 0;
|
long dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getOwnerTime());
|
||||||
if (!customer.getDealStatus()) {
|
|
||||||
dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime());
|
|
||||||
}
|
|
||||||
if (dealExpireDay < 0) {
|
|
||||||
dealExpireDay = 0;
|
|
||||||
}
|
|
||||||
// 1.2 未跟进放入公海天数
|
// 1.2 未跟进放入公海天数
|
||||||
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
|
LocalDateTime lastTime = customer.getOwnerTime();
|
||||||
long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime);
|
if (customer.getContactLastTime() != null && customer.getContactLastTime().isAfter(lastTime)) {
|
||||||
if (contactExpireDay < 0) {
|
lastTime = customer.getContactLastTime();
|
||||||
contactExpireDay = 0;
|
|
||||||
}
|
}
|
||||||
|
long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime);
|
||||||
// 2. 返回最小的天数
|
// 2. 返回最小的天数
|
||||||
return Math.min(dealExpireDay, contactExpireDay);
|
long poolDay = Math.min(dealExpireDay, contactExpireDay);
|
||||||
|
return poolDay > 0 ? poolDay : 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,10 @@ public class CrmCustomerDO extends BaseDO {
|
|||||||
* 关联 AdminUserDO 的 id 字段
|
* 关联 AdminUserDO 的 id 字段
|
||||||
*/
|
*/
|
||||||
private Long ownerUserId;
|
private Long ownerUserId;
|
||||||
|
/**
|
||||||
|
* 成为负责人的时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime ownerTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 锁定状态
|
* 锁定状态
|
||||||
|
@ -31,40 +31,6 @@ import java.util.List;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
||||||
|
|
||||||
private static MPJLambdaWrapperX<CrmCustomerDO> buildPutInPoolRemindCustomerWrapper(CrmCustomerPageReqVO pageReqVO, CrmCustomerPoolConfigDO poolConfigDO, Long userId) {
|
|
||||||
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
|
||||||
// 拼接数据权限的查询条件
|
|
||||||
CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
|
|
||||||
CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), null);
|
|
||||||
|
|
||||||
// 锁定状态不需要提醒
|
|
||||||
query.ne(CrmCustomerDO::getLockStatus, true);
|
|
||||||
|
|
||||||
// 情况一:未成交提醒日期区间
|
|
||||||
Integer dealExpireDays = poolConfigDO.getDealExpireDays();
|
|
||||||
LocalDateTime startDealRemindDate = LocalDateTimeUtil.beginOfDay(LocalDateTime.now())
|
|
||||||
.minusDays(dealExpireDays);
|
|
||||||
LocalDateTime endDealRemindDate = LocalDateTimeUtil.endOfDay(LocalDateTime.now())
|
|
||||||
.minusDays(Math.max(dealExpireDays - poolConfigDO.getNotifyDays(), 0));
|
|
||||||
// 情况二:未跟进提醒日期区间
|
|
||||||
Integer contactExpireDays = poolConfigDO.getContactExpireDays();
|
|
||||||
LocalDateTime startContactRemindDate = LocalDateTimeUtil.beginOfDay(LocalDateTime.now())
|
|
||||||
.minusDays(contactExpireDays);
|
|
||||||
LocalDateTime endContactRemindDate = LocalDateTimeUtil.endOfDay(LocalDateTime.now())
|
|
||||||
.minusDays(Math.max(contactExpireDays - poolConfigDO.getNotifyDays(), 0));
|
|
||||||
query
|
|
||||||
// 情况一:1. 未成交放入公海提醒
|
|
||||||
.eq(CrmCustomerDO::getDealStatus, false)
|
|
||||||
.between(CrmCustomerDO::getCreateTime, startDealRemindDate, endDealRemindDate)
|
|
||||||
// 情况二:未跟进放入公海提醒
|
|
||||||
.or() // 2.1 contactLastTime 为空 TODO 芋艿:这个要不要搞个默认值;
|
|
||||||
.isNull(CrmCustomerDO::getContactLastTime)
|
|
||||||
.between(CrmCustomerDO::getCreateTime, startContactRemindDate, endContactRemindDate)
|
|
||||||
.or() // 2.2 ContactLastTime 不为空
|
|
||||||
.between(CrmCustomerDO::getContactLastTime, startContactRemindDate, endContactRemindDate);
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) {
|
default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) {
|
||||||
return selectCount(new LambdaUpdateWrapper<CrmCustomerDO>()
|
return selectCount(new LambdaUpdateWrapper<CrmCustomerDO>()
|
||||||
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
||||||
@ -124,30 +90,80 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
|||||||
return selectJoinList(CrmCustomerDO.class, query);
|
return selectJoinList(CrmCustomerDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmCustomerDO> selectListByLockAndNotPool(Boolean lockStatus) {
|
|
||||||
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
|
||||||
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
|
||||||
.gt(CrmCustomerDO::getOwnerUserId, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
default CrmCustomerDO selectByCustomerName(String name) {
|
default CrmCustomerDO selectByCustomerName(String name) {
|
||||||
return selectOne(CrmCustomerDO::getName, name);
|
return selectOne(CrmCustomerDO::getName, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmCustomerDO> selectPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
|
default PageResult<CrmCustomerDO> selectPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
CrmCustomerPoolConfigDO poolConfig,
|
||||||
Long userId) {
|
Long userId) {
|
||||||
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutInPoolRemindCustomerWrapper(pageReqVO, poolConfigDO, userId);
|
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, userId);
|
||||||
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class));
|
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Long selectPutInPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO,
|
default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO,
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
CrmCustomerPoolConfigDO poolConfigDO,
|
||||||
Long userId) {
|
Long userId) {
|
||||||
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutInPoolRemindCustomerWrapper(pageReqVO, poolConfigDO, userId);
|
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfigDO, userId);
|
||||||
return selectCount(query);
|
return selectCount(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static MPJLambdaWrapperX<CrmCustomerDO> buildPutPoolRemindCustomerQuery(CrmCustomerPageReqVO pageReqVO,
|
||||||
|
CrmCustomerPoolConfigDO poolConfig,
|
||||||
|
Long userId) {
|
||||||
|
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
||||||
|
// 拼接数据权限的查询条件
|
||||||
|
CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
|
||||||
|
CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), null);
|
||||||
|
|
||||||
|
// 未锁定 + 未成交
|
||||||
|
query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false);
|
||||||
|
|
||||||
|
// 情况一:未成交提醒日期区间
|
||||||
|
Integer dealExpireDays = poolConfig.getDealExpireDays();
|
||||||
|
LocalDateTime startDealRemindTime = LocalDateTime.now().minusDays(dealExpireDays);
|
||||||
|
LocalDateTime endDealRemindTime = LocalDateTime.now()
|
||||||
|
.minusDays(Math.max(dealExpireDays - poolConfig.getNotifyDays(), 0));
|
||||||
|
// 情况二:未跟进提醒日期区间
|
||||||
|
Integer contactExpireDays = poolConfig.getContactExpireDays();
|
||||||
|
LocalDateTime startContactRemindTime = LocalDateTime.now().minusDays(contactExpireDays);
|
||||||
|
LocalDateTime endContactRemindTime = LocalDateTime.now()
|
||||||
|
.minusDays(Math.max(contactExpireDays - poolConfig.getNotifyDays(), 0));
|
||||||
|
query.and(q -> {
|
||||||
|
// 情况一:成交超时提醒
|
||||||
|
q.between(CrmCustomerDO::getOwnerTime, startDealRemindTime, endDealRemindTime)
|
||||||
|
// 情况二:跟进超时提醒
|
||||||
|
.or(w -> w.between(CrmCustomerDO::getOwnerTime, startContactRemindTime, endContactRemindTime)
|
||||||
|
.and(p -> p.between(CrmCustomerDO::getContactLastTime, startContactRemindTime, endContactRemindTime)
|
||||||
|
.or().isNull(CrmCustomerDO::getContactLastTime)));
|
||||||
|
});
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得需要过期到公海的客户列表
|
||||||
|
*
|
||||||
|
* @return 客户列表
|
||||||
|
*/
|
||||||
|
default List<CrmCustomerDO> selectListByAutoPool(CrmCustomerPoolConfigDO poolConfig) {
|
||||||
|
LambdaQueryWrapper<CrmCustomerDO> query = new LambdaQueryWrapper<>();
|
||||||
|
query.gt(CrmCustomerDO::getOwnerUserId, 0);
|
||||||
|
// 未锁定 + 未成交
|
||||||
|
query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false);
|
||||||
|
// 已经超时
|
||||||
|
LocalDateTime dealExpireTime = LocalDateTime.now().minusDays(poolConfig.getDealExpireDays());
|
||||||
|
LocalDateTime contactExpireTime = LocalDateTime.now().minusDays(poolConfig.getContactExpireDays());
|
||||||
|
query.and(q -> {
|
||||||
|
// 情况一:成交超时
|
||||||
|
q.lt(CrmCustomerDO::getOwnerTime, dealExpireTime)
|
||||||
|
// 情况二:跟进超时
|
||||||
|
.or(w -> w.lt(CrmCustomerDO::getOwnerTime, contactExpireTime)
|
||||||
|
.and(p -> p.lt(CrmCustomerDO::getContactLastTime, contactExpireTime)
|
||||||
|
.or().isNull(CrmCustomerDO::getContactLastTime)));
|
||||||
|
});
|
||||||
|
return selectList(query);
|
||||||
|
}
|
||||||
|
|
||||||
default Long selectTodayCustomerCount(Long userId) {
|
default Long selectTodayCustomerCount(Long userId) {
|
||||||
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 我负责的 + 非公海
|
// 我负责的 + 非公海
|
||||||
|
@ -78,8 +78,7 @@ public class CrmClueServiceImpl implements CrmClueService {
|
|||||||
adminUserApi.validateUser(createReqVO.getOwnerUserId());
|
adminUserApi.validateUser(createReqVO.getOwnerUserId());
|
||||||
|
|
||||||
// 2. 插入线索
|
// 2. 插入线索
|
||||||
CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class)
|
CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class);
|
||||||
.setContactLastTime(LocalDateTime.now());
|
|
||||||
clueMapper.insert(clue);
|
clueMapper.insert(clue);
|
||||||
|
|
||||||
// 3. 创建数据权限
|
// 3. 创建数据权限
|
||||||
@ -129,7 +128,7 @@ public class CrmClueServiceImpl implements CrmClueService {
|
|||||||
// 校验线索是否存在
|
// 校验线索是否存在
|
||||||
CrmClueDO oldClue = validateClueExists(id);
|
CrmClueDO oldClue = validateClueExists(id);
|
||||||
|
|
||||||
// 更新
|
// 更新线索
|
||||||
clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime)
|
clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime)
|
||||||
.setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent));
|
.setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent));
|
||||||
|
|
||||||
|
@ -3,11 +3,10 @@ package cn.iocoder.yudao.module.crm.service.customer;
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -45,6 +44,15 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
void updateCustomerDealStatus(Long id, Boolean dealStatus);
|
void updateCustomerDealStatus(Long id, Boolean dealStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新客户相关的跟进信息
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @param contactNextTime 下次联系时间
|
||||||
|
* @param contactLastContent 最后联系内容
|
||||||
|
*/
|
||||||
|
void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除客户
|
* 删除客户
|
||||||
*
|
*
|
||||||
@ -88,6 +96,23 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId);
|
PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得放入公海提醒的客户分页
|
||||||
|
*
|
||||||
|
* @param pageVO 分页查询
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 客户分页
|
||||||
|
*/
|
||||||
|
PageResult<CrmCustomerDO> getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得待进入公海的客户数量
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 提醒数量
|
||||||
|
*/
|
||||||
|
Long getPutPoolRemindCustomerCount(Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验客户是否存在
|
* 校验客户是否存在
|
||||||
*
|
*
|
||||||
@ -111,13 +136,6 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId);
|
void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新客户相关更进信息
|
|
||||||
*
|
|
||||||
* @param customerUpdateFollowUpReqBO 请求
|
|
||||||
*/
|
|
||||||
void updateCustomerFollowUp(CrmUpdateFollowUpReqBO customerUpdateFollowUpReqBO);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建客户
|
* 创建客户
|
||||||
*
|
*
|
||||||
@ -161,18 +179,6 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
int autoPutCustomerPool();
|
int autoPutCustomerPool();
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得放入公海提醒的客户分页数据
|
|
||||||
*
|
|
||||||
* @param pageVO 分页查询
|
|
||||||
* @param poolConfigDO 公海配置
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 客户分页
|
|
||||||
*/
|
|
||||||
PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO,
|
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
|
||||||
Long userId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得今日需联系客户数量
|
* 获得今日需联系客户数量
|
||||||
*
|
*
|
||||||
@ -181,18 +187,6 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
Long getTodayCustomerCount(Long userId);
|
Long getTodayCustomerCount(Long userId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得待进入公海的客户数量
|
|
||||||
*
|
|
||||||
* @param pageVO 分页查询
|
|
||||||
* @param poolConfigDO 公海配置
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 提醒数量
|
|
||||||
*/
|
|
||||||
Long getPutInPoolRemindCustomerCount(CrmCustomerPageReqVO pageVO,
|
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
|
||||||
Long userId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得分配给我的客户数量
|
* 获得分配给我的客户数量
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,6 @@ import cn.hutool.extra.spring.SpringUtil;
|
|||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
@ -16,6 +15,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfi
|
|||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
|
import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
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.framework.permission.core.annotations.CrmPermission;
|
||||||
import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils;
|
import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils;
|
||||||
@ -23,7 +23,6 @@ import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
|||||||
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
|
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
|
||||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
||||||
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.CrmPermissionService;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
|
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.crm.service.permission.bo.CrmPermissionTransferReqBO;
|
||||||
@ -43,7 +42,6 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
|
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
|
||||||
@ -114,7 +112,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
private static CrmCustomerDO initCustomer(Object customer, Long ownerUserId) {
|
private static CrmCustomerDO initCustomer(Object customer, Long ownerUserId) {
|
||||||
return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(ownerUserId)
|
return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(ownerUserId)
|
||||||
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
.setOwnerTime(LocalDateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -157,6 +155,22 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
LogRecordContext.putVariable("dealStatus", dealStatus);
|
LogRecordContext.putVariable("dealStatus", dealStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}",
|
||||||
|
success = CRM_CUSTOMER_FOLLOW_UP_SUCCESS)
|
||||||
|
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
|
||||||
|
public void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {
|
||||||
|
// 1.1 校验存在
|
||||||
|
CrmCustomerDO customer = validateCustomerExists(id);
|
||||||
|
|
||||||
|
// 2. 更新客户的跟进信息
|
||||||
|
customerMapper.updateById(new CrmCustomerDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime)
|
||||||
|
.setContactLastTime(LocalDateTime.now()));
|
||||||
|
|
||||||
|
// 3. 记录操作日志上下文
|
||||||
|
LogRecordContext.putVariable("customerName", customer.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
|
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
|
||||||
@ -168,7 +182,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
// 1.2 检查引用
|
// 1.2 检查引用
|
||||||
validateCustomerReference(id);
|
validateCustomerReference(id);
|
||||||
|
|
||||||
// 2. 删除
|
// 2. 删除客户
|
||||||
customerMapper.deleteById(id);
|
customerMapper.deleteById(id);
|
||||||
// 3. 删除数据权限
|
// 3. 删除数据权限
|
||||||
permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
|
permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
|
||||||
@ -209,7 +223,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
|
permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CUSTOMER.getType(),
|
||||||
reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel()));
|
reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel()));
|
||||||
// 2.2 转移后重新设置负责人
|
// 2.2 转移后重新设置负责人
|
||||||
customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
|
customerMapper.updateById(new CrmCustomerDO().setId(reqVO.getId())
|
||||||
|
.setOwnerUserId(reqVO.getNewOwnerUserId()).setOwnerTime(LocalDateTime.now()));
|
||||||
|
|
||||||
// 3. 记录转移日志
|
// 3. 记录转移日志
|
||||||
LogRecordContext.putVariable("customer", customer);
|
LogRecordContext.putVariable("customer", customer);
|
||||||
@ -226,7 +241,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) {
|
if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) {
|
||||||
throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK);
|
throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK);
|
||||||
}
|
}
|
||||||
// 1.3 校验锁定上限。
|
// 1.3 校验锁定上限
|
||||||
if (lockReqVO.getLockStatus()) {
|
if (lockReqVO.getLockStatus()) {
|
||||||
validateCustomerExceedLockLimit(userId);
|
validateCustomerExceedLockLimit(userId);
|
||||||
}
|
}
|
||||||
@ -239,11 +254,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
LogRecordContext.putVariable("customer", customer);
|
LogRecordContext.putVariable("customer", customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateCustomerFollowUp(CrmUpdateFollowUpReqBO customerUpdateFollowUpReqBO) {
|
|
||||||
customerMapper.updateById(BeanUtils.toBean(customerUpdateFollowUpReqBO, CrmCustomerDO.class).setId(customerUpdateFollowUpReqBO.getBizId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}",
|
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}",
|
||||||
@ -263,7 +273,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, CrmCustomerImportReqVO importReqVO) {
|
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
|
||||||
|
CrmCustomerImportReqVO importReqVO) {
|
||||||
if (CollUtil.isEmpty(importCustomers)) {
|
if (CollUtil.isEmpty(importCustomers)) {
|
||||||
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
||||||
}
|
}
|
||||||
@ -383,12 +394,13 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
// 1.4 校验负责人是否到达上限
|
// 1.4 校验负责人是否到达上限
|
||||||
validateCustomerExceedOwnerLimit(ownerUserId, customers.size());
|
validateCustomerExceedOwnerLimit(ownerUserId, customers.size());
|
||||||
|
|
||||||
// 2.1 领取公海数据
|
// 2. 领取公海数据
|
||||||
List<CrmCustomerDO> updateCustomers = new ArrayList<>();
|
List<CrmCustomerDO> updateCustomers = new ArrayList<>();
|
||||||
List<CrmPermissionCreateReqBO> createPermissions = new ArrayList<>();
|
List<CrmPermissionCreateReqBO> createPermissions = new ArrayList<>();
|
||||||
customers.forEach(customer -> {
|
customers.forEach(customer -> {
|
||||||
// 2.1. 设置负责人
|
// 2.1. 设置负责人
|
||||||
updateCustomers.add(new CrmCustomerDO().setId(customer.getId()).setOwnerUserId(ownerUserId));
|
updateCustomers.add(new CrmCustomerDO().setId(customer.getId())
|
||||||
|
.setOwnerUserId(ownerUserId).setOwnerTime(LocalDateTime.now()));
|
||||||
// 2.2. 创建负责人数据权限
|
// 2.2. 创建负责人数据权限
|
||||||
createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
||||||
.setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
.setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
||||||
@ -415,34 +427,23 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
if (poolConfig == null || !poolConfig.getEnabled()) {
|
if (poolConfig == null || !poolConfig.getEnabled()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 1.1 获取没有锁定的不在公海的客户
|
// 1. 获得需要放到的客户列表
|
||||||
List<CrmCustomerDO> customerList = customerMapper.selectListByLockAndNotPool(Boolean.FALSE);
|
List<CrmCustomerDO> customerList = customerMapper.selectListByAutoPool(poolConfig);
|
||||||
// TODO @puhui999:下面也搞到 sql 里去哈;写 or 查询,问题不大的;低 393 到 402;原因是,避免无用的太多数据查询到 java 进程里;
|
|
||||||
List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
|
|
||||||
poolCustomerList.addAll(filterList(customerList, customer ->
|
|
||||||
!customer.getDealStatus() && (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
|
|
||||||
poolCustomerList.addAll(filterList(customerList, customer -> {
|
|
||||||
if (!customer.getDealStatus()) { // 这里只处理成交的
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
|
|
||||||
return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 2. 逐个放入公海
|
// 2. 逐个放入公海
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (CrmCustomerDO customer : poolCustomerList) {
|
for (CrmCustomerDO customer : customerList) {
|
||||||
try {
|
try {
|
||||||
getSelf().putCustomerPool(customer);
|
getSelf().putCustomerPool(customer);
|
||||||
count++;
|
count++;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error("[autoPutCustomerPool][Customer 客户({}) 放入公海异常]", customer.getId(), e);
|
log.error("[autoPutCustomerPool][客户({}) 放入公海异常]", customer.getId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putCustomerPool(CrmCustomerDO customer) {
|
@Transactional // 需要 protected 修饰,因为需要在事务中调用
|
||||||
|
protected void putCustomerPool(CrmCustomerDO customer) {
|
||||||
// 1. 设置负责人为 NULL
|
// 1. 设置负责人为 NULL
|
||||||
int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null);
|
int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null);
|
||||||
if (updateOwnerUserIncr == 0) {
|
if (updateOwnerUserIncr == 0) {
|
||||||
@ -486,17 +487,29 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
|
public PageResult<CrmCustomerDO> getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId) {
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig();
|
||||||
Long userId) {
|
if (ObjUtil.isNull(poolConfig)
|
||||||
return customerMapper.selectPutInPoolRemindCustomerPage(pageReqVO, poolConfigDO, userId);
|
|| Boolean.FALSE.equals(poolConfig.getEnabled())
|
||||||
|
|| Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) {
|
||||||
|
return PageResult.empty();
|
||||||
|
}
|
||||||
|
return customerMapper.selectPutPoolRemindCustomerPage(pageVO, poolConfig, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getPutInPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO,
|
public Long getPutPoolRemindCustomerCount(Long userId) {
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig();
|
||||||
Long userId) {
|
if (ObjUtil.isNull(poolConfig)
|
||||||
return customerMapper.selectPutInPoolRemindCustomerCount(pageReqVO, poolConfigDO, userId);
|
|| Boolean.FALSE.equals(poolConfig.getEnabled())
|
||||||
|
|| Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
CrmCustomerPageReqVO pageVO = new CrmCustomerPageReqVO()
|
||||||
|
.setPool(null)
|
||||||
|
.setContactStatus(CrmCustomerPageReqVO.CONTACT_TODAY)
|
||||||
|
.setSceneType(CrmSceneTypeEnum.OWNER.getType());
|
||||||
|
return customerMapper.selectPutPoolRemindCustomerCount(pageVO, poolConfig, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -596,7 +609,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得自身的代理对象,解决 AOP 生效问题
|
* 获得自身的代理对象,解决 AOP 生效问题
|
||||||
*
|
*
|
||||||
|
@ -72,24 +72,24 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
|
|||||||
CrmFollowUpRecordDO followUpRecord = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class);
|
CrmFollowUpRecordDO followUpRecord = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class);
|
||||||
crmFollowUpRecordMapper.insert(followUpRecord);
|
crmFollowUpRecordMapper.insert(followUpRecord);
|
||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
CrmUpdateFollowUpReqBO updateFollowUpReqBO = new CrmUpdateFollowUpReqBO().setBizId(followUpRecord.getBizId())
|
|
||||||
.setContactLastTime(now).setContactNextTime(followUpRecord.getNextTime()).setContactLastContent(followUpRecord.getContent());
|
|
||||||
// 2. 更新 bizId 对应的记录;
|
// 2. 更新 bizId 对应的记录;
|
||||||
if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_BUSINESS.getType(), followUpRecord.getBizType())) { // 更新商机跟进信息
|
CrmUpdateFollowUpReqBO updateFollowUpReqBO = new CrmUpdateFollowUpReqBO().setBizId(followUpRecord.getBizId())
|
||||||
|
.setContactLastTime(LocalDateTime.now())
|
||||||
|
.setContactNextTime(followUpRecord.getNextTime()).setContactLastContent(followUpRecord.getContent());
|
||||||
|
if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), followUpRecord.getBizType())) { // 更新商机跟进信息
|
||||||
businessService.updateBusinessFollowUpBatch(Collections.singletonList(updateFollowUpReqBO));
|
businessService.updateBusinessFollowUpBatch(Collections.singletonList(updateFollowUpReqBO));
|
||||||
}
|
}
|
||||||
if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CLUE.getType(), followUpRecord.getBizType())) { // 更新线索跟进信息
|
if (ObjUtil.equal(CrmBizTypeEnum.CRM_CLUE.getType(), followUpRecord.getBizType())) { // 更新线索跟进信息
|
||||||
clueService.updateClueFollowUp(followUpRecord.getId(), followUpRecord.getNextTime(), followUpRecord.getContent());
|
clueService.updateClueFollowUp(followUpRecord.getId(), followUpRecord.getNextTime(), followUpRecord.getContent());
|
||||||
}
|
}
|
||||||
if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CONTACT.getType(), followUpRecord.getBizType())) { // 更新联系人跟进信息
|
if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTACT.getType(), followUpRecord.getBizType())) { // 更新联系人跟进信息
|
||||||
contactService.updateContactFollowUpBatch(Collections.singletonList(updateFollowUpReqBO));
|
contactService.updateContactFollowUpBatch(Collections.singletonList(updateFollowUpReqBO));
|
||||||
}
|
}
|
||||||
if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CONTRACT.getType(), followUpRecord.getBizType())) { // 更新合同跟进信息
|
if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTRACT.getType(), followUpRecord.getBizType())) { // 更新合同跟进信息
|
||||||
contractService.updateContractFollowUp(updateFollowUpReqBO);
|
contractService.updateContractFollowUp(updateFollowUpReqBO);
|
||||||
}
|
}
|
||||||
if (ObjUtil.notEqual(CrmBizTypeEnum.CRM_CUSTOMER.getType(), followUpRecord.getBizType())) { // 更新客户跟进信息
|
if (ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), followUpRecord.getBizType())) { // 更新客户跟进信息
|
||||||
customerService.updateCustomerFollowUp(updateFollowUpReqBO);
|
customerService.updateCustomerFollowUp(followUpRecord.getBizId(), followUpRecord.getNextTime(), followUpRecord.getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1 更新 contactIds 对应的记录,不更新 lastTime 和 lastContent
|
// 3.1 更新 contactIds 对应的记录,不更新 lastTime 和 lastContent
|
||||||
|
Loading…
Reference in New Issue
Block a user