Commit 3d6f82701e655f6e13247056ad20862a9adec02a

Authored by 张志伟
1 parent 29507dd8

feature(*): 公共池线索开始逻辑

- 公共池线索开始逻辑
- 单种类型待办最大数量限制
doc/v2.0/update.sql
@@ -64,7 +64,6 @@ CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info @@ -64,7 +64,6 @@ CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info
64 shop_id bigint not null comment '门店id', 64 shop_id bigint not null comment '门店id',
65 shop_name varchar(255) null comment '门店名称', 65 shop_name varchar(255) null comment '门店名称',
66 group_id bigint not null comment '集团id', 66 group_id bigint not null comment '集团id',
67 - defeat_reason int(3) null comment '关单原因 1:主动放弃 2:进另一门店 3:角色变动战败 4:到期战败',  
68 create_time datetime not null, 67 create_time datetime not null,
69 update_time datetime null, 68 update_time datetime null,
70 constraint pub_stand_staff_info_staff_id_group_id_uindex 69 constraint pub_stand_staff_info_staff_id_group_id_uindex
@@ -116,22 +115,24 @@ create unique index public_pool_frame_no_group_id_uindex @@ -116,22 +115,24 @@ create unique index public_pool_frame_no_group_id_uindex
116 115
117 create table if not exists fw_valhalla.pub_clue_pool 116 create table if not exists fw_valhalla.pub_clue_pool
118 ( 117 (
119 - id bigint auto_increment 118 + id bigint auto_increment
120 primary key, 119 primary key,
121 - vin varchar(128) not null comment '车架号',  
122 - start_time date not null comment '开始时间',  
123 - deadline date not null comment '转换截止时间',  
124 - close_time datetime null comment '关闭时间',  
125 - begun tinyint(1) null comment '是否已经开始',  
126 - state int(3) not null comment '状态: 1、转换中 2、已转换 3、转换失败',  
127 - source_type int(5) null comment '来源类型 1:公共池 2:公共池活动',  
128 - adviser_id bigint not null comment '顾问id',  
129 - adviser_name varchar(32) null comment '顾问名称',  
130 - shop_id bigint not null comment '门店id',  
131 - shop_name varchar(128) null comment '门店名称',  
132 - group_id bigint not null comment '集团id',  
133 - create_time datetime null,  
134 - update_time datetime null, 120 + vin varchar(128) not null comment '车架号',
  121 + start_time date not null comment '开始时间',
  122 + deadline date not null comment '转换截止时间',
  123 + close_time datetime null comment '关闭时间',
  124 + begun tinyint(1) null comment '是否已经开始',
  125 + state int(3) not null comment '状态: 1、转换中 2、已转换 3、转换失败',
  126 + source_type int(5) null comment '来源类型 1:公共池 2:公共池活动',
  127 + next_time date null comment '下次跟进时间',
  128 + adviser_id bigint not null comment '顾问id',
  129 + adviser_name varchar(32) null comment '顾问名称',
  130 + shop_id bigint not null comment '门店id',
  131 + shop_name varchar(128) null comment '门店名称',
  132 + group_id bigint not null comment '集团id',
  133 + defeat_reason int(3) null comment '关单原因 1:主动放弃 2:进另一门店 3:角色变动战败 4:到期战败',
  134 + create_time datetime null,
  135 + update_time datetime null,
135 constraint pub_clue_pool_customer_id_adviser_id_uindex 136 constraint pub_clue_pool_customer_id_adviser_id_uindex
136 unique (vin, adviser_id) 137 unique (vin, adviser_id)
137 ) 138 )
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/pub/PubCluePool.java
@@ -49,6 +49,10 @@ public class PubCluePool extends BaseAuditableTimeEntity<PubCluePool, Long> { @@ -49,6 +49,10 @@ public class PubCluePool extends BaseAuditableTimeEntity<PubCluePool, Long> {
49 */ 49 */
50 private Boolean begun; 50 private Boolean begun;
51 /** 51 /**
  52 + * 下次跟进时间
  53 + */
  54 + private LocalDate nextTime;
  55 + /**
52 * 顾问id 56 * 顾问id
53 */ 57 */
54 private Long adviserId; 58 private Long adviserId;
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
@@ -841,19 +841,6 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { @@ -841,19 +841,6 @@ public abstract class AbstractFollowStrategy implements FollowStrategy {
841 return dynamicMap; 841 return dynamicMap;
842 } 842 }
843 843
844 - protected LocalDateTime calTime(LocalDateTime baseTime, SettingUnitEnum unit, long value) {  
845 - switch (unit) {  
846 - case HOUR:  
847 - return baseTime.plusHours(value);  
848 - case MONTH:  
849 - return baseTime.plusMonths(value);  
850 - case MINUTE:  
851 - return baseTime.plusMinutes(value);  
852 - default:  
853 - return baseTime.plusDays(value);  
854 - }  
855 - }  
856 -  
857 protected void createSecondaryTask(FollowClue clue, Long userId) { 844 protected void createSecondaryTask(FollowClue clue, Long userId) {
858 ClueTask redistributionTask = new ClueTask(); 845 ClueTask redistributionTask = new ClueTask();
859 redistributionTask.setClueId(clue.getId()); 846 redistributionTask.setClueId(clue.getId());
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java
@@ -4,10 +4,12 @@ import cn.fw.valhalla.domain.db.OriginalData; @@ -4,10 +4,12 @@ import cn.fw.valhalla.domain.db.OriginalData;
4 import cn.fw.valhalla.domain.db.follow.ClueTask; 4 import cn.fw.valhalla.domain.db.follow.ClueTask;
5 import cn.fw.valhalla.domain.db.follow.FollowClue; 5 import cn.fw.valhalla.domain.db.follow.FollowClue;
6 import cn.fw.valhalla.domain.enums.FollowTypeEnum; 6 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  7 +import cn.fw.valhalla.domain.enums.SettingUnitEnum;
7 import cn.fw.valhalla.domain.vo.setting.SettingVO; 8 import cn.fw.valhalla.domain.vo.setting.SettingVO;
8 import org.springframework.transaction.annotation.Transactional; 9 import org.springframework.transaction.annotation.Transactional;
9 10
10 import java.time.LocalDate; 11 import java.time.LocalDate;
  12 +import java.time.LocalDateTime;
11 import java.util.List; 13 import java.util.List;
12 14
13 /** 15 /**
@@ -108,4 +110,18 @@ public interface FollowStrategy { @@ -108,4 +110,18 @@ public interface FollowStrategy {
108 */ 110 */
109 @Transactional(rollbackFor = Exception.class) 111 @Transactional(rollbackFor = Exception.class)
110 void syncEndTask(ClueTask task); 112 void syncEndTask(ClueTask task);
  113 +
  114 +
  115 + default LocalDateTime calTime(LocalDateTime baseTime, SettingUnitEnum unit, long value) {
  116 + switch (unit) {
  117 + case HOUR:
  118 + return baseTime.plusHours(value);
  119 + case MONTH:
  120 + return baseTime.plusMonths(value);
  121 + case MINUTE:
  122 + return baseTime.plusMinutes(value);
  123 + default:
  124 + return baseTime.plusDays(value);
  125 + }
  126 + }
111 } 127 }
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/PubFollowStrategy.java
1 package cn.fw.valhalla.service.bus.follow.strategy.impl; 1 package cn.fw.valhalla.service.bus.follow.strategy.impl;
2 2
  3 +import cn.fw.shirasawa.sdk.enums.BusinessTypeEnum;
  4 +import cn.fw.shirasawa.sdk.enums.DataTypeEnum;
  5 +import cn.fw.valhalla.common.utils.DateUtil;
3 import cn.fw.valhalla.domain.db.OriginalData; 6 import cn.fw.valhalla.domain.db.OriginalData;
4 import cn.fw.valhalla.domain.db.follow.ClueTask; 7 import cn.fw.valhalla.domain.db.follow.ClueTask;
5 import cn.fw.valhalla.domain.db.follow.FollowClue; 8 import cn.fw.valhalla.domain.db.follow.FollowClue;
6 import cn.fw.valhalla.domain.db.pub.PubCluePool; 9 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; 10 +import cn.fw.valhalla.domain.dto.CustomerDetailDto;
  11 +import cn.fw.valhalla.domain.enums.*;
  12 +import cn.fw.valhalla.domain.vo.setting.SettingVO;
  13 +import cn.fw.valhalla.rpc.oop.OopService;
  14 +import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
  15 +import cn.fw.valhalla.rpc.shirasawa.ShirasawaRpcService;
  16 +import cn.fw.valhalla.rpc.shirasawa.dto.ClueStopDTO;
  17 +import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO;
  18 +import cn.fw.valhalla.service.bus.cust.CustomerBizService;
  19 +import cn.fw.valhalla.service.bus.follow.strategy.FollowStrategy;
  20 +import cn.fw.valhalla.service.bus.setting.SettingBizService;
  21 +import cn.fw.valhalla.service.data.ClueTaskService;
12 import cn.fw.valhalla.service.data.PubCluePoolService; 22 import cn.fw.valhalla.service.data.PubCluePoolService;
  23 +import cn.fw.valhalla.service.data.StammkundePoolService;
13 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
14 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.stereotype.Component; 26 import org.springframework.stereotype.Component;
16 import org.springframework.transaction.annotation.Transactional; 27 import org.springframework.transaction.annotation.Transactional;
17 28
  29 +import java.time.LocalDate;
18 import java.time.LocalDateTime; 30 import java.time.LocalDateTime;
  31 +import java.util.*;
19 32
20 import static cn.fw.common.businessvalidator.Validator.BV; 33 import static cn.fw.common.businessvalidator.Validator.BV;
  34 +import static cn.fw.valhalla.service.bus.setting.strategy.SettingStrategy.COMMON_BRAND_ID;
21 35
22 /** 36 /**
23 * 公共池线索跟进 37 * 公共池线索跟进
@@ -30,12 +44,30 @@ import static cn.fw.common.businessvalidator.Validator.BV; @@ -30,12 +44,30 @@ import static cn.fw.common.businessvalidator.Validator.BV;
30 */ 44 */
31 @Slf4j 45 @Slf4j
32 @Component 46 @Component
33 -public class PubFollowStrategy extends AbstractFollowStrategy { 47 +public class PubFollowStrategy implements FollowStrategy {
34 private final PubCluePoolService pubCluePoolService; 48 private final PubCluePoolService pubCluePoolService;
  49 + private final ClueTaskService clueTaskService;
  50 + private final CustomerBizService customerBizService;
  51 + private final ShirasawaRpcService shirasawaRpcService;
  52 + private final OopService oopService;
  53 + private final SettingBizService settingBizService;
  54 + private final StammkundePoolService stammkundePoolService;
35 55
36 @Autowired 56 @Autowired
37 - public PubFollowStrategy(final PubCluePoolService pubCluePoolService) { 57 + public PubFollowStrategy(final PubCluePoolService pubCluePoolService,
  58 + final ClueTaskService clueTaskService,
  59 + final CustomerBizService customerBizService,
  60 + final ShirasawaRpcService shirasawaRpcService,
  61 + final OopService oopService,
  62 + final SettingBizService settingBizService,
  63 + final StammkundePoolService stammkundePoolService) {
38 this.pubCluePoolService = pubCluePoolService; 64 this.pubCluePoolService = pubCluePoolService;
  65 + this.clueTaskService = clueTaskService;
  66 + this.customerBizService = customerBizService;
  67 + this.shirasawaRpcService = shirasawaRpcService;
  68 + this.oopService = oopService;
  69 + this.settingBizService = settingBizService;
  70 + this.stammkundePoolService = stammkundePoolService;
39 } 71 }
40 72
41 @Override 73 @Override
@@ -54,9 +86,44 @@ public class PubFollowStrategy extends AbstractFollowStrategy { @@ -54,9 +86,44 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
54 return false; 86 return false;
55 } 87 }
56 88
  89 + /**
  90 + * 公共池线索跟进此方法无效
  91 + *
  92 + * @param followClue
  93 + * @return
  94 + */
57 @Override 95 @Override
58 public void startClue(final FollowClue followClue) { 96 public void startClue(final FollowClue followClue) {
  97 + }
59 98
  99 + @Override
  100 + public void settingChanged(List<SettingVO> setting, Long groupId) {
  101 + // 更改设置不影响公共池线索跟进
  102 + }
  103 +
  104 + @Override
  105 + public void forceStopClue(final FollowClue clue) {
  106 +
  107 + }
  108 +
  109 +
  110 + public void startClue(final PubCluePool pubClue) {
  111 + ClueTask clueTask = new ClueTask();
  112 + clueTask.setClueId(pubClue.getId());
  113 + clueTask.setType(getFollowType());
  114 + clueTask.setBeginTime(pubClue.getStartTime().atStartOfDay());
  115 + clueTask.setRedistribution(Boolean.FALSE);
  116 + clueTask.setDeadline(pubClue.getDeadline().atStartOfDay());
  117 + clueTask.setState(TaskStateEnum.ONGOING);
  118 + clueTask.setGroupId(pubClue.getGroupId());
  119 + clueTask.setFollowShop(pubClue.getShopId());
  120 + clueTask.setFollowUser(pubClue.getAdviserId());
  121 + clueTask.setFollowUserName(pubClue.getAdviserName());
  122 + clueTaskService.save(clueTask);
  123 +
  124 + final FollowInitDTO followInitDTO = creteFollowInitDTO(pubClue, clueTask);
  125 + pubClue.setNextTime(clueTask.getDeadline().plusDays(1L).toLocalDate());
  126 + shirasawaRpcService.createFollowData(followInitDTO);
60 } 127 }
61 128
62 @Override 129 @Override
@@ -75,6 +142,26 @@ public class PubFollowStrategy extends AbstractFollowStrategy { @@ -75,6 +142,26 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
75 } 142 }
76 143
77 @Override 144 @Override
  145 + public void forceStopTask(final ClueTask task) {
  146 +
  147 + }
  148 +
  149 + @Override
  150 + public void onFollowComplete(final ClueTask task, final Long preRecordId, final LocalDate originTime, final boolean overdue) {
  151 +
  152 + }
  153 +
  154 + @Override
  155 + public void createNextFollowTodo(final FollowClue clue) {
  156 +
  157 + }
  158 +
  159 + @Override
  160 + public void syncEndTask(final ClueTask task) {
  161 +
  162 + }
  163 +
  164 + @Override
78 @Transactional(rollbackFor = Exception.class) 165 @Transactional(rollbackFor = Exception.class)
79 public void closeTask(final ClueTask task) { 166 public void closeTask(final ClueTask task) {
80 final Long clueId = task.getClueId(); 167 final Long clueId = task.getClueId();
@@ -93,7 +180,89 @@ public class PubFollowStrategy extends AbstractFollowStrategy { @@ -93,7 +180,89 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
93 pubCluePool.setState(PublicClueStateEnum.DEFEAT); 180 pubCluePool.setState(PublicClueStateEnum.DEFEAT);
94 pubCluePool.setDefeatReason(task.getReason()); 181 pubCluePool.setDefeatReason(task.getReason());
95 pubCluePoolService.updateById(pubCluePool); 182 pubCluePoolService.updateById(pubCluePool);
96 - redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));  
97 customerBizService.pubTaskEndAbandon(pubCluePool); 183 customerBizService.pubTaskEndAbandon(pubCluePool);
98 } 184 }
  185 +
  186 + private boolean rpcStopTask(ClueTask clueTask) {
  187 + ClueStopDTO clueStopDTO = new ClueStopDTO();
  188 + clueStopDTO.setType(DataTypeEnum.ofValue(clueTask.getType().getValue()));
  189 + clueStopDTO.setBusinessType(BusinessTypeEnum.AS);
  190 + if (TaskStateEnum.DEFEAT.equals(clueTask.getState())) {
  191 + clueStopDTO.setTermination(Boolean.TRUE);
  192 + }
  193 + clueStopDTO.setDetailId(String.valueOf(clueTask.getId()));
  194 + clueStopDTO.setShopId(clueTask.getFinishShop());
  195 + ShopDTO shop = oopService.shop(clueTask.getFinishShop());
  196 + if (Objects.nonNull(shop)) {
  197 + clueStopDTO.setShopName(shop.getShortName());
  198 + }
  199 + clueStopDTO.setCompleteTime(DateUtil.localDateTime2Date(clueTask.getCloseTime()));
  200 + clueStopDTO.setGroupId(clueTask.getGroupId());
  201 + clueStopDTO.setUserId(clueTask.getFollowUser());
  202 + clueStopDTO.setUserName(clueTask.getFollowUserName());
  203 + return shirasawaRpcService.stopTask(clueStopDTO);
  204 + }
  205 +
  206 + private FollowInitDTO creteFollowInitDTO(PubCluePool pubClue, ClueTask clueTask) {
  207 + CustomerDetailDto customerDetailDto = customerBizService.queryByFrameNo(pubClue.getVin(), pubClue.getGroupId());
  208 + BV.notNull(customerDetailDto, () -> "档案信息有误");
  209 +
  210 + final FollowInitDTO followInitDTO = FollowInitDTO.builder()
  211 + .businessType(BusinessTypeEnum.AS)
  212 + .type(DataTypeEnum.ofValue(getFollowType().getValue()))
  213 + .customerId(customerDetailDto.getId())
  214 + .customerName(customerDetailDto.getName())
  215 + .memberId(customerDetailDto.getMemberId())
  216 + .plateNo(customerDetailDto.getPlateNo())
  217 + .frameNo(pubClue.getVin())
  218 + .contacts(customerDetailDto.getMobile())
  219 + .detailId(String.valueOf(clueTask.getId()))
  220 + .generateTime(DateUtil.localDateTime2Date(clueTask.getBeginTime()))
  221 + .deadline(DateUtil.localDateTime2Date(clueTask.getDeadline()))
  222 + .groupId(clueTask.getGroupId())
  223 + .shopId(clueTask.getFollowShop())
  224 + .userId(clueTask.getFollowUser())
  225 + .userName(clueTask.getFollowUserName())
  226 + .bizId(pubClue.getVin())
  227 + .secondary(Boolean.FALSE)
  228 + .build();
  229 + followInitDTO.setShopName(pubClue.getShopName());
  230 + // 除事故车以外,其他待办跟进时长统一配置
  231 + Optional<SettingVO> setting = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.EFFECTIVE_TIME, clueTask.getGroupId(), COMMON_BRAND_ID);
  232 + setting.ifPresent(r -> {
  233 + LocalDateTime dateTime = calTime(clueTask.getBeginTime(), Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit())), r.getDetailValue());
  234 + followInitDTO.setFirstRecordDeadline(DateUtil.localDateTime2Date(dateTime.minusSeconds(1L)));
  235 + });
  236 + Map<String, String> noteMap = createNoteMap(pubClue, customerDetailDto);
  237 + followInitDTO.setNoteMap(noteMap);
  238 + return followInitDTO;
  239 + }
  240 +
  241 +
  242 + private Map<String, String> createNoteMap(PubCluePool pubClue, CustomerDetailDto detailDto) {
  243 + Map<String, String> dynamicMap = new HashMap<>();
  244 + if (Objects.nonNull(pubClue)) {
  245 + int count = Optional.ofNullable(detailDto.getArrivalCount()).orElse(0);
  246 + Date buyDate = detailDto.getBuyDate();
  247 + Date expires = detailDto.getInsuranceExpires();
  248 +
  249 + String name = detailDto.getName();
  250 + String vin = pubClue.getVin();
  251 + String arrivalCount = String.valueOf(count);
  252 + String defeatCount = "0";
  253 + String vehicleAge = String.valueOf(Math.abs(DateUtil.sub(buyDate, new Date(), "y")));
  254 + String _buyDate = DateUtil.getStringDateShort(buyDate);
  255 + String insuranceExpires = DateUtil.getStringDateShort(expires);
  256 +
  257 + dynamicMap.put("name", name);
  258 + dynamicMap.put("vin", vin);
  259 + dynamicMap.put("arrivalCount", arrivalCount);
  260 + dynamicMap.put("defeatCount", defeatCount);
  261 + dynamicMap.put("vehicleAge", vehicleAge + "年");
  262 + dynamicMap.put("buyDate", _buyDate);
  263 + dynamicMap.put("insuranceExpires", insuranceExpires);
  264 + }
  265 + return dynamicMap;
  266 + }
  267 +
99 } 268 }
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubFollowBizService.java
@@ -104,6 +104,17 @@ public class PubFollowBizService { @@ -104,6 +104,17 @@ public class PubFollowBizService {
104 } 104 }
105 105
106 /** 106 /**
  107 + * 开始线索
  108 + * @param pool
  109 + */
  110 + @Transactional(rollbackFor = Exception.class)
  111 + public void startClue(PubCluePool pool) {
  112 + pubFollowStrategy.startClue(pool);
  113 + pool.setBegun(Boolean.TRUE);
  114 + pubCluePoolService.updateById(pool);
  115 + }
  116 +
  117 + /**
107 * 角色变动结束线索 118 * 角色变动结束线索
108 * 119 *
109 * @param id 120 * @param id
@@ -126,6 +137,7 @@ public class PubFollowBizService { @@ -126,6 +137,7 @@ public class PubFollowBizService {
126 * 137 *
127 * @param pool 138 * @param pool
128 */ 139 */
  140 + @Transactional(rollbackFor = Exception.class)
129 public void endClue(PubCluePool pool) { 141 public void endClue(PubCluePool pool) {
130 ClueTask task = clueTaskService.getOne(Wrappers.<ClueTask>lambdaQuery() 142 ClueTask task = clueTaskService.getOne(Wrappers.<ClueTask>lambdaQuery()
131 .eq(ClueTask::getClueId, pool.getId()) 143 .eq(ClueTask::getClueId, pool.getId())