Commit 3d6f82701e655f6e13247056ad20862a9adec02a
1 parent
29507dd8
feature(*): 公共池线索开始逻辑
- 公共池线索开始逻辑 - 单种类型待办最大数量限制
Showing
6 changed files
with
226 additions
and
37 deletions
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
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()) | ... | ... |