📖 CRM:code review 跟进记录
This commit is contained in:
parent
1a7be60503
commit
814b6f688d
|
@ -74,7 +74,7 @@ function stop() {
|
||||||
if [ -n "$PID" ]; then
|
if [ -n "$PID" ]; then
|
||||||
echo -e ".\c"
|
echo -e ".\c"
|
||||||
else
|
else
|
||||||
echo '[stop] 停止 $BASE_PATH/$SERVER_NAME 成功'
|
echo "[stop] 停止 $BASE_PATH/$SERVER_NAME 成功"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -70,6 +70,8 @@
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- TODO @puhui999:放的位置,要整齐哈。 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
||||||
|
|
|
@ -13,76 +13,31 @@ public class CrmOperateLogV2RespVO {
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
||||||
private Long id;
|
private Long id;
|
||||||
/**
|
|
||||||
* 链路追踪编号
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
|
||||||
private String traceId;
|
|
||||||
/**
|
|
||||||
* 用户编号
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
private Long userId;
|
private Long userId;
|
||||||
/**
|
|
||||||
* 用户名称
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
|
||||||
private String userName;
|
private String userName;
|
||||||
/**
|
|
||||||
* 用户类型
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
private Integer userType;
|
private Integer userType;
|
||||||
/**
|
|
||||||
* 操作模块类型
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
||||||
private String type;
|
private String type;
|
||||||
/**
|
|
||||||
* 操作名
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "修改客户")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "修改客户")
|
||||||
private String subType;
|
private String subType;
|
||||||
/**
|
|
||||||
* 操作模块业务编号
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
||||||
private Long bizId;
|
private Long bizId;
|
||||||
/**
|
|
||||||
* 操作内容
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "将什么从什么改为了什么")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "将什么从什么改为了什么")
|
||||||
private String action;
|
private String action;
|
||||||
/**
|
|
||||||
* 拓展字段
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", example = "{orderId: 1}")
|
@Schema(description = "编号", example = "{orderId: 1}")
|
||||||
private String extra;
|
private String extra;
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求方法名
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
|
||||||
private String requestMethod;
|
|
||||||
/**
|
|
||||||
* 请求地址
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
|
||||||
private String requestUrl;
|
|
||||||
/**
|
|
||||||
* 用户 IP
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
|
||||||
private String userIp;
|
|
||||||
/**
|
|
||||||
* 浏览器 UA
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
|
|
||||||
private String userAgent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建时间
|
|
||||||
*/
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-01")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-01")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
||||||
default List<CrmCustomerDO> selectListByLockStatusAndOwnerUserIdNotNull(Boolean lockStatus) {
|
default List<CrmCustomerDO> selectListByLockStatusAndOwnerUserIdNotNull(Boolean lockStatus) {
|
||||||
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
||||||
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
||||||
|
// TODO @puhui999:not null 可以转化成大于 0
|
||||||
.isNotNull(CrmCustomerDO::getOwnerUserId));
|
.isNotNull(CrmCustomerDO::getOwnerUserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class CrmPermissionUtils {
|
||||||
return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:这个貌似直接放到 CrmPermissionService 会更好?
|
||||||
/**
|
/**
|
||||||
* 校验权限
|
* 校验权限
|
||||||
*
|
*
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
|
/**
|
||||||
|
* TODO 芋艿:临时占位,后续可删除
|
||||||
|
*/
|
||||||
package cn.iocoder.yudao.module.crm.job;
|
package cn.iocoder.yudao.module.crm.job;
|
|
@ -190,32 +190,36 @@ public class CrmClueServiceImpl implements CrmClueService {
|
||||||
throw exception(CLUE_ANY_CLUE_ALREADY_TRANSLATED, convertSet(translatedClues, CrmClueDO::getId));
|
throw exception(CLUE_ANY_CLUE_ALREADY_TRANSLATED, convertSet(translatedClues, CrmClueDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 遍历线索(未转化的线索),创建对应的客户
|
// 2.1 遍历线索(未转化的线索),创建对应的客户
|
||||||
clues.forEach(clue -> {
|
clues.forEach(clue -> {
|
||||||
Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId);
|
Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId);
|
||||||
clue.setCustomerId(customerId);
|
clue.setCustomerId(customerId);
|
||||||
});
|
});
|
||||||
|
// 2.2 更新线索
|
||||||
|
clueMapper.updateBatch(convertList(clues, clue -> new CrmClueDO().setId(clue.getId())
|
||||||
|
.setTransformStatus(Boolean.TRUE).setCustomerId(clue.getCustomerId())));
|
||||||
|
// 2.3 复制跟进记录
|
||||||
|
copyFollowUpRecords(clues);
|
||||||
|
|
||||||
// 2.1 更新线索
|
|
||||||
clueMapper.updateBatch(convertList(clues, clue -> new CrmClueDO().setId(clue.getId()).setTransformStatus(Boolean.TRUE)
|
|
||||||
.setCustomerId(clue.getCustomerId())));
|
|
||||||
// 2.3 复制跟进
|
|
||||||
updateFollowUpRecords(clues);
|
|
||||||
// 3. 记录操作日志
|
// 3. 记录操作日志
|
||||||
for (CrmClueDO clue : clues) {
|
for (CrmClueDO clue : clues) {
|
||||||
getSelf().translateCustomerLog(clue);
|
getSelf().translateCustomerLog(clue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFollowUpRecords(List<CrmClueDO> clues) {
|
/**
|
||||||
|
* 线索被转换客户后,需要将线索的跟进记录,复制到客户上
|
||||||
|
*
|
||||||
|
* @param clues 被转化的线索
|
||||||
|
*/
|
||||||
|
private void copyFollowUpRecords(List<CrmClueDO> clues) {
|
||||||
List<CrmFollowUpRecordDO> followUpRecords = followUpRecordService.getFollowUpRecordByBiz(
|
List<CrmFollowUpRecordDO> followUpRecords = followUpRecordService.getFollowUpRecordByBiz(
|
||||||
CrmBizTypeEnum.CRM_LEADS.getType(), convertSet(clues, CrmClueDO::getId));
|
CrmBizTypeEnum.CRM_LEADS.getType(), convertSet(clues, CrmClueDO::getId));
|
||||||
if (CollUtil.isEmpty(followUpRecords)) {
|
if (CollUtil.isEmpty(followUpRecords)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, CrmClueDO> clueMap = convertMap(clues, CrmClueDO::getId);
|
|
||||||
// 创建跟进
|
// 创建跟进
|
||||||
|
Map<Long, CrmClueDO> clueMap = convertMap(clues, CrmClueDO::getId);
|
||||||
followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, followUpRecord ->
|
followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, followUpRecord ->
|
||||||
BeanUtils.toBean(followUpRecord, CrmFollowUpCreateReqBO.class).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
BeanUtils.toBean(followUpRecord, CrmFollowUpCreateReqBO.class).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
||||||
.setBizId(clueMap.get(followUpRecord.getBizId()).getCustomerId())));
|
.setBizId(clueMap.get(followUpRecord.getBizId()).getCustomerId())));
|
||||||
|
|
|
@ -126,6 +126,7 @@ public interface CrmCustomerService {
|
||||||
*/
|
*/
|
||||||
void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
|
void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
|
||||||
|
|
||||||
|
// TODO @puhui999:autoPutCustomerPool,注释说明是系统就好哈;
|
||||||
/**
|
/**
|
||||||
* 【系统】客户自动掉入公海
|
* 【系统】客户自动掉入公海
|
||||||
*
|
*
|
||||||
|
|
|
@ -28,9 +28,9 @@ public interface CrmFollowUpRecordService {
|
||||||
/**
|
/**
|
||||||
* 创建更进
|
* 创建更进
|
||||||
*
|
*
|
||||||
* @param followUpCreateReqBOs 请求
|
* @param list 请求
|
||||||
*/
|
*/
|
||||||
void createFollowUpRecordBatch(List<CrmFollowUpCreateReqBO> followUpCreateReqBOs);
|
void createFollowUpRecordBatch(List<CrmFollowUpCreateReqBO> list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除跟进记录 (数据权限基于 bizType、 bizId)
|
* 删除跟进记录 (数据权限基于 bizType、 bizId)
|
||||||
|
|
|
@ -93,12 +93,12 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
|
||||||
customerService.updateCustomerFollowUp(updateFollowUpReqBO);
|
customerService.updateCustomerFollowUp(updateFollowUpReqBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1 更新 contactIds 对应的记录
|
// 3.1 更新 contactIds 对应的记录,不更新 lastTime 和 lastContent
|
||||||
if (CollUtil.isNotEmpty(createReqVO.getContactIds())) {
|
if (CollUtil.isNotEmpty(createReqVO.getContactIds())) {
|
||||||
contactService.updateContactFollowUpBatch(convertList(createReqVO.getContactIds(),
|
contactService.updateContactFollowUpBatch(convertList(createReqVO.getContactIds(),
|
||||||
contactId -> updateFollowUpReqBO.setBizId(contactId).setContactLastTime(null).setContactLastContent(null)));
|
contactId -> updateFollowUpReqBO.setBizId(contactId).setContactLastTime(null).setContactLastContent(null)));
|
||||||
}
|
}
|
||||||
// 3.2 需要更新 businessIds、contactIds 对应的记录
|
// 3.2 需要更新 businessIds 对应的记录,不更新 lastTime 和 lastContent
|
||||||
if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) {
|
if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) {
|
||||||
businessService.updateBusinessFollowUpBatch(convertList(createReqVO.getBusinessIds(),
|
businessService.updateBusinessFollowUpBatch(convertList(createReqVO.getBusinessIds(),
|
||||||
businessId -> updateFollowUpReqBO.setBizId(businessId).setContactLastTime(null).setContactLastContent(null)));
|
businessId -> updateFollowUpReqBO.setBizId(businessId).setContactLastTime(null).setContactLastContent(null)));
|
||||||
|
@ -107,12 +107,11 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createFollowUpRecordBatch(List<CrmFollowUpCreateReqBO> followUpCreateReqBOs) {
|
public void createFollowUpRecordBatch(List<CrmFollowUpCreateReqBO> list) {
|
||||||
if (CollUtil.isEmpty(followUpCreateReqBOs)) {
|
if (CollUtil.isEmpty(list)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
crmFollowUpRecordMapper.insertBatch(BeanUtils.toBean(list, CrmFollowUpRecordDO.class));
|
||||||
crmFollowUpRecordMapper.insertBatch(BeanUtils.toBean(followUpCreateReqBOs, CrmFollowUpRecordDO.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -98,7 +98,7 @@ public interface ErrorCodeConstants {
|
||||||
ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用");
|
ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用");
|
||||||
ErrorCode SMS_CODE_NOT_CORRECT = new ErrorCode(1_002_014_003, "验证码不正确");
|
ErrorCode SMS_CODE_NOT_CORRECT = new ErrorCode(1_002_014_003, "验证码不正确");
|
||||||
ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量");
|
ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量");
|
||||||
ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频率");
|
ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁");
|
||||||
ErrorCode SMS_CODE_IS_EXISTS = new ErrorCode(1_002_014_006, "手机号已被使用");
|
ErrorCode SMS_CODE_IS_EXISTS = new ErrorCode(1_002_014_006, "手机号已被使用");
|
||||||
ErrorCode SMS_CODE_IS_UNUSED = new ErrorCode(1_002_014_007, "验证码未被使用");
|
ErrorCode SMS_CODE_IS_UNUSED = new ErrorCode(1_002_014_007, "验证码未被使用");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue