Commit 9de0e2d7a508ae01a6557735f636e5d817f329ae
1 parent
1331548a
feature(*): 公共池线索终止逻辑
- 角色调整总之公共池线索跟进 - 公共池跟进到期终止线索 - 线索终止后档案以及专属性的逻辑关系处理
Showing
15 changed files
with
405 additions
and
33 deletions
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
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<Integer> { |
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<Integer> { |
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
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 | } | ... | ... |