Blame view

fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java 15 KB
65610b54   张志伟   :art:
1
2
  package cn.fw.valhalla.service.bus.follow.strategy.impl;
  
725fb553   张志伟   :bug:
3
  import cn.fw.valhalla.common.constant.RoleCode;
59ae8b14   张志伟   feature(*): 售后crm...
4
  import cn.fw.valhalla.common.utils.StringUtils;
ad395b9c   张志伟   :art:
5
  import cn.fw.valhalla.domain.db.OriginalData;
23b952c1   张志伟   :art:
6
  import cn.fw.valhalla.domain.db.customer.Customer;
2a40e3f8   张志伟   feature(*): 续保跟进调整
7
  import cn.fw.valhalla.domain.db.customer.CustomerReachLog;
59ae8b14   张志伟   feature(*): 售后crm...
8
9
  import cn.fw.valhalla.domain.db.follow.ClueTask;
  import cn.fw.valhalla.domain.db.follow.FollowClue;
55003764   张志伟   feature(*): 售后crm...
10
  import cn.fw.valhalla.domain.dto.CustomerDetailDto;
ad395b9c   张志伟   :art:
11
  import cn.fw.valhalla.domain.enums.*;
2a40e3f8   张志伟   feature(*): 续保跟进调整
12
  import cn.fw.valhalla.domain.vo.customer.CustomerDetailVO;
364db3cc   张志伟   :sparkles:
13
  import cn.fw.valhalla.domain.vo.setting.SettingVO;
725fb553   张志伟   :bug:
14
  import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
f31a375d   张志伟   feature(*): bug修复
15
  import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
59ae8b14   张志伟   feature(*): 售后crm...
16
  import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO;
65610b54   张志伟   :art:
17
  import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
2a40e3f8   张志伟   feature(*): 续保跟进调整
18
  import cn.fw.valhalla.service.data.CustomerReachLogService;
03d7ac84   张志伟   feature(*): 添加续保、...
19
  import cn.fw.valhalla.service.event.ClueFromPublicEvent;
43d41dd0   张志伟   :sparkles:
20
  import cn.hutool.core.collection.ListUtil;
08704989   张志伟   :art:
21
  import com.baomidou.mybatisplus.core.toolkit.Wrappers;
65610b54   张志伟   :art:
22
  import lombok.extern.slf4j.Slf4j;
2a40e3f8   张志伟   feature(*): 续保跟进调整
23
  import org.springframework.beans.factory.annotation.Autowired;
03d7ac84   张志伟   feature(*): 添加续保、...
24
  import org.springframework.context.ApplicationEventPublisher;
65610b54   张志伟   :art:
25
  import org.springframework.stereotype.Component;
08704989   张志伟   :art:
26
  import org.springframework.transaction.annotation.Transactional;
65610b54   张志伟   :art:
27
  
9dad9666   张志伟   feature(*): 售后crm...
28
  import java.time.LocalDate;
3a2863b4   张志伟   :art:
29
  import java.time.LocalDateTime;
43d41dd0   张志伟   :sparkles:
30
  import java.util.*;
03d7ac84   张志伟   feature(*): 添加续保、...
31
  import java.util.concurrent.CompletableFuture;
65610b54   张志伟   :art:
32
  
b2f969bd   张志伟   :art:
33
  import static cn.fw.common.businessvalidator.Validator.BV;
364db3cc   张志伟   :sparkles:
34
  import static cn.fw.valhalla.service.bus.setting.strategy.SettingStrategy.COMMON_BRAND_ID;
b2f969bd   张志伟   :art:
35
  
65610b54   张志伟   :art:
36
37
38
39
40
41
42
43
  /**
   * @author : kurisu
   * @className : IRFollowStrategy
   * @description : 续保策略
   * @date: 2020-08-17 10:48
   */
  @Slf4j
  @Component
f36f3da7   张志伟   :construction:
44
  @SuppressWarnings("Duplicates")
65610b54   张志伟   :art:
45
  public class IRFollowStrategy extends AbstractFollowStrategy {
2a40e3f8   张志伟   feature(*): 续保跟进调整
46
      private final CustomerReachLogService customerReachLogService;
03d7ac84   张志伟   feature(*): 添加续保、...
47
      private final ApplicationEventPublisher eventPublisher;
2a40e3f8   张志伟   feature(*): 续保跟进调整
48
49
  
      @Autowired
03d7ac84   张志伟   feature(*): 添加续保、...
50
51
      public IRFollowStrategy(final CustomerReachLogService customerReachLogService,
                              final ApplicationEventPublisher eventPublisher) {
2a40e3f8   张志伟   feature(*): 续保跟进调整
52
          this.customerReachLogService = customerReachLogService;
03d7ac84   张志伟   feature(*): 添加续保、...
53
          this.eventPublisher = eventPublisher;
2a40e3f8   张志伟   feature(*): 续保跟进调整
54
55
      }
  
65610b54   张志伟   :art:
56
57
58
59
60
      @Override
      public FollowTypeEnum getFollowType() {
          return FollowTypeEnum.IR;
      }
  
08704989   张志伟   :art:
61
62
63
  
      @Override
      @Transactional(rollbackFor = Exception.class)
59ae8b14   张志伟   feature(*): 售后crm...
64
65
66
67
      public boolean origin2task(OriginalData originalData) {
          Customer customer = null;
          if (StringUtils.isValid(originalData.getFrameNo())) {
              customer = customerService.queryByFrameNo(originalData.getFrameNo(), originalData.getGroupId());
8587e21d   张志伟   :art:
68
          }
59ae8b14   张志伟   feature(*): 售后crm...
69
70
          if (Objects.isNull(customer)) {
              customer = customerService.queryById(originalData.getCustomerId());
8587e21d   张志伟   :art:
71
          }
59ae8b14   张志伟   feature(*): 售后crm...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
          BV.notNull(customer, () -> "档案不存在");
          FollowClue completeClue = followClueService.getOne(Wrappers.<FollowClue>lambdaQuery()
                          .eq(FollowClue::getVin, customer.getFrameNo())
                          .eq(FollowClue::getClueType, getFollowType())
                          .eq(FollowClue::getClueState, ClueStatusEnum.ONGOING)
                  , Boolean.FALSE);
          finishClue(originalData, completeClue);
  
          FollowClue wattingClue = followClueService.getOne(Wrappers.<FollowClue>lambdaQuery()
                          .eq(FollowClue::getVin, customer.getFrameNo())
                          .eq(FollowClue::getClueType, getFollowType())
                          .eq(FollowClue::getClueState, ClueStatusEnum.WAITING)
                  , Boolean.FALSE);
          if (Objects.nonNull(wattingClue)) {
              followClueService.removeById(wattingClue.getId());
          }
          FollowClue clue = createClueInfo(originalData, getFollowType(), customer);
          followClueService.save(clue);
8b00f03a   张志伟   :sparkles:
90
          createFirstNotice(clue, customer.getId(), customer.getBrandId());
59ae8b14   张志伟   feature(*): 售后crm...
91
          return true;
08704989   张志伟   :art:
92
      }
ad395b9c   张志伟   :art:
93
  
ad395b9c   张志伟   :art:
94
      @Transactional(rollbackFor = Exception.class)
ad395b9c   张志伟   :art:
95
      @Override
59ae8b14   张志伟   feature(*): 售后crm...
96
97
      public void startClue(FollowClue followClue) {
          if (!ClueStatusEnum.WAITING.equals(followClue.getClueState())) {
ad395b9c   张志伟   :art:
98
99
              return;
          }
1943d0bc   张志伟   feature(*): 公共线索池
100
          Customer customer = customerService.queryByFrameNo(followClue.getVin(), followClue.getGroupId());
bad8a098   张志伟   新增手动运维的接口
101
          if (Objects.isNull(customer)) {
1943d0bc   张志伟   feature(*): 公共线索池
102
103
104
              followClueService.removeById(followClue.getId());
              return;
          }
364db3cc   张志伟   :sparkles:
105
106
107
          Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, followClue.getGroupId(), COMMON_BRAND_ID);
          // 模式 1、续保角色 2、续保角色+服务接待/新车销售
          final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1);
db636ace   张志伟   fix(*): 优化逻辑
108
          followClue.setPlateNo(customer.getPlateNo());
4553499b   张志伟   feature(*): 开始线索时...
109
          final ClueTask clueTask = createNewTask(followClue);
2a40e3f8   张志伟   feature(*): 续保跟进调整
110
          List<PostUserDTO> userByRole;
364db3cc   张志伟   :sparkles:
111
112
113
114
115
116
          if (mode == 1) {
              userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ);
          } else {
              userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ, RoleCode.FWGW);
          }
          BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode));
59ae8b14   张志伟   feature(*): 售后crm...
117
          fillTaskUser(clueTask, userByRole);
03d7ac84   张志伟   feature(*): 添加续保、...
118
119
120
121
122
123
124
125
126
          if (mode == 2 && Objects.isNull(customer.getAdviserId())) {
              final ClueFromPublicEvent poolEvent = new ClueFromPublicEvent();
              poolEvent.setVin(customer.getFrameNo());
              poolEvent.setShopId(clueTask.getFollowShop());
              poolEvent.setUserId(clueTask.getFollowUser());
              poolEvent.setType(PubStandType.IR);
              poolEvent.setGroupId(clueTask.getGroupId());
              CompletableFuture.runAsync(() -> eventPublisher.publishEvent(poolEvent));
          }
db636ace   张志伟   fix(*): 优化逻辑
127
          clueTaskService.save(clueTask);
59ae8b14   张志伟   feature(*): 售后crm...
128
129
          followClue.setClueState(ClueStatusEnum.ONGOING);
          final FollowInitDTO followInitDTO = creteFollowInitDTO(followClue, clueTask);
59ae8b14   张志伟   feature(*): 售后crm...
130
131
          shirasawaRpcService.createFollowData(followInitDTO);
          followClueService.updateById(followClue);
23b952c1   张志伟   :art:
132
133
      }
  
23b952c1   张志伟   :art:
134
      @Override
8587e21d   张志伟   :art:
135
      @Transactional(rollbackFor = Exception.class)
9dad9666   张志伟   feature(*): 售后crm...
136
      public void closeTask(ClueTask task) {
78a11476   张志伟   取消二次分配
137
          final Long clueId = task.getClueId();
9dad9666   张志伟   feature(*): 售后crm...
138
          FollowClue clue = followClueService.getById(clueId);
78a11476   张志伟   取消二次分配
139
          BV.notNull(clue, () -> "跟进线索不存在: " + clueId);
172cb4a3   张志伟   :art:
140
          task.setState(TaskStateEnum.DEFEAT);
9dad9666   张志伟   feature(*): 售后crm...
141
          task.setCloseTime(task.getDeadline().minusSeconds(1L));
78a11476   张志伟   取消二次分配
142
          task.setReason(TaskDefeatTypeEnum.C);
9dad9666   张志伟   feature(*): 售后crm...
143
          boolean rpcSucess = rpcStopTask(task);
9de0e2d7   张志伟   feature(*): 公共池线索...
144
145
146
          if (!rpcSucess) {
              log.info("跟进系统终止任务失败");
          }
9dad9666   张志伟   feature(*): 售后crm...
147
          task.setRpcSuccess(rpcSucess);
2a40e3f8   张志伟   feature(*): 续保跟进调整
148
          if (Objects.nonNull(clue)) {
931be588   张志伟   feature(*): 售后crm...
149
150
151
              clue.setClueState(ClueStatusEnum.FAILURE);
              clue.setCloseTime(task.getCloseTime());
              followClueService.updateById(clue);
c6ea42b4   张志伟   feature(*): 新增线索结...
152
              redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
931be588   张志伟   feature(*): 售后crm...
153
154
155
              afterStopClue(clue);
          }
          clueTaskService.updateById(task);
931be588   张志伟   feature(*): 售后crm...
156
157
158
159
160
161
162
163
164
      }
  
      /**
       * [角色变动]结束任务
       *
       * @param task
       */
      @Transactional(rollbackFor = Exception.class)
      public void onRoleChangeCloseTask(ClueTask task) {
931be588   张志伟   feature(*): 售后crm...
165
166
          Long clueId = task.getClueId();
          FollowClue clue = followClueService.getById(clueId);
78a11476   张志伟   取消二次分配
167
          BV.notNull(clue, () -> "跟进线索不存在: " + clueId);
b245c23a   张志伟   feature(*): 续保跟进调整
168
169
170
          Customer customer = customerService.queryByFrameNo(clue.getVin(), clue.getGroupId());
          Long adviserId = Optional.ofNullable(customer).map(Customer::getAdviserId).orElse(null);
  
2a40e3f8   张志伟   feature(*): 续保跟进调整
171
172
173
          Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, clue.getGroupId(), COMMON_BRAND_ID);
          // 模式 1、续保角色 2、续保角色+服务接待/新车销售
          final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1);
931be588   张志伟   feature(*): 售后crm...
174
175
176
          task.setState(TaskStateEnum.DEFEAT);
          task.setCloseTime(LocalDateTime.now());
          task.setReason(TaskDefeatTypeEnum.D);
2a40e3f8   张志伟   feature(*): 续保跟进调整
177
178
179
180
181
182
183
184
185
          if (mode == 1) {
              task.setRpcSuccess(true);
              clueTaskService.updateById(task);
              List<PostUserDTO> userByRole = userService.getShopRolesUser(task.getFollowShop(), RoleCode.XBGJ);
              BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode));
              int randomIndex = new Random().nextInt(userByRole.size());
              PostUserDTO userDTO = userByRole.get(randomIndex);
              createSecondaryTask(clue, userDTO.getUserId());
          } else {
2a40e3f8   张志伟   feature(*): 续保跟进调整
186
              if (Objects.isNull(adviserId)) {
b245c23a   张志伟   feature(*): 续保跟进调整
187
188
189
190
191
192
193
194
                  List<PostUserDTO> userByRole = userService.getShopRolesUser(task.getFollowShop(), RoleCode.XBGJ, RoleCode.FWGW);
                  BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode));
                  int randomIndex = new Random().nextInt(userByRole.size());
                  PostUserDTO userDTO = userByRole.get(randomIndex);
                  adviserId = userDTO.getUserId();
              } else {
                  if (task.getFollowUser().equals(adviserId)) {
                      return;
2a40e3f8   张志伟   feature(*): 续保跟进调整
195
                  }
2a40e3f8   张志伟   feature(*): 续保跟进调整
196
              }
b245c23a   张志伟   feature(*): 续保跟进调整
197
198
199
200
201
202
203
  
              boolean rpcSucess = rpcStopTask(task);
              if (!rpcSucess) {
                  log.info("跟进系统终止任务失败");
              }
              task.setRpcSuccess(rpcSucess);
              clueTaskService.updateById(task);
2a40e3f8   张志伟   feature(*): 续保跟进调整
204
              this.createSecondaryTask(clue, adviserId);
9b497427   张志伟   :art:
205
          }
612d25d9   张志伟   :art:
206
207
      }
  
55003764   张志伟   feature(*): 售后crm...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
      @Override
      @Transactional(rollbackFor = Exception.class)
      public void forceStopTask(ClueTask task) {
          Long clueId = task.getClueId();
          FollowClue clue = followClueService.getById(clueId);
          task.setState(TaskStateEnum.DEFEAT);
          task.setCloseTime(LocalDateTime.now());
          task.setReason(TaskDefeatTypeEnum.A);
          boolean rpcSucess = rpcStopTask(task);
          task.setRpcSuccess(rpcSucess);
          clueTaskService.updateById(task);
          if (Objects.nonNull(clue)) {
              clue.setClueState(ClueStatusEnum.FAILURE);
              clue.setCloseTime(LocalDateTime.now());
              followClueService.updateById(clue);
              afterStopClue(clue);
c6ea42b4   张志伟   feature(*): 新增线索结...
224
              redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
55003764   张志伟   feature(*): 售后crm...
225
          }
2a40e3f8   张志伟   feature(*): 续保跟进调整
226
227
228
          Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, clue.getGroupId(), COMMON_BRAND_ID);
          // 模式 1、续保角色 2、续保角色+服务接待/新车销售
          final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1);
b245c23a   张志伟   feature(*): 续保跟进调整
229
230
231
232
233
234
          if (mode != 1) {
              CustomerDetailVO detailByVin = customerBizService.getDetailByVin(clue.getVin(), clue.getGroupId());
              Long aLong = Optional.ofNullable(detailByVin).map(CustomerDetailVO::getAdviserId).orElse(null);
              if (task.getFollowUser().equals(aLong)) {
                  customerBizService.abandon(detailByVin.getId(), "主动放弃");
              }
2a40e3f8   张志伟   feature(*): 续保跟进调整
235
          }
55003764   张志伟   feature(*): 售后crm...
236
237
      }
  
f31a375d   张志伟   feature(*): bug修复
238
239
240
241
242
243
244
245
246
      @Override
      protected ClueTask createNewTask(FollowClue followClue) {
          final FollowTypeEnum followTypeEnum = followClue.getClueType();
          final ClueTask clueTask = new ClueTask();
          clueTask.setClueId(followClue.getId());
          clueTask.setType(followTypeEnum);
          clueTask.setBeginTime(followClue.getStartTime());
          clueTask.setRedistribution(Boolean.FALSE);
          clueTask.setDeadline(followClue.getEndTime());
f31a375d   张志伟   feature(*): bug修复
247
248
249
250
          clueTask.setState(TaskStateEnum.ONGOING);
          clueTask.setGroupId(followClue.getGroupId());
          Long userId = null;
          Long shopId = null;
2a40e3f8   张志伟   feature(*): 续保跟进调整
251
252
253
254
255
256
257
258
          Customer customer = customerService.queryByFrameNo(followClue.getVin(), followClue.getGroupId());
          if (Objects.nonNull(customer)) {
              userId = customer.getAdviserId();
              shopId = customer.getShopId();
              ShopDTO shop = oopService.shop(shopId);
              if (Objects.isNull(shop)) {
                  userId = null;
                  shopId = null;
f31a375d   张志伟   feature(*): bug修复
259
260
261
              }
          }
          if (Objects.isNull(shopId)) {
2a40e3f8   张志伟   feature(*): 续保跟进调整
262
263
264
265
266
267
268
269
270
271
272
273
              CustomerReachLog lastReach = customerReachLogService.getOne(Wrappers.<CustomerReachLog>lambdaQuery()
                              .eq(CustomerReachLog::getFrameNo, followClue.getVin())
                              .eq(CustomerReachLog::getGroupId, followClue.getGroupId())
                              .orderByDesc(CustomerReachLog::getArrivalTime)
                      , Boolean.FALSE);
              if (Objects.nonNull(lastReach)) {
                  shopId = lastReach.getShopId();
              }
  
              if (Objects.isNull(shopId)) {
                  shopId = followClue.getSuggestShopId();
              }
f31a375d   张志伟   feature(*): bug修复
274
          }
43d41dd0   张志伟   :sparkles:
275
276
277
278
279
          if (shopId == 146L) {
              ArrayList<Long> arrayList = ListUtil.toList(67L, 65L, 66L);
              int randomIndex = new Random().nextInt(arrayList.size());
              shopId = arrayList.get(randomIndex);
          }
f31a375d   张志伟   feature(*): bug修复
280
281
          clueTask.setFollowShop(shopId);
          clueTask.setFollowUser(userId);
89bd2e6c   张志伟   feature(*): 新增区域站...
282
          clueTask.setVersion(2);
f31a375d   张志伟   feature(*): bug修复
283
284
285
          return clueTask;
      }
  
55003764   张志伟   feature(*): 售后crm...
286
287
288
      private void afterStopClue(FollowClue clue) {
          String vin = clue.getVin();
          Long groupId = clue.getGroupId();
eff44caf   张志伟   fix: 优化部分时间计算
289
          LocalDate originTime = clue.getOriginTime().plusYears(1L).toLocalDate();
55003764   张志伟   feature(*): 售后crm...
290
291
          CustomerDetailDto customer = customerBizService.queryByFrameNo(vin, groupId);
          if (Objects.isNull(customer)) {
68cd8666   张志伟   :bug:
292
293
              return;
          }
55003764   张志伟   feature(*): 售后crm...
294
295
296
          final FollowClue newClue = new FollowClue();
          newClue.setVin(vin);
          newClue.setPlateNo(customer.getPlateNo());
eff44caf   张志伟   fix: 优化部分时间计算
297
          newClue.setOriginTime(clue.getOriginTime().plusYears(1L));
55003764   张志伟   feature(*): 售后crm...
298
299
300
301
302
303
          newClue.setClueState(ClueStatusEnum.WAITING);
          newClue.setClueType(clue.getClueType());
          newClue.setGroupId(groupId);
          newClue.setSuggestShopId(Objects.isNull(customer.getShopId()) ? clue.getSuggestShopId() : customer.getShopId());
          newClue.setSuggestMobile(StringUtils.isEmpty(customer.getMobile()) ? clue.getSuggestMobile() : customer.getMobile());
  
8b00f03a   张志伟   :sparkles:
304
          settingBizService.querySettingByType(clue.getClueType(), SettingTypeEnum.FIRST_TRIGGER_TIME, groupId, customer.getBrandId())
55003764   张志伟   feature(*): 售后crm...
305
306
307
                  .ifPresent(r -> {
                      int detailValue = Optional.ofNullable(r.getDetailValue()).orElse(0);
                      SettingUnitEnum unitEnum = Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit()), "时间单位缺失");
eff44caf   张志伟   fix: 优化部分时间计算
308
                      LocalDateTime localDateTime = calTime(originTime.atStartOfDay(), unitEnum, detailValue * -1);
55003764   张志伟   feature(*): 售后crm...
309
310
311
                      newClue.setStartTime(localDateTime);
                  });
  
8b00f03a   张志伟   :sparkles:
312
          settingBizService.querySettingByType(clue.getClueType(), SettingTypeEnum.FAIL_TIME, groupId, customer.getBrandId())
55003764   张志伟   feature(*): 售后crm...
313
314
                  .ifPresent(r -> {
                      int detailValue = Optional.ofNullable(r.getDetailValue()).orElse(0);
55003764   张志伟   feature(*): 售后crm...
315
                      SettingUnitEnum unitEnum = Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit()), "时间单位缺失");
eff44caf   张志伟   fix: 优化部分时间计算
316
                      LocalDateTime localDateTime = calTime(originTime.atStartOfDay(), unitEnum, detailValue);
55003764   张志伟   feature(*): 售后crm...
317
318
319
                      newClue.setEndTime(localDateTime);
                  });
          followClueService.save(newClue);
8b00f03a   张志伟   :sparkles:
320
          createFirstNotice(newClue, customer.getId(), customer.getBrandId());
68cd8666   张志伟   :bug:
321
      }
65610b54   张志伟   :art:
322
  }