Commit 9de0e2d7a508ae01a6557735f636e5d817f329ae

Authored by 张志伟
1 parent 1331548a

feature(*): 公共池线索终止逻辑

- 角色调整总之公共池线索跟进
- 公共池跟进到期终止线索
- 线索终止后档案以及专属性的逻辑关系处理
doc/v2.0/update.sql
... ... @@ -2,6 +2,9 @@ drop table if exists customer_clue_pool;
2 2  
3 3 drop table if exists follow_task;
4 4  
  5 +alter table customer
  6 + add last_arrival_shop bigint null comment '上次进站门店' after arrival_time;
  7 +
5 8 # 续保跟进模式
6 9 INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn,
7 10 create_time, update_time)
... ... @@ -61,6 +64,7 @@ CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info
61 64 shop_id bigint not null comment '门店id',
62 65 shop_name varchar(255) null comment '门店名称',
63 66 group_id bigint not null comment '集团id',
  67 + defeat_reason int(3) null comment '关单原因 1:主动放弃 2:进另一门店 3:角色变动战败 4:到期战败',
64 68 create_time datetime not null,
65 69 update_time datetime null,
66 70 constraint pub_stand_staff_info_staff_id_group_id_uindex
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/Customer.java
... ... @@ -106,6 +106,10 @@ public class Customer extends BaseAuditableTimeEntity<Customer, Long> {
106 106 */
107 107 private Date arrivalTime;
108 108 /**
  109 + * 上次进站门店
  110 + */
  111 + private Long lastArrivalShop;
  112 + /**
109 113 * 进站次数
110 114 */
111 115 private Integer arrivalCount;
... ... @@ -118,6 +122,10 @@ public class Customer extends BaseAuditableTimeEntity<Customer, Long> {
118 122 */
119 123 private Date insuranceExpires;
120 124 /**
  125 + * 临时的专属顾问关系
  126 + */
  127 + private Boolean temporary;
  128 + /**
121 129 * 所属服务站
122 130 */
123 131 private Long shopId;
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/pub/PubCluePool.java
... ... @@ -3,6 +3,7 @@ package cn.fw.valhalla.domain.db.pub;
3 3 import cn.fw.common.data.entity.BaseAuditableTimeEntity;
4 4 import cn.fw.valhalla.domain.enums.PubStandType;
5 5 import cn.fw.valhalla.domain.enums.PublicClueStateEnum;
  6 +import cn.fw.valhalla.domain.enums.TaskDefeatTypeEnum;
6 7 import lombok.Data;
7 8  
8 9 import java.time.LocalDate;
... ... @@ -67,4 +68,8 @@ public class PubCluePool extends BaseAuditableTimeEntity<PubCluePool, Long> {
67 68 * 集团id
68 69 */
69 70 private Long groupId;
  71 + /**
  72 + * 战败原因
  73 + */
  74 + private TaskDefeatTypeEnum defeatReason;
70 75 }
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/CustomerDetailDto.java
... ... @@ -184,6 +184,10 @@ public class CustomerDetailDto {
184 184 */
185 185 private Long shopId;
186 186 /**
  187 + * 上次进站门店
  188 + */
  189 + private Long lastArrivalShop;
  190 + /**
187 191 * 车价 (分)
188 192 */
189 193 private Long buyPrice;
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/DefeatReasonEnum.java
... ... @@ -14,11 +14,13 @@ import lombok.Getter;
14 14 public enum DefeatReasonEnum implements IEnum<Integer> {
15 15 /**
16 16 * 保养卡流失
  17 + *
17 18 * @deprecated
18 19 */
19 20 MC(1, "保养卡流失"),
20 21 /**
21 22 * 质保卡流失
  23 + *
22 24 * @deprecated
23 25 */
24 26 WC(2, "质保卡流失"),
... ... @@ -44,6 +46,7 @@ public enum DefeatReasonEnum implements IEnum&lt;Integer&gt; {
44 46 RM(7, "流失预警划走"),
45 47 /**
46 48 * 客户变更
  49 + *
47 50 * @deprecated
48 51 */
49 52 CC(8, "客户主动变更"),
... ... @@ -56,10 +59,17 @@ public enum DefeatReasonEnum implements IEnum&lt;Integer&gt; {
56 59 */
57 60 LC(10, "客户分配"),
58 61 /**
  62 + * 角色变动
  63 + */
  64 + RC(11, "角色变动"),
  65 + /**
  66 + * 线索逾期
  67 + */
  68 + CD(12, "线索逾期"),
  69 + /**
59 70 * 其他原因
60 71 */
61   - OT(99, "其他原因")
62   - ;
  72 + OT(99, "其他原因");
63 73  
64 74 /**
65 75 * 值
... ...
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/PublicPoolTypeEnum.java
... ... @@ -28,6 +28,7 @@ public enum PublicPoolTypeEnum implements IEnum&lt;Integer&gt; {
28 28 * 公共线索池过期
29 29 */
30 30 PD(4, "公共线索池过期"),
  31 + RC(5, "角色变动战败"),
31 32 ;
32 33  
33 34 /**
... ...
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/PubFollowTask.java 0 → 100644
  1 +package cn.fw.valhalla.controller.task;
  2 +
  3 +import cn.fw.valhalla.common.utils.StringUtils;
  4 +import cn.fw.valhalla.service.bus.pub.PubFollowBizService;
  5 +import lombok.AccessLevel;
  6 +import lombok.Getter;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.beans.factory.annotation.Value;
  9 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  10 +import org.springframework.data.redis.core.BoundSetOperations;
  11 +import org.springframework.data.redis.core.StringRedisTemplate;
  12 +import org.springframework.scheduling.annotation.Scheduled;
  13 +import org.springframework.stereotype.Component;
  14 +import org.springframework.util.CollectionUtils;
  15 +
  16 +import java.util.ArrayList;
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * 公共池线索任务
  21 + *
  22 + * @author : kurisu
  23 + * @version : 1.0
  24 + * @className : PubFollowTask
  25 + * @description : 公共池线索任务
  26 + * @date : 2023-03-21 16:11
  27 + */
  28 +@Component
  29 +@ConditionalOnProperty(prefix = "task", name = "switch", havingValue = "on")
  30 +@Slf4j
  31 +public class PubFollowTask {
  32 + private final StringRedisTemplate stringRedisTemplate;
  33 + private final PubFollowBizService pubFollowBizService;
  34 + @Value("${spring.cache.custom.global-prefix}:role-change-need-close:clue")
  35 + @Getter(AccessLevel.PRIVATE)
  36 + private String roleChangeNeedCloseClueKey;
  37 +
  38 + public PubFollowTask(final StringRedisTemplate stringRedisTemplate,
  39 + final PubFollowBizService pubFollowBizService) {
  40 + this.stringRedisTemplate = stringRedisTemplate;
  41 + this.pubFollowBizService = pubFollowBizService;
  42 + }
  43 +
  44 + /**
  45 + * 处理角色变动战败公共池跟进线索
  46 + */
  47 + @Scheduled(cron = "0/20 * * * * *")
  48 + public void roleChangeDefeatClue() {
  49 + BoundSetOperations<String, String> setOps = stringRedisTemplate.boundSetOps(getRoleChangeNeedCloseClueKey());
  50 + List<String> failList = new ArrayList<>();
  51 + String idStr;
  52 + while ((idStr = setOps.pop()) != null) {
  53 + if (!StringUtils.isNumber(idStr)) {
  54 + continue;
  55 + }
  56 + try {
  57 + pubFollowBizService.roleChangeDefeatClue(idStr);
  58 + } catch (Exception e) {
  59 + if (StringUtils.isValid(idStr)) {
  60 + failList.add(idStr);
  61 + }
  62 + log.error("处理角色变动结束公共池线索失败", e);
  63 + }
  64 + }
  65 + if (!CollectionUtils.isEmpty(failList)) {
  66 + String[] idArr = failList.toArray(new String[0]);
  67 + setOps.add(idArr);
  68 + }
  69 + }
  70 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java
... ... @@ -120,6 +120,7 @@ public class LeaveNeedDoBizService {
120 120 .eq(Customer::getAdviserId, userId)
121 121 .eq(Customer::getShopId, shopId)
122 122 .eq(Customer::getYn, Boolean.TRUE)
  123 + .and(w1 -> w1.eq(Customer::getTemporary, Boolean.FALSE).or().isNull(Customer::getTemporary))
123 124 );
124 125 if (count <= 0) {
125 126 return;
... ... @@ -152,6 +153,7 @@ public class LeaveNeedDoBizService {
152 153 int i = customerService.count(Wrappers.<Customer>lambdaQuery()
153 154 .eq(Customer::getAdviserId, needDo.getUserId())
154 155 .eq(Customer::getYn, Boolean.TRUE)
  156 + .and(w1 -> w1.eq(Customer::getTemporary, Boolean.FALSE).or().isNull(Customer::getTemporary))
155 157 );
156 158 list.add(LeaveNeedDoVO.with(needDo, i));
157 159 }
... ... @@ -184,6 +186,7 @@ public class LeaveNeedDoBizService {
184 186 int i = customerService.count(Wrappers.<Customer>lambdaQuery()
185 187 .eq(Customer::getAdviserId, needDo.getUserId())
186 188 .eq(Customer::getYn, Boolean.TRUE)
  189 + .and(w1 -> w1.eq(Customer::getTemporary, Boolean.FALSE).or().isNull(Customer::getTemporary))
187 190 );
188 191 if (i > 0) {
189 192 return;
... ... @@ -312,7 +315,8 @@ public class LeaveNeedDoBizService {
312 315 * @return 处理完的档案
313 316 */
314 317 private void doAllocation(LeaveAllocationDTO dto, String key) {
315   - List<Customer> customerList = customerService.queryByAdviserId(dto.getAdviserId());
  318 + List<Customer> customerAllList = Optional.ofNullable(customerService.queryByAdviserId(dto.getAdviserId())).orElse(new ArrayList<>());
  319 + List<Customer> customerList = customerAllList.stream().filter(r -> !Boolean.TRUE.equals(r.getTemporary())).collect(Collectors.toList());
316 320 if (CollectionUtils.isEmpty(customerList)) {
317 321 return;
318 322 }
... ... @@ -456,6 +460,7 @@ public class LeaveNeedDoBizService {
456 460 .eq(Customer::getAdviserId, userId)
457 461 .eq(Customer::getShopId, shopId)
458 462 .eq(Customer::getYn, Boolean.TRUE)
  463 + .and(w1 -> w1.eq(Customer::getTemporary, Boolean.FALSE).or().isNull(Customer::getTemporary))
459 464 ) > 0;
460 465 BV.isTrue(bool, () -> "该顾问没有可用档案无需分配保有客");
461 466 LeaveNeedDo db = new LeaveNeedDo();
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/ReachLogBizService.java
... ... @@ -56,6 +56,7 @@ public class ReachLogBizService {
56 56 int count = Objects.nonNull(customer.getArrivalCount()) ? customer.getArrivalCount() : 0;
57 57 customer.setArrivalTime(arrivalTime);
58 58 customer.setArrivalCount(count + 1);
  59 + customer.setLastArrivalShop(reachLogReq.getShopId());
59 60 customer.setCurrentMileage(reachLogReq.getArrivalMileage());
60 61 customerService.updateById(customer);
61 62 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AbstractCustomerService.java
... ... @@ -146,10 +146,10 @@ public abstract class AbstractCustomerService {
146 146 dto.setGroupId(customer.getGroupId());
147 147 dto.setVehicleLicense(customer.getVehicleLicense());
148 148 dto.setShopId(customer.getShopId());
  149 + dto.setLastArrivalShop(customer.getLastArrivalShop());
149 150 dto.setBuyPrice(customer.getBuyPrice());
150 151 dto.setSource(Objects.isNull(customer.getSource()) ? null : customer.getSource().getValue());
151 152 dto.setYn(customer.getYn());
152   - dto.setShopId(customer.getShopId());
153 153 return dto;
154 154 }
155 155  
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerBizService.java
... ... @@ -17,6 +17,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord;
17 17 import cn.fw.valhalla.domain.db.pool.PublicCluePool;
18 18 import cn.fw.valhalla.domain.db.pool.PublicPool;
19 19 import cn.fw.valhalla.domain.db.pool.StammkundePool;
  20 +import cn.fw.valhalla.domain.db.pub.PubCluePool;
20 21 import cn.fw.valhalla.domain.dto.CustomerDetailDto;
21 22 import cn.fw.valhalla.domain.enums.*;
22 23 import cn.fw.valhalla.domain.query.CustomCustomerQuery;
... ... @@ -579,10 +580,42 @@ public class CustomerBizService extends AbstractCustomerService {
579 580 }
580 581  
581 582 /**
  583 + * 公共池跟进任务结束战败客户到公共池
  584 + *
  585 + * @param pubCluePool
  586 + */
  587 + @Transactional(rollbackFor = Exception.class)
  588 + public void pubTaskEndAbandon(PubCluePool pubCluePool) {
  589 + Long groupId = pubCluePool.getGroupId();
  590 + CustomerDetailDto detailDto = queryByFrameNo(pubCluePool.getVin(), groupId);
  591 + if (Objects.isNull(detailDto)) {
  592 + return;
  593 + }
  594 + boolean updated = customerService.update(Wrappers.<Customer>lambdaUpdate()
  595 + .set(Customer::getAdviserId, null)
  596 + .set(Customer::getShopId, null)
  597 + .eq(Customer::getId, detailDto.getId()));
  598 + if (!updated) {
  599 + return;
  600 + }
  601 + stammkundePoolService.reject(detailDto.getId(), groupId, DefeatReasonEnum.CD);
  602 + publicCluePoolService.removeClue(detailDto.getId(), detailDto.getAdviserId());
  603 + AffiliationRecord entity = createEntity(detailDto);
  604 + entity.setReason("跟进超期");
  605 + affiliationRecordService.save(entity);
  606 + if (publicPoolService.queryByPlate(detailDto.getPlateNo(), detailDto.getGroupId()).isPresent()) {
  607 + return;
  608 + }
  609 + PublicPool publicPool = createPublicPool(detailDto, PublicPoolTypeEnum.PD, PublicPoolTypeEnum.PD.getName());
  610 + publicPoolService.save(publicPool);
  611 + }
  612 +
  613 + /**
582 614 * 继续跟进
583   - * @deprecated
  615 + *
584 616 * @param currentUser
585 617 * @param customerId
  618 + * @deprecated
586 619 */
587 620 @DisLock(prefix = "#this.getKeyPrefix()", key = "'continueFollow:' + #customerId", message = "请勿重复提交")
588 621 public void continueFollow(LoginAuthBean currentUser, final Long customerId) {
... ... @@ -869,11 +902,11 @@ public class CustomerBizService extends AbstractCustomerService {
869 902 }
870 903  
871 904 /**
872   - * @deprecated 已弃用 sclie 2.0
873 905 * @param customer
874 906 * @param currentUser
875 907 * @param rangeDTO
876 908 * @param deadline
  909 + * @deprecated 已弃用 sclie 2.0
877 910 */
878 911 @Transactional(rollbackFor = Exception.class)
879 912 public void createPublicPoolClue(Customer customer, LoginAuthBean currentUser, UserRoleDataRangeDTO rangeDTO, Date deadline) {
... ... @@ -891,11 +924,12 @@ public class CustomerBizService extends AbstractCustomerService {
891 924  
892 925 /**
893 926 * 创建公共池线索跟进
894   - * @deprecated 已弃用 sclie 2.0
  927 + *
895 928 * @param customerId
896 929 * @param deadline
897 930 * @param currentUser
898 931 * @param rangeDTO
  932 + * @deprecated 已弃用 sclie 2.0
899 933 */
900 934 private void createPublicCluePool(Long customerId, Date deadline, LoginAuthBean currentUser, UserRoleDataRangeDTO rangeDTO) {
901 935 final PublicCluePool publicCluePool = new PublicCluePool();
... ... @@ -954,8 +988,9 @@ public class CustomerBizService extends AbstractCustomerService {
954 988 pool.setCompany(dto.getCompanyName());
955 989 pool.setType(type);
956 990 pool.setReason(reason);
957   - pool.setShopId(dto.getShopId());
958   - ShopDTO shop = oopService.shop(dto.getShopId());
  991 + Long shopId = Optional.ofNullable(dto.getLastArrivalShop()).orElse(dto.getShopId());
  992 + pool.setShopId(shopId);
  993 + ShopDTO shop = oopService.shop(shopId);
959 994 if (Objects.nonNull(shop)) {
960 995 pool.setShopName(shop.getShortName());
961 996 }
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
... ... @@ -201,7 +201,9 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
201 201 task.setReason(TaskDefeatTypeEnum.B);
202 202 }
203 203 boolean rpcSucess = rpcStopTask(task);
204   - BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
  204 + if (!rpcSucess) {
  205 + log.info("跟进系统终止任务失败");
  206 + }
205 207 task.setRpcSuccess(rpcSucess);
206 208 clueTaskService.updateById(task);
207 209 if (Objects.nonNull(clue)) {
... ... @@ -233,7 +235,9 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
233 235 task.setReason(TaskDefeatTypeEnum.D);
234 236 if (Objects.isNull(clue)) {
235 237 boolean rpcSucess = rpcStopTask(task);
236   - BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
  238 + if (!rpcSucess) {
  239 + log.info("跟进系统终止任务失败");
  240 + }
237 241 task.setRpcSuccess(rpcSucess);
238 242 clueTaskService.updateById(task);
239 243 } else {
... ... @@ -248,7 +252,9 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
248 252 }
249 253  
250 254 boolean rpcSucess = rpcStopTask(task);
251   - BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
  255 + if (!rpcSucess) {
  256 + log.info("跟进系统终止任务失败");
  257 + }
252 258 task.setRpcSuccess(rpcSucess);
253 259 clueTaskService.updateById(task);
254 260  
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java
... ... @@ -124,7 +124,9 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
124 124 task.setReason(TaskDefeatTypeEnum.B);
125 125 }
126 126 boolean rpcSucess = rpcStopTask(task);
127   - BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
  127 + if (!rpcSucess) {
  128 + log.info("跟进系统终止任务失败");
  129 + }
128 130 task.setRpcSuccess(rpcSucess);
129 131 if (Objects.nonNull(clue) && redistribution) {
130 132 clue.setClueState(ClueStatusEnum.FAILURE);
... ... @@ -155,7 +157,9 @@ public class IRFollowStrategy extends AbstractFollowStrategy {
155 157 task.setCloseTime(LocalDateTime.now());
156 158 task.setReason(TaskDefeatTypeEnum.D);
157 159 boolean rpcSucess = rpcStopTask(task);
158   - BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
  160 + if (!rpcSucess) {
  161 + log.info("跟进系统终止任务失败");
  162 + }
159 163 task.setRpcSuccess(rpcSucess);
160 164 if (Objects.nonNull(clue) && redistribution) {
161 165 clue.setClueState(ClueStatusEnum.FAILURE);
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/PubFollowStrategy.java 0 → 100644
  1 +package cn.fw.valhalla.service.bus.follow.strategy.impl;
  2 +
  3 +import cn.fw.valhalla.domain.db.OriginalData;
  4 +import cn.fw.valhalla.domain.db.follow.ClueTask;
  5 +import cn.fw.valhalla.domain.db.follow.FollowClue;
  6 +import cn.fw.valhalla.domain.db.pub.PubCluePool;
  7 +import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  8 +import cn.fw.valhalla.domain.enums.PublicClueStateEnum;
  9 +import cn.fw.valhalla.domain.enums.TaskDefeatTypeEnum;
  10 +import cn.fw.valhalla.domain.enums.TaskStateEnum;
  11 +import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
  12 +import cn.fw.valhalla.service.data.PubCluePoolService;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.stereotype.Component;
  16 +import org.springframework.transaction.annotation.Transactional;
  17 +
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.fw.common.businessvalidator.Validator.BV;
  21 +
  22 +/**
  23 + * 公共池线索跟进
  24 + *
  25 + * @author : kurisu
  26 + * @version : 1.0
  27 + * @className : PubFollowStrategy
  28 + * @description : 公共池线索跟进
  29 + * @date : 2023-03-21 16:52
  30 + */
  31 +@Slf4j
  32 +@Component
  33 +public class PubFollowStrategy extends AbstractFollowStrategy {
  34 + private final PubCluePoolService pubCluePoolService;
  35 +
  36 + @Autowired
  37 + public PubFollowStrategy(final PubCluePoolService pubCluePoolService) {
  38 + this.pubCluePoolService = pubCluePoolService;
  39 + }
  40 +
  41 + @Override
  42 + public FollowTypeEnum getFollowType() {
  43 + return FollowTypeEnum.PL;
  44 + }
  45 +
  46 + /**
  47 + * 公共池线索跟进此方法无效
  48 + *
  49 + * @param originalData
  50 + * @return
  51 + */
  52 + @Override
  53 + public boolean origin2task(final OriginalData originalData) {
  54 + return false;
  55 + }
  56 +
  57 + @Override
  58 + public void startClue(final FollowClue followClue) {
  59 +
  60 + }
  61 +
  62 + @Override
  63 + @Transactional(rollbackFor = Exception.class)
  64 + public void onRoleChangeCloseTask(final ClueTask task) {
  65 + task.setState(TaskStateEnum.DEFEAT);
  66 + task.setCloseTime(LocalDateTime.now());
  67 + task.setReason(TaskDefeatTypeEnum.D);
  68 +
  69 + boolean rpcSucess = rpcStopTask(task);
  70 + if (!rpcSucess) {
  71 + log.info("跟进系统终止任务失败");
  72 + }
  73 + task.setRpcSuccess(rpcSucess);
  74 + clueTaskService.updateById(task);
  75 + }
  76 +
  77 + @Override
  78 + @Transactional(rollbackFor = Exception.class)
  79 + public void closeTask(final ClueTask task) {
  80 + final Long clueId = task.getClueId();
  81 + PubCluePool pubCluePool = pubCluePoolService.getById(clueId);
  82 + BV.notNull(pubCluePool, () -> "公共池跟进线索不存在: " + clueId);
  83 + task.setState(TaskStateEnum.DEFEAT);
  84 + task.setCloseTime(task.getDeadline().minusSeconds(1L));
  85 + task.setReason(TaskDefeatTypeEnum.C);
  86 + boolean rpcSucess = rpcStopTask(task);
  87 + if (!rpcSucess) {
  88 + log.info("跟进系统终止任务失败");
  89 + }
  90 + task.setRpcSuccess(rpcSucess);
  91 + clueTaskService.updateById(task);
  92 + pubCluePool.setCloseTime(task.getCloseTime());
  93 + pubCluePool.setState(PublicClueStateEnum.DEFEAT);
  94 + pubCluePool.setDefeatReason(task.getReason());
  95 + pubCluePoolService.updateById(pubCluePool);
  96 + redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
  97 + customerBizService.pubTaskEndAbandon(pubCluePool);
  98 + }
  99 +}
... ...
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubFollowBizService.java
1 1 package cn.fw.valhalla.service.bus.pub;
2 2  
  3 +import cn.fw.valhalla.domain.db.customer.Customer;
  4 +import cn.fw.valhalla.domain.db.customer.CustomerBaseInfo;
  5 +import cn.fw.valhalla.domain.db.follow.ClueTask;
  6 +import cn.fw.valhalla.domain.db.pool.PublicPool;
3 7 import cn.fw.valhalla.domain.db.pub.PubCluePool;
4   -import cn.fw.valhalla.domain.enums.PublicClueStateEnum;
  8 +import cn.fw.valhalla.domain.enums.*;
  9 +import cn.fw.valhalla.rpc.oop.OopService;
  10 +import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
  11 +import cn.fw.valhalla.service.bus.follow.strategy.impl.PubFollowStrategy;
5 12 import cn.fw.valhalla.service.bus.setting.SettingBizService;
6   -import cn.fw.valhalla.service.data.CustomerService;
7   -import cn.fw.valhalla.service.data.PubCluePoolService;
8   -import cn.fw.valhalla.service.data.StammkundePoolService;
  13 +import cn.fw.valhalla.service.data.*;
9 14 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
10 15 import lombok.AccessLevel;
11 16 import lombok.Getter;
12   -import lombok.RequiredArgsConstructor;
13 17 import lombok.extern.slf4j.Slf4j;
  18 +import org.springframework.beans.factory.annotation.Autowired;
14 19 import org.springframework.beans.factory.annotation.Value;
  20 +import org.springframework.data.redis.core.BoundSetOperations;
  21 +import org.springframework.data.redis.core.StringRedisTemplate;
15 22 import org.springframework.stereotype.Service;
16 23 import org.springframework.transaction.annotation.Transactional;
17 24 import org.springframework.util.CollectionUtils;
18 25  
  26 +import java.time.LocalDateTime;
19 27 import java.util.List;
  28 +import java.util.Objects;
  29 +import java.util.Optional;
  30 +
  31 +import static cn.fw.common.businessvalidator.Validator.BV;
20 32  
21 33 /**
22 34 * 公共池跟进处理
... ... @@ -29,41 +41,149 @@ import java.util.List;
29 41 */
30 42 @Slf4j
31 43 @Service
32   -@RequiredArgsConstructor
33 44 public class PubFollowBizService {
34 45 private final PubCluePoolService pubCluePoolService;
  46 + private final PublicPoolService publicPoolService;
35 47 private final StammkundePoolService stammkundePoolService;
36 48 private final CustomerService customerService;
  49 + private final CustomerBaseInfoService customerBaseInfoService;
37 50 private final SettingBizService settingBizService;
  51 + private final ClueTaskService clueTaskService;
  52 + private final StringRedisTemplate stringRedisTemplate;
  53 + private final OopService oopService;
  54 + private final PubFollowStrategy pubFollowStrategy;
38 55 @Value("${follow.todo.PubFollowCode}")
39 56 @Getter(AccessLevel.PRIVATE)
40 57 private String pubFollowCode;
41 58  
  59 + @Value("${spring.cache.custom.global-prefix}:role-change-need-close:clue")
  60 + @Getter(AccessLevel.PRIVATE)
  61 + private String roleChangeNeedCloseClueKey;
42 62  
43   - @Transactional(rollbackFor = Exception.class)
44   - public void onRoleChange(Long userId, Long shopId) {
45   - try {
46   - List<PubCluePool> list = pubCluePoolService.list(Wrappers.<PubCluePool>lambdaQuery()
47   - .eq(PubCluePool::getAdviserId, userId)
48   - .eq(PubCluePool::getState, PublicClueStateEnum.ONGOING)
49   - );
50   -
51   - if (CollectionUtils.isEmpty(list)) {
52   - return;
53   - }
54   -
  63 + @Autowired
  64 + public PubFollowBizService(final PubCluePoolService pubCluePoolService,
  65 + final PublicPoolService publicPoolService,
  66 + final StammkundePoolService stammkundePoolService,
  67 + final CustomerService customerService,
  68 + final CustomerBaseInfoService customerBaseInfoService,
  69 + final SettingBizService settingBizService,
  70 + final ClueTaskService clueTaskService,
  71 + final StringRedisTemplate stringRedisTemplate,
  72 + final OopService oopService,
  73 + final PubFollowStrategy pubFollowStrategy) {
  74 + this.pubCluePoolService = pubCluePoolService;
  75 + this.publicPoolService = publicPoolService;
  76 + this.stammkundePoolService = stammkundePoolService;
  77 + this.customerService = customerService;
  78 + this.customerBaseInfoService = customerBaseInfoService;
  79 + this.settingBizService = settingBizService;
  80 + this.clueTaskService = clueTaskService;
  81 + this.stringRedisTemplate = stringRedisTemplate;
  82 + this.oopService = oopService;
  83 + this.pubFollowStrategy = pubFollowStrategy;
  84 + }
55 85  
56   - } catch (Exception e) {
  86 + /**
  87 + * 人员角色变动或缓存需要战败的vin
  88 + *
  89 + * @param userId
  90 + * @param shopId
  91 + */
  92 + public void onRoleChange(Long userId, Long shopId) {
  93 + List<PubCluePool> list = pubCluePoolService.list(Wrappers.<PubCluePool>lambdaQuery()
  94 + .eq(PubCluePool::getAdviserId, userId)
  95 + .eq(PubCluePool::getState, PublicClueStateEnum.ONGOING)
  96 + );
  97 + if (CollectionUtils.isEmpty(list)) {
  98 + return;
  99 + }
  100 + BoundSetOperations<String, String> setOps = stringRedisTemplate.boundSetOps(getRoleChangeNeedCloseClueKey());
  101 + for (PubCluePool pool : list) {
  102 + setOps.add(String.valueOf(pool.getId()));
  103 + }
  104 + }
57 105  
  106 + /**
  107 + * 角色变动结束线索
  108 + *
  109 + * @param id
  110 + */
  111 + @Transactional(rollbackFor = Exception.class)
  112 + public void roleChangeDefeatClue(String id) {
  113 + PubCluePool pool = pubCluePoolService.getById(Long.valueOf(id));
  114 + if (Objects.isNull(pool)) {
  115 + return;
  116 + }
  117 + Customer customer = customerService.queryByFrameNo(pool.getVin(), pool.getGroupId());
  118 + endClue(pool);
  119 + if (Objects.nonNull(customer)) {
  120 + customerRemoval(customer);
58 121 }
59 122 }
60 123  
61 124 /**
62 125 * 结束线索
  126 + *
63 127 * @param pool
64 128 */
65 129 public void endClue(PubCluePool pool) {
  130 + ClueTask task = clueTaskService.getOne(Wrappers.<ClueTask>lambdaQuery()
  131 + .eq(ClueTask::getClueId, pool.getId())
  132 + .eq(ClueTask::getType, FollowTypeEnum.PL)
  133 + .eq(ClueTask::getState, TaskStateEnum.ONGOING)
  134 + , Boolean.FALSE);
  135 +
  136 + if (Objects.nonNull(task)) {
  137 + pubFollowStrategy.onRoleChangeCloseTask(task);
  138 + }
  139 + pool.setState(PublicClueStateEnum.DEFEAT);
  140 + pool.setCloseTime(LocalDateTime.now());
  141 + pool.setDefeatReason(TaskDefeatTypeEnum.D);
  142 + pubCluePoolService.updateById(pool);
  143 + }
  144 +
  145 + /**
  146 + * 移除档案到公共池
  147 + *
  148 + * @param customer
  149 + */
  150 + private void customerRemoval(Customer customer) {
  151 + PublicPool publicPool = createPublicPool(customer);
  152 + publicPoolService.save(publicPool);
  153 + stammkundePoolService.reject(customer.getId(), customer.getGroupId(), DefeatReasonEnum.RC);
  154 + customer.setAdviserId(null);
  155 + customer.setShopId(null);
  156 + customerService.updateById(customer);
  157 + }
66 158  
  159 + private PublicPool createPublicPool(Customer customer) {
  160 + final Long shopId = Optional.ofNullable(customer.getLastArrivalShop()).orElse(customer.getShopId());
  161 + ShopDTO shop = oopService.shop(shopId);
  162 + BV.notNull(shop, () -> String.format("门店[%s]信息获取失败", shopId));
  163 + String shopName = shop.getShortName();
  164 + final Long baseId = customer.getBaseId();
  165 + CustomerBaseInfo baseInfo = customerBaseInfoService.getById(baseId);
  166 + BV.notNull(baseInfo, () -> String.format("档案车主信息获取失败[%s]", baseId));
  167 + PublicPool pool = new PublicPool();
  168 + pool.setCustomerId(customer.getId());
  169 + pool.setCustomerName(baseInfo.getName());
  170 + pool.setPlateNo(customer.getPlateNo());
  171 + pool.setFrameNo(customer.getFrameNo());
  172 + pool.setBrandId(customer.getBrandId());
  173 + pool.setBrandName(customer.getBrandName());
  174 + pool.setSeriesId(customer.getSeriesId());
  175 + pool.setSeriesName(customer.getSeriesName());
  176 + pool.setSpecId(customer.getSpecId());
  177 + pool.setSpecName(customer.getSpecName());
  178 + pool.setAddress(baseInfo.getAddress());
  179 + pool.setCompany(baseInfo.getCompanyName());
  180 + pool.setType(PublicPoolTypeEnum.RC);
  181 + pool.setShopId(shopId);
  182 + pool.setShopName(shopName);
  183 + pool.setTimes(customer.getArrivalCount());
  184 + pool.setReason(PublicPoolTypeEnum.RC.getName());
  185 + pool.setGroupId(customer.getGroupId());
  186 + return pool;
67 187 }
68 188  
69 189 }
... ...