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 64 shop_id bigint not null comment '门店id',
65 65 shop_name varchar(255) null comment '门店名称',
66 66 group_id bigint not null comment '集团id',
67   - defeat_reason int(3) null comment '关单原因 1:主动放弃 2:进另一门店 3:角色变动战败 4:到期战败',
68 67 create_time datetime not null,
69 68 update_time datetime null,
70 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 115  
117 116 create table if not exists fw_valhalla.pub_clue_pool
118 117 (
119   - id bigint auto_increment
  118 + id bigint auto_increment
120 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 136 constraint pub_clue_pool_customer_id_adviser_id_uindex
136 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 49 */
50 50 private Boolean begun;
51 51 /**
  52 + * 下次跟进时间
  53 + */
  54 + private LocalDate nextTime;
  55 + /**
52 56 * 顾问id
53 57 */
54 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 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 844 protected void createSecondaryTask(FollowClue clue, Long userId) {
858 845 ClueTask redistributionTask = new ClueTask();
859 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 4 import cn.fw.valhalla.domain.db.follow.ClueTask;
5 5 import cn.fw.valhalla.domain.db.follow.FollowClue;
6 6 import cn.fw.valhalla.domain.enums.FollowTypeEnum;
  7 +import cn.fw.valhalla.domain.enums.SettingUnitEnum;
7 8 import cn.fw.valhalla.domain.vo.setting.SettingVO;
8 9 import org.springframework.transaction.annotation.Transactional;
9 10  
10 11 import java.time.LocalDate;
  12 +import java.time.LocalDateTime;
11 13 import java.util.List;
12 14  
13 15 /**
... ... @@ -108,4 +110,18 @@ public interface FollowStrategy {
108 110 */
109 111 @Transactional(rollbackFor = Exception.class)
110 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 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 6 import cn.fw.valhalla.domain.db.OriginalData;
4 7 import cn.fw.valhalla.domain.db.follow.ClueTask;
5 8 import cn.fw.valhalla.domain.db.follow.FollowClue;
6 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 22 import cn.fw.valhalla.service.data.PubCluePoolService;
  23 +import cn.fw.valhalla.service.data.StammkundePoolService;
13 24 import lombok.extern.slf4j.Slf4j;
14 25 import org.springframework.beans.factory.annotation.Autowired;
15 26 import org.springframework.stereotype.Component;
16 27 import org.springframework.transaction.annotation.Transactional;
17 28  
  29 +import java.time.LocalDate;
18 30 import java.time.LocalDateTime;
  31 +import java.util.*;
19 32  
20 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 44 */
31 45 @Slf4j
32 46 @Component
33   -public class PubFollowStrategy extends AbstractFollowStrategy {
  47 +public class PubFollowStrategy implements FollowStrategy {
34 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 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 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 73 @Override
... ... @@ -54,9 +86,44 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
54 86 return false;
55 87 }
56 88  
  89 + /**
  90 + * 公共池线索跟进此方法无效
  91 + *
  92 + * @param followClue
  93 + * @return
  94 + */
57 95 @Override
58 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 129 @Override
... ... @@ -75,6 +142,26 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
75 142 }
76 143  
77 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 165 @Transactional(rollbackFor = Exception.class)
79 166 public void closeTask(final ClueTask task) {
80 167 final Long clueId = task.getClueId();
... ... @@ -93,7 +180,89 @@ public class PubFollowStrategy extends AbstractFollowStrategy {
93 180 pubCluePool.setState(PublicClueStateEnum.DEFEAT);
94 181 pubCluePool.setDefeatReason(task.getReason());
95 182 pubCluePoolService.updateById(pubCluePool);
96   - redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
97 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 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 120 * @param id
... ... @@ -126,6 +137,7 @@ public class PubFollowBizService {
126 137 *
127 138 * @param pool
128 139 */
  140 + @Transactional(rollbackFor = Exception.class)
129 141 public void endClue(PubCluePool pool) {
130 142 ClueTask task = clueTaskService.getOne(Wrappers.<ClueTask>lambdaQuery()
131 143 .eq(ClueTask::getClueId, pool.getId())
... ...