Commit b245c23a44ca3544ea7b0eadc1a6fa45858c45b4
1 parent
8cd965a1
feature(*): 续保跟进调整
- 续保跟进调整
Showing
7 changed files
with
139 additions
and
29 deletions
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/shirasawa/ShirasawaRpcService.java
... | ... | @@ -7,6 +7,7 @@ import cn.fw.shirasawa.sdk.param.FollowChangeUserDTO; |
7 | 7 | import cn.fw.shirasawa.sdk.param.FollowGenerateDTO; |
8 | 8 | import cn.fw.shirasawa.sdk.param.TaskCompleteDTO; |
9 | 9 | import cn.fw.shirasawa.sdk.param.TerminationDTO; |
10 | +import cn.fw.valhalla.common.utils.DateUtil; | |
10 | 11 | import cn.fw.valhalla.rpc.shirasawa.dto.ClueStopDTO; |
11 | 12 | import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO; |
12 | 13 | import lombok.RequiredArgsConstructor; |
... | ... | @@ -14,6 +15,7 @@ import lombok.extern.slf4j.Slf4j; |
14 | 15 | import org.springframework.beans.BeanUtils; |
15 | 16 | import org.springframework.stereotype.Service; |
16 | 17 | |
18 | +import java.time.LocalDate; | |
17 | 19 | import java.util.Objects; |
18 | 20 | import java.util.Optional; |
19 | 21 | |
... | ... | @@ -87,19 +89,36 @@ public class ShirasawaRpcService { |
87 | 89 | * 变更跟进人数据 |
88 | 90 | * |
89 | 91 | * @param dto |
92 | + * @param nextTime | |
90 | 93 | */ |
91 | - public void changeFollowData(final FollowInitDTO dto) { | |
94 | + public void changeFollowData(final FollowInitDTO dto, LocalDate nextTime) { | |
92 | 95 | FollowChangeUserDTO followChangeUserDTO = new FollowChangeUserDTO(); |
93 | 96 | followChangeUserDTO.setType(dto.getType()); |
94 | 97 | followChangeUserDTO.setBusinessType(dto.getBusinessType()); |
95 | 98 | followChangeUserDTO.setDetailId(dto.getDetailId()); |
96 | 99 | followChangeUserDTO.setShopId(dto.getShopId()); |
97 | 100 | followChangeUserDTO.setUserId(dto.getUserId()); |
101 | + followChangeUserDTO.setRecommendNextTime(DateUtil.localDate2Date(nextTime)); | |
98 | 102 | final Message<Void> msg = followApiService.taskChangeUser(followChangeUserDTO); |
99 | 103 | BV.isTrue(msg.isSuccess(), msg::getResult); |
100 | 104 | } |
101 | 105 | |
102 | 106 | /** |
107 | + * 变更下次跟进时间 | |
108 | + * | |
109 | + * @param dataType dataType | |
110 | + * @param detailId detailId | |
111 | + * @param nextTime nextTime | |
112 | + */ | |
113 | + public void updateNextTime(Integer dataType, | |
114 | + String detailId, | |
115 | + LocalDate nextTime) { | |
116 | + long time = DateUtil.localDate2Date(nextTime).getTime(); | |
117 | + final Message<Void> msg = followApiService.updateFollowNextTime(dataType, detailId, time); | |
118 | + BV.isTrue(msg.isSuccess(), msg::getResult); | |
119 | + } | |
120 | + | |
121 | + /** | |
103 | 122 | * 查询是否有未完成的待办 |
104 | 123 | * |
105 | 124 | * @param userId | ... | ... |
fw-valhalla-sdk/pom.xml
... | ... | @@ -37,8 +37,9 @@ |
37 | 37 | <scope>provided</scope> |
38 | 38 | </dependency> |
39 | 39 | <dependency> |
40 | - <groupId>cn.fw</groupId> | |
41 | - <artifactId>fw-common-data</artifactId> | |
40 | + <groupId>com.baomidou</groupId> | |
41 | + <artifactId>mybatis-plus-extension</artifactId> | |
42 | + <scope>provided</scope> | |
42 | 43 | </dependency> |
43 | 44 | </dependencies> |
44 | 45 | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java
... | ... | @@ -23,6 +23,7 @@ import cn.fw.valhalla.domain.enums.*; |
23 | 23 | import cn.fw.valhalla.domain.query.LeaveQueryVO; |
24 | 24 | import cn.fw.valhalla.domain.vo.DistributableVO; |
25 | 25 | import cn.fw.valhalla.domain.vo.LeaveNeedDoVO; |
26 | +import cn.fw.valhalla.domain.vo.setting.SettingVO; | |
26 | 27 | import cn.fw.valhalla.rpc.backlog.TodoRpcService; |
27 | 28 | import cn.fw.valhalla.rpc.backlog.dto.BackLogItemDTO; |
28 | 29 | import cn.fw.valhalla.rpc.ehr.EhrRpcService; |
... | ... | @@ -33,7 +34,9 @@ import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO; |
33 | 34 | import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; |
34 | 35 | import cn.fw.valhalla.rpc.oop.OopService; |
35 | 36 | import cn.fw.valhalla.rpc.oop.dto.ShopDTO; |
37 | +import cn.fw.valhalla.rpc.shirasawa.ShirasawaRpcService; | |
36 | 38 | import cn.fw.valhalla.service.bus.follow.FollowBizService; |
39 | +import cn.fw.valhalla.service.bus.setting.SettingBizService; | |
37 | 40 | import cn.fw.valhalla.service.data.*; |
38 | 41 | import com.alibaba.fastjson.JSONObject; |
39 | 42 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
... | ... | @@ -52,6 +55,7 @@ import java.util.*; |
52 | 55 | import java.util.stream.Collectors; |
53 | 56 | |
54 | 57 | import static cn.fw.common.businessvalidator.Validator.BV; |
58 | +import static cn.fw.valhalla.service.bus.setting.strategy.SettingStrategy.COMMON_BRAND_ID; | |
55 | 59 | |
56 | 60 | /** |
57 | 61 | * @author : kurisu |
... | ... | @@ -75,7 +79,8 @@ public class LeaveNeedDoBizService { |
75 | 79 | private final FollowClueService followClueService; |
76 | 80 | private final ClueTaskService clueTaskService; |
77 | 81 | private final CustAfterDistProducer custAfterDistProducer; |
78 | - | |
82 | + private final ShirasawaRpcService shirasawaRpcService; | |
83 | + private final SettingBizService settingBizService; | |
79 | 84 | /** |
80 | 85 | * Redis工具 |
81 | 86 | */ |
... | ... | @@ -215,16 +220,35 @@ public class LeaveNeedDoBizService { |
215 | 220 | if (Objects.isNull(leaveNeedDo)) { |
216 | 221 | return; |
217 | 222 | } |
223 | + | |
218 | 224 | List<ClueTask> list = clueTaskService.list(Wrappers.<ClueTask>lambdaQuery() |
219 | 225 | .in(ClueTask::getType, FollowTypeEnum.FM, FollowTypeEnum.RM) |
220 | 226 | .eq(ClueTask::getState, TaskStateEnum.ONGOING) |
221 | 227 | .eq(ClueTask::getFollowUser, leaveNeedDo.getUserId()) |
222 | 228 | ); |
223 | - if (CollectionUtils.isEmpty(list)) { | |
224 | - return; | |
229 | + if (!CollectionUtils.isEmpty(list)) { | |
230 | + for (ClueTask task : list) { | |
231 | + followBizService.roleChangeEndTask(task); | |
232 | + } | |
225 | 233 | } |
226 | - for (ClueTask task : list) { | |
227 | - followBizService.roleChangeEndTask(task); | |
234 | + | |
235 | + List<ClueTask> irlist = clueTaskService.list(Wrappers.<ClueTask>lambdaQuery() | |
236 | + .eq(ClueTask::getType, FollowTypeEnum.IR) | |
237 | + .eq(ClueTask::getState, TaskStateEnum.ONGOING) | |
238 | + .eq(ClueTask::getFollowUser, leaveNeedDo.getUserId()) | |
239 | + ); | |
240 | + | |
241 | + if (!CollectionUtils.isEmpty(irlist)) { | |
242 | + Long groupId = irlist.get(0).getGroupId(); | |
243 | + Optional<SettingVO> settingVO = settingBizService.querySettingByType(FollowTypeEnum.IR, SettingTypeEnum.MODE, groupId, COMMON_BRAND_ID); | |
244 | + // 模式 1、续保角色 2、续保角色+服务接待/新车销售 | |
245 | + final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1); | |
246 | + if (mode == 1) { | |
247 | + return; | |
248 | + } | |
249 | + for (ClueTask task : irlist) { | |
250 | + followBizService.roleChangeEndTask(task); | |
251 | + } | |
228 | 252 | } |
229 | 253 | } |
230 | 254 | |
... | ... | @@ -245,8 +269,15 @@ public class LeaveNeedDoBizService { |
245 | 269 | if (CollectionUtils.isEmpty(list)) { |
246 | 270 | return; |
247 | 271 | } |
272 | + Long groupId = list.get(0).getGroupId(); | |
273 | + Optional<SettingVO> settingVO = settingBizService.querySettingByType(FollowTypeEnum.IR, SettingTypeEnum.MODE, groupId, COMMON_BRAND_ID); | |
274 | + // 模式 1、续保角色 2、续保角色+服务接待/新车销售 | |
275 | + final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1); | |
248 | 276 | |
249 | 277 | for (ClueTask task : list) { |
278 | + if (mode != 1) { | |
279 | + shirasawaRpcService.updateNextTime(FollowTypeEnum.IR.getValue(), String.valueOf(task.getClueId()), task.getDeadline().plusDays(1L).toLocalDate()); | |
280 | + } | |
250 | 281 | followBizService.roleChangeEndTask(task); |
251 | 282 | } |
252 | 283 | } | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
... | ... | @@ -734,14 +734,10 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { |
734 | 734 | redistributionTask.setRpcSuccess(Boolean.FALSE); |
735 | 735 | clueTaskService.save(redistributionTask); |
736 | 736 | FollowInitDTO followInitDTO = creteRedistributionFollowInitDTO(clue, redistributionTask); |
737 | - shirasawaRpcService.changeFollowData(followInitDTO); | |
737 | + shirasawaRpcService.changeFollowData(followInitDTO, redistributionTask.getBeginTime().toLocalDate()); | |
738 | 738 | followClueService.updateById(clue); |
739 | 739 | } |
740 | 740 | |
741 | - protected String generateAddKey() { | |
742 | - return String.format("%s:%s", getClueChangeKeyPrefix(), "ADD"); | |
743 | - } | |
744 | - | |
745 | 741 | protected String generateStopKey() { |
746 | 742 | return String.format("%s:%s", getClueChangeKeyPrefix(), "STOP"); |
747 | 743 | } | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java
... | ... | @@ -150,6 +150,9 @@ public class IRFollowStrategy extends AbstractFollowStrategy { |
150 | 150 | Long clueId = task.getClueId(); |
151 | 151 | FollowClue clue = followClueService.getById(clueId); |
152 | 152 | BV.notNull(clue, () -> "跟进线索不存在: " + clueId); |
153 | + Customer customer = customerService.queryByFrameNo(clue.getVin(), clue.getGroupId()); | |
154 | + Long adviserId = Optional.ofNullable(customer).map(Customer::getAdviserId).orElse(null); | |
155 | + | |
153 | 156 | Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, clue.getGroupId(), COMMON_BRAND_ID); |
154 | 157 | // 模式 1、续保角色 2、续保角色+服务接待/新车销售 |
155 | 158 | final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1); |
... | ... | @@ -165,17 +168,24 @@ public class IRFollowStrategy extends AbstractFollowStrategy { |
165 | 168 | PostUserDTO userDTO = userByRole.get(randomIndex); |
166 | 169 | createSecondaryTask(clue, userDTO.getUserId()); |
167 | 170 | } else { |
168 | - Customer customer = customerService.queryByFrameNo(clue.getVin(), clue.getGroupId()); | |
169 | - Long adviserId = Optional.ofNullable(customer).map(Customer::getAdviserId).orElse(null); | |
170 | 171 | if (Objects.isNull(adviserId)) { |
171 | - boolean rpcSucess = rpcStopTask(task); | |
172 | - if (!rpcSucess) { | |
173 | - log.info("跟进系统终止任务失败"); | |
172 | + List<PostUserDTO> userByRole = userService.getShopRolesUser(task.getFollowShop(), RoleCode.XBGJ, RoleCode.FWGW); | |
173 | + BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode)); | |
174 | + int randomIndex = new Random().nextInt(userByRole.size()); | |
175 | + PostUserDTO userDTO = userByRole.get(randomIndex); | |
176 | + adviserId = userDTO.getUserId(); | |
177 | + } else { | |
178 | + if (task.getFollowUser().equals(adviserId)) { | |
179 | + return; | |
174 | 180 | } |
175 | - task.setRpcSuccess(rpcSucess); | |
176 | - clueTaskService.updateById(task); | |
177 | - return; | |
178 | 181 | } |
182 | + | |
183 | + boolean rpcSucess = rpcStopTask(task); | |
184 | + if (!rpcSucess) { | |
185 | + log.info("跟进系统终止任务失败"); | |
186 | + } | |
187 | + task.setRpcSuccess(rpcSucess); | |
188 | + clueTaskService.updateById(task); | |
179 | 189 | this.createSecondaryTask(clue, adviserId); |
180 | 190 | } |
181 | 191 | } |
... | ... | @@ -201,10 +211,12 @@ public class IRFollowStrategy extends AbstractFollowStrategy { |
201 | 211 | Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, clue.getGroupId(), COMMON_BRAND_ID); |
202 | 212 | // 模式 1、续保角色 2、续保角色+服务接待/新车销售 |
203 | 213 | final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1); |
204 | - CustomerDetailVO detailByVin = customerBizService.getDetailByVin(clue.getVin(), clue.getGroupId()); | |
205 | - Long aLong = Optional.ofNullable(detailByVin).map(CustomerDetailVO::getAdviserId).orElse(null); | |
206 | - if (task.getFollowUser().equals(aLong)) { | |
207 | - customerBizService.abandon(detailByVin.getId(), "主动放弃"); | |
214 | + if (mode != 1) { | |
215 | + CustomerDetailVO detailByVin = customerBizService.getDetailByVin(clue.getVin(), clue.getGroupId()); | |
216 | + Long aLong = Optional.ofNullable(detailByVin).map(CustomerDetailVO::getAdviserId).orElse(null); | |
217 | + if (task.getFollowUser().equals(aLong)) { | |
218 | + customerBizService.abandon(detailByVin.getId(), "主动放弃"); | |
219 | + } | |
208 | 220 | } |
209 | 221 | } |
210 | 222 | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubDistributeBizService.java
1 | 1 | package cn.fw.valhalla.service.bus.pub; |
2 | 2 | |
3 | +import cn.fw.valhalla.common.constant.RoleCode; | |
3 | 4 | import cn.fw.valhalla.common.utils.DateUtil; |
4 | 5 | import cn.fw.valhalla.domain.db.customer.AffiliationRecord; |
5 | 6 | import cn.fw.valhalla.domain.db.customer.Customer; |
7 | +import cn.fw.valhalla.domain.db.follow.ClueTask; | |
6 | 8 | import cn.fw.valhalla.domain.db.follow.FollowClue; |
7 | 9 | import cn.fw.valhalla.domain.db.pool.StammkundePool; |
8 | 10 | import cn.fw.valhalla.domain.db.pub.PubCluePool; |
9 | 11 | import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo; |
10 | 12 | import cn.fw.valhalla.domain.enums.*; |
11 | 13 | import cn.fw.valhalla.domain.vo.setting.SettingVO; |
14 | +import cn.fw.valhalla.rpc.erp.UserService; | |
15 | +import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; | |
12 | 16 | import cn.fw.valhalla.rpc.mkt.MktRpcService; |
13 | 17 | import cn.fw.valhalla.rpc.mkt.dto.QualificationDTO; |
14 | 18 | import cn.fw.valhalla.rpc.oop.OopService; |
... | ... | @@ -45,7 +49,9 @@ import java.util.stream.Collectors; |
45 | 49 | @Slf4j |
46 | 50 | public class PubDistributeBizService { |
47 | 51 | private final OopService oopService; |
52 | + private final UserService userService; | |
48 | 53 | private final FollowClueService followClueService; |
54 | + private final ClueTaskService clueTaskService; | |
49 | 55 | private final ShirasawaRpcService shirasawaRpcService; |
50 | 56 | private final PublicPoolService publicPoolService; |
51 | 57 | private final CustomerService customerService; |
... | ... | @@ -211,7 +217,7 @@ public class PubDistributeBizService { |
211 | 217 | PubStandType standType = Optional.ofNullable(staffInfo.getStandType()).orElse(PubStandType.PUB); |
212 | 218 | switch (standType) { |
213 | 219 | case PUB: |
214 | - vinArr = vinList.subList(0, count); | |
220 | + vinArr = determinePub(vinList, staffInfo, count); | |
215 | 221 | break; |
216 | 222 | case ACTIVITY: |
217 | 223 | vinArr = determineMkt(vinList, staffInfo, count); |
... | ... | @@ -223,6 +229,51 @@ public class PubDistributeBizService { |
223 | 229 | } |
224 | 230 | |
225 | 231 | /** |
232 | + * 分配档案 | |
233 | + * | |
234 | + * @param vinList | |
235 | + * @param staffInfo | |
236 | + * @param count | |
237 | + * @return | |
238 | + */ | |
239 | + private List<String> determinePub(List<String> vinList, PubStandStaffInfo staffInfo, int count) { | |
240 | + List<String> list = new ArrayList<>(); | |
241 | + for (String vin : vinList) { | |
242 | + if (list.size() >= count) { | |
243 | + break; | |
244 | + } | |
245 | + Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId()); | |
246 | + if (Objects.isNull(customer)) { | |
247 | + continue; | |
248 | + } | |
249 | + boolean hasDefeat = affiliationRecordService.count(Wrappers.<AffiliationRecord>lambdaQuery() | |
250 | + .eq(AffiliationRecord::getCustomerId, customer.getId()) | |
251 | + .eq(AffiliationRecord::getOriginUserId, staffInfo.getStaffId()) | |
252 | + .ge(AffiliationRecord::getDefeatTime, DateUtil.localDate2Date(LocalDate.now().minusMonths(12L))) | |
253 | + ) > 1; | |
254 | + if (hasDefeat) { | |
255 | + continue; | |
256 | + } | |
257 | + FollowClue clue = followClueService.getOne(Wrappers.<FollowClue>lambdaQuery() | |
258 | + .eq(FollowClue::getVin, vin) | |
259 | + .eq(FollowClue::getClueType, FollowTypeEnum.IR) | |
260 | + .eq(FollowClue::getClueState, ClueStatusEnum.ONGOING) | |
261 | + , Boolean.FALSE | |
262 | + ); | |
263 | + if (Objects.nonNull(clue)) { | |
264 | + ClueTask clueTask = clueTaskService.queryOngoingTaskByClueId(clue.getId()); | |
265 | + Long followUser = clueTask.getFollowUser(); | |
266 | + List<UserRoleDataRangeDTO> roleDataRange = userService.getUserRoleDataRange(followUser, RoleCode.FWGW); | |
267 | + if (!staffInfo.getStaffId().equals(followUser) && !CollectionUtils.isEmpty(roleDataRange)) { | |
268 | + continue; | |
269 | + } | |
270 | + } | |
271 | + list.add(vin); | |
272 | + } | |
273 | + return list; | |
274 | + } | |
275 | + | |
276 | + /** | |
226 | 277 | * 查询档案用户能否参与活动 |
227 | 278 | * |
228 | 279 | * @param vinList |
... | ... | @@ -233,7 +284,7 @@ public class PubDistributeBizService { |
233 | 284 | private List<String> determineMkt(List<String> vinList, PubStandStaffInfo staffInfo, int count) { |
234 | 285 | List<String> list = new ArrayList<>(); |
235 | 286 | for (String vin : vinList) { |
236 | - if (list.size() == count) { | |
287 | + if (list.size() >= count) { | |
237 | 288 | break; |
238 | 289 | } |
239 | 290 | Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId()); |
... | ... | @@ -243,7 +294,7 @@ public class PubDistributeBizService { |
243 | 294 | boolean hasDefeat = affiliationRecordService.count(Wrappers.<AffiliationRecord>lambdaQuery() |
244 | 295 | .eq(AffiliationRecord::getCustomerId, customer.getId()) |
245 | 296 | .eq(AffiliationRecord::getOriginUserId, staffInfo.getStaffId()) |
246 | - .ge(AffiliationRecord::getDefeatTime, DateUtil.localDate2Date(LocalDate.now().minusMonths(6L))) | |
297 | + .ge(AffiliationRecord::getDefeatTime, DateUtil.localDate2Date(LocalDate.now().minusMonths(12L))) | |
247 | 298 | ) > 1; |
248 | 299 | if (hasDefeat) { |
249 | 300 | continue; | ... | ... |