Commit 364db3cc508d4797829ca51afb36214f47b60dbd
1 parent
073324d4
feature(*): 公共池跟进逻辑
- 公共池跟进逻辑
Showing
19 changed files
with
509 additions
and
85 deletions
doc/v2.0/update.sql
... | ... | @@ -2,6 +2,47 @@ drop table if exists customer_clue_pool; |
2 | 2 | |
3 | 3 | drop table if exists follow_task; |
4 | 4 | |
5 | +# 续保跟进模式 | |
6 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
7 | + create_time, update_time) | |
8 | +VALUES (4, -1, 99, 1, 11, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
9 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
10 | + create_time, update_time) | |
11 | +VALUES (8, -1, 99, 1, 11, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
12 | + | |
13 | +# 统一设置待办时长[事故车除外] | |
14 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
15 | + create_time, update_time) | |
16 | +VALUES (9, -1, 2, 36, 3, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
17 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
18 | + create_time, update_time) | |
19 | +VALUES (10, -1, 2, 36, 3, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
20 | + | |
21 | +# 转换率最低要求 | |
22 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
23 | + create_time, update_time) | |
24 | +VALUES (9, -1, 13, 2000, 9, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
25 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
26 | + create_time, update_time) | |
27 | +VALUES (10, -1, 13, 2000, 9, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
28 | + | |
29 | +# 公共池线索初始值 | |
30 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
31 | + create_time, update_time) | |
32 | +VALUES (9, -1, 14, 50, 10, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
33 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
34 | + create_time, update_time) | |
35 | +VALUES (10, -1, 14, 50, 10, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
36 | + | |
37 | + | |
38 | +# 公共池线索增量 | |
39 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
40 | + create_time, update_time) | |
41 | +VALUES (9, -1, 15, 10, 10, 1, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
42 | +INSERT INTO fw_valhalla.follow_setting_detail (setting_id, brand_id, type, detail_value, unit, group_id, yn, | |
43 | + create_time, update_time) | |
44 | +VALUES (10, -1, 15, 10, 10, 2, 1, '2023-03-17 16:00:31', '2023-03-17 16:00:32'); | |
45 | + | |
5 | 46 | |
6 | 47 | CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info |
7 | 48 | ( |
... | ... | @@ -16,13 +57,14 @@ CREATE TABLE IF NOT EXISTS fw_valhalla.pub_stand_staff_info |
16 | 57 | id_code varchar(255) null comment '识别码 站岗类型为公共池类型时为空', |
17 | 58 | stand_rang int(3) not null comment '站岗范围 1:本门店范围 2:区域范围', |
18 | 59 | reason_of_no_lining varchar(255) null comment '不在队列原因', |
60 | + area_code varchar(16) not null comment '门店区域码', | |
19 | 61 | shop_id bigint not null comment '门店id', |
20 | 62 | shop_name varchar(255) null comment '门店名称', |
21 | 63 | group_id bigint not null comment '集团id', |
22 | 64 | create_time datetime not null, |
23 | 65 | update_time datetime null, |
24 | 66 | constraint pub_stand_staff_info_staff_id_group_id_uindex |
25 | - unique (staff_id,group_id) comment '集团用户' | |
67 | + unique (staff_id, group_id) comment '集团用户' | |
26 | 68 | ) |
27 | 69 | comment '公共池站岗配置'; |
28 | 70 | |
... | ... | @@ -38,4 +80,54 @@ where t1.vin is null |
38 | 80 | and t2.id = t1.customer_id; |
39 | 81 | |
40 | 82 | alter table public_clue_pool |
41 | - modify vin varchar(128) not null comment '车架号' | |
42 | 83 | \ No newline at end of file |
84 | + modify vin varchar(128) not null comment '车架号'; | |
85 | + | |
86 | + | |
87 | +# 公共池数据表调整 | |
88 | +update public_pool t1, customer t2 | |
89 | +set t1.frame_no = ifnull(t2.frame_no, '') | |
90 | +where t1.frame_no is null | |
91 | + and t2.yn = 1 | |
92 | + and t2.id = t1.customer_id; | |
93 | + | |
94 | +update public_pool t1 | |
95 | +set t1.frame_no = concat_ws('-', t1.plate_no, t1.customer_id) | |
96 | +where t1.frame_no is null; | |
97 | + | |
98 | +alter table public_pool | |
99 | + modify frame_no varchar(64) not null comment '车架号'; | |
100 | + | |
101 | +alter table public_pool | |
102 | + modify plate_no varchar(32) null comment '车牌号'; | |
103 | + | |
104 | +alter table public_pool | |
105 | + modify shop_id bigint not null comment '最后所在服务站'; | |
106 | + | |
107 | +alter table public_pool | |
108 | + modify shop_name varchar(128) null comment '最后所在服务站名'; | |
109 | + | |
110 | +create unique index public_pool_frame_no_group_id_uindex | |
111 | + on public_pool (frame_no, group_id); | |
112 | + | |
113 | + | |
114 | +create table if not exists fw_valhalla.pub_clue_pool | |
115 | +( | |
116 | + id bigint auto_increment | |
117 | + primary key, | |
118 | + vin varchar(128) not null comment '车架号', | |
119 | + start_time datetime not null comment '开始时间', | |
120 | + deadline datetime not null comment '转换截止时间', | |
121 | + close_time datetime null comment '关闭时间', | |
122 | + state int(3) not null comment '状态: 1、转换中 2、已转换 3、转换失败', | |
123 | + adviser_id bigint not null comment '顾问id', | |
124 | + adviser_name varchar(32) null comment '顾问名称', | |
125 | + shop_id bigint not null comment '门店id', | |
126 | + shop_name varchar(128) null comment '门店名称', | |
127 | + group_id bigint not null comment '集团id', | |
128 | + create_time datetime null, | |
129 | + update_time datetime null, | |
130 | + constraint pub_clue_pool_customer_id_adviser_id_uindex | |
131 | + unique (vin, adviser_id) | |
132 | +) | |
133 | + comment '公共池线索跟进池'; | |
134 | + | ... | ... |
fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/PublicPoolMapper.java
... | ... | @@ -34,4 +34,11 @@ public interface PublicPoolMapper extends BaseMapper<PublicPool> { |
34 | 34 | * @return |
35 | 35 | */ |
36 | 36 | Long publicListCount(@Param("condition") PublicPoolQueryVO queryVO); |
37 | + | |
38 | + /** | |
39 | + * 根据门店列表查询vin | |
40 | + * @param shopIds | |
41 | + * @return | |
42 | + */ | |
43 | + List<String> queryIdListByShops(@Param("shopIds") List<Long> shopIds); | |
37 | 44 | } | ... | ... |
fw-valhalla-dao/src/main/resources/mapper/PublicPoolMapper.xml
... | ... | @@ -6,26 +6,26 @@ |
6 | 6 | resultType="cn.fw.valhalla.domain.dto.PublicPoolDTO" |
7 | 7 | parameterType="cn.fw.valhalla.domain.query.PublicPoolQueryVO" |
8 | 8 | > |
9 | - SELECT t1.id id, | |
10 | - t1.customer_id customer_id, | |
9 | + SELECT t1.id id, | |
10 | + t1.customer_id customer_id, | |
11 | 11 | t1.customer_name customer_name, |
12 | - t1.frame_no frame_no, | |
13 | - t1.plate_no plate_no, | |
14 | - t1.brand_id brand_id, | |
15 | - t1.brand_name brand_name, | |
16 | - t1.series_id series_id, | |
17 | - t1.series_name series_name, | |
18 | - t1.spec_id spec_id, | |
19 | - t1.spec_name spec_name, | |
20 | - t1.address address, | |
21 | - t1.company company, | |
22 | - t1.type type, | |
23 | - t1.shop_id shop_id, | |
24 | - t1.shop_name shop_name, | |
25 | - t1.times times, | |
26 | - t1.reason reason, | |
27 | - t1.group_id group_id, | |
28 | - t2.tags tags | |
12 | + t1.frame_no frame_no, | |
13 | + t1.plate_no plate_no, | |
14 | + t1.brand_id brand_id, | |
15 | + t1.brand_name brand_name, | |
16 | + t1.series_id series_id, | |
17 | + t1.series_name series_name, | |
18 | + t1.spec_id spec_id, | |
19 | + t1.spec_name spec_name, | |
20 | + t1.address address, | |
21 | + t1.company company, | |
22 | + t1.type type, | |
23 | + t1.shop_id shop_id, | |
24 | + t1.shop_name shop_name, | |
25 | + t1.times times, | |
26 | + t1.reason reason, | |
27 | + t1.group_id group_id, | |
28 | + t2.tags tags | |
29 | 29 | FROM public_pool t1 |
30 | 30 | left join customer t2 on t1.customer_id = t2.id |
31 | 31 | <where> |
... | ... | @@ -52,7 +52,7 @@ |
52 | 52 | and t1.type = #{condition.type} |
53 | 53 | </if> |
54 | 54 | <if test="condition.shopIds !=null"> |
55 | - and t1.shop_id in | |
55 | + and t1.shop_id in | |
56 | 56 | <foreach collection="condition.shopIds" item="id" index="index" open="(" close=")" separator=","> |
57 | 57 | #{id} |
58 | 58 | </foreach> |
... | ... | @@ -61,7 +61,7 @@ |
61 | 61 | and t1.shop_name like concat('%', #{condition.shopName}, '%') |
62 | 62 | </if> |
63 | 63 | <if test="condition.ignoreCustIds !=null"> |
64 | - and t1.customer_id not in | |
64 | + and t1.customer_id not in | |
65 | 65 | <foreach collection="condition.ignoreCustIds" item="id" index="index" open="(" close=")" separator=","> |
66 | 66 | #{id} |
67 | 67 | </foreach> |
... | ... | @@ -121,7 +121,7 @@ |
121 | 121 | and t1.type = #{condition.type} |
122 | 122 | </if> |
123 | 123 | <if test="condition.shopIds !=null"> |
124 | - and t1.shop_id in | |
124 | + and t1.shop_id in | |
125 | 125 | <foreach collection="condition.shopIds" item="id" index="index" open="(" close=")" separator=","> |
126 | 126 | #{id} |
127 | 127 | </foreach> |
... | ... | @@ -130,7 +130,7 @@ |
130 | 130 | and t1.shop_name like concat('%', #{condition.shopName}, '%') |
131 | 131 | </if> |
132 | 132 | <if test="condition.ignoreCustIds !=null"> |
133 | - and t1.customer_id not in | |
133 | + and t1.customer_id not in | |
134 | 134 | <foreach collection="condition.ignoreCustIds" item="id" index="index" open="(" close=")" separator=","> |
135 | 135 | #{id} |
136 | 136 | </foreach> |
... | ... | @@ -149,4 +149,20 @@ |
149 | 149 | </if> |
150 | 150 | </where> |
151 | 151 | </select> |
152 | + | |
153 | + <select | |
154 | + id="queryIdListByShops" | |
155 | + resultType="java.lang.String" | |
156 | + > | |
157 | + SELECT frame_no | |
158 | + FROM public_pool | |
159 | + <where> | |
160 | + <if test="shopIds !=null"> | |
161 | + shop_id in | |
162 | + <foreach collection="shopIds" item="id" index="index" open="(" close=")" separator=","> | |
163 | + #{id} | |
164 | + </foreach> | |
165 | + </if> | |
166 | + </where> | |
167 | + </select> | |
152 | 168 | </mapper> | ... | ... |
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/pub/PubStandStaffInfo.java
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/FollowTypeEnum.java
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java
... | ... | @@ -61,6 +61,13 @@ public enum SettingTypeEnum implements IEnum<Integer> { |
61 | 61 | * 公共客户线索池保留最大时长 |
62 | 62 | */ |
63 | 63 | PUBLIC_VALID_DAY(12, "公共客户线索池保留时间", 11), |
64 | + /** | |
65 | + * 公共客户线索最低转换率 | |
66 | + */ | |
67 | + MINIMUM_CONVERSION_RATE(13, "公共客户线索最低转换率", 12), | |
68 | + MINIMUM_CLUE_COUNT(14, "公共客户线索分配初始数", 13), | |
69 | + INCREASE_COUNT(15, "公共客户线增量数", 14), | |
70 | + MODE(99, "续保跟进模式", 1000), | |
64 | 71 | ; |
65 | 72 | |
66 | 73 | /** | ... | ... |
fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserService.java
... | ... | @@ -17,11 +17,9 @@ import org.springframework.stereotype.Service; |
17 | 17 | import org.springframework.util.Assert; |
18 | 18 | import org.springframework.util.CollectionUtils; |
19 | 19 | |
20 | -import java.util.ArrayList; | |
21 | -import java.util.Collections; | |
22 | -import java.util.List; | |
23 | -import java.util.Objects; | |
20 | +import java.util.*; | |
24 | 21 | import java.util.concurrent.TimeUnit; |
22 | +import java.util.stream.Collectors; | |
25 | 23 | |
26 | 24 | /** |
27 | 25 | * 用户服务 |
... | ... | @@ -121,6 +119,43 @@ public class UserService extends AbsBaseRpcService { |
121 | 119 | return Collections.emptyList(); |
122 | 120 | } |
123 | 121 | |
122 | + /** | |
123 | + * 门店内拥有多个角色的人员 | |
124 | + * @param shopId | |
125 | + * @param roleCode | |
126 | + * @return | |
127 | + */ | |
128 | + public List<PostUserDTO> getShopRolesUser(Long shopId, String... roleCode) { | |
129 | + if (roleCode.length == 0 || Objects.isNull(shopId)) { | |
130 | + return Collections.emptyList(); | |
131 | + } | |
132 | + String key = generateKey(shopId, String.join(",", roleCode)); | |
133 | + List<PostUserDTO> dtos = getListFromCache(key, PostUserDTO.class); | |
134 | + if (!CollectionUtils.isEmpty(dtos)) { | |
135 | + return dtos; | |
136 | + } | |
137 | + try { | |
138 | + List<String> roleCodeList = Arrays.stream(roleCode).collect(Collectors.toList()); | |
139 | + Message<List<UserRoleInfo>> msg = userRoleApi.queryRoleUsers(roleCodeList, shopId); | |
140 | + List<UserRoleInfo> userRoleInfos = msg.getData(); | |
141 | + if (!msg.isSuccess() || CollectionUtils.isEmpty(userRoleInfos)) { | |
142 | + return Collections.emptyList(); | |
143 | + } | |
144 | + List<PostUserDTO> list = new ArrayList<>(userRoleInfos.size()); | |
145 | + for (UserRoleInfo datum : userRoleInfos) { | |
146 | + PostUserDTO dto = new PostUserDTO(); | |
147 | + BeanUtils.copyProperties(datum, dto); | |
148 | + list.add(dto); | |
149 | + setListToCache(key, JSONObject.toJSONString(dto)); | |
150 | + } | |
151 | + getQueue(key).expire(10, TimeUnit.MINUTES); | |
152 | + return list; | |
153 | + } catch (Exception e) { | |
154 | + e.printStackTrace(); | |
155 | + } | |
156 | + return Collections.emptyList(); | |
157 | + } | |
158 | + | |
124 | 159 | private String generateKey(final Long shopId, final String roleCOde) { |
125 | 160 | Assert.notNull(shopId, "id cannot be null"); |
126 | 161 | Assert.hasLength(roleCOde, "roleCOde cannot be null"); | ... | ... |
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/oop/OopService.java
... | ... | @@ -185,6 +185,31 @@ public class OopService extends AbsBaseRpcService { |
185 | 185 | } |
186 | 186 | |
187 | 187 | /** |
188 | + * 根据区域code查询该地区门店列表 | |
189 | + * @param areaCode | |
190 | + * @return | |
191 | + */ | |
192 | + public List<ShopDTO> areaShops(final String areaCode) { | |
193 | + if (StringUtils.isEmpty(areaCode)) { | |
194 | + return Collections.emptyList(); | |
195 | + } | |
196 | +// try { | |
197 | +// Message<List<ShopInfoVo>> msg = shopApiService.getShopInfoList(new ArrayList<>()); | |
198 | +// if (!msg.isSuccess() || CollectionUtils.isEmpty(msg.getData())) { | |
199 | +// return Collections.emptyList(); | |
200 | +// } | |
201 | +// return msg.getData().stream().map(item -> { | |
202 | +// final ShopDTO shop = new ShopDTO(); | |
203 | +// BeanUtils.copyProperties(item, shop); | |
204 | +// return shop; | |
205 | +// }).collect(Collectors.toList()); | |
206 | +// } catch (Exception e) { | |
207 | +// e.printStackTrace(); | |
208 | +// } | |
209 | + return Collections.emptyList(); | |
210 | + } | |
211 | + | |
212 | + /** | |
188 | 213 | * 根据ID获取商家信息 |
189 | 214 | * |
190 | 215 | * @param dealerId 商家ID | ... | ... |
fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/shirasawa/ShirasawaRpcService.java
... | ... | @@ -115,10 +115,10 @@ public class ShirasawaRpcService { |
115 | 115 | * @param userId |
116 | 116 | * @return |
117 | 117 | */ |
118 | - public boolean hasOngoingFollow(Long userId) { | |
118 | + public Boolean hasOngoingFollow(Long userId) { | |
119 | 119 | try { |
120 | 120 | if (Objects.isNull(userId)) { |
121 | - return true; | |
121 | + return null; | |
122 | 122 | } |
123 | 123 | Message<Long> message = followApiService.queryRecordRemaining(userId, BusinessTypeEnum.AS.getValue()); |
124 | 124 | log.info("followApiService.queryRecordRemaining: msg.code={}, msg.result={}", message.getCode(), message.getResult()); |
... | ... | @@ -129,6 +129,6 @@ public class ShirasawaRpcService { |
129 | 129 | } catch (Exception e) { |
130 | 130 | log.error("查询未完成的待办失败。userId: [{}]", userId, e); |
131 | 131 | } |
132 | - return true; | |
132 | + return null; | |
133 | 133 | } |
134 | 134 | } | ... | ... |
fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/PubStandTask.java
... | ... | @@ -71,7 +71,7 @@ public class PubStandTask { |
71 | 71 | while ((id = ops.leftPop()) != null) { |
72 | 72 | if (StringUtils.isNumber(id)) { |
73 | 73 | try { |
74 | - Boolean distributed = pubDistributeBizService.distribute(Long.valueOf(id)); | |
74 | + Boolean distributed = pubDistributeBizService.distribute(Long.parseLong(id)); | |
75 | 75 | if (!Boolean.TRUE.equals(distributed)) { |
76 | 76 | failList.add(id); |
77 | 77 | } | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java
... | ... | @@ -349,13 +349,13 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { |
349 | 349 | @Override |
350 | 350 | @Transactional(rollbackFor = Exception.class) |
351 | 351 | public void createNextFollowTodo(FollowClue clue) { |
352 | - FollowTypeEnum clueType = clue.getClueType(); | |
353 | 352 | Long brandId = COMMON_BRAND_ID; |
354 | 353 | Customer customer = customerService.queryByFrameNo(clue.getVin(), clue.getGroupId()); |
355 | 354 | if (Objects.nonNull(customer)) { |
356 | 355 | brandId = customer.getBrandId(); |
357 | 356 | } |
358 | - SettingVO efsetting = settingBizService.querySettingByType(clueType, SettingTypeEnum.EFFECTIVE_TIME, clue.getGroupId(), brandId).orElse(null); | |
357 | + // 除事故车以外,其他待办跟进时长统一配置 | |
358 | + SettingVO efsetting = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.EFFECTIVE_TIME, clue.getGroupId(), brandId).orElse(null); | |
359 | 359 | BV.notNull(efsetting, () -> MessageFormatUtil.MessageFormatTransfer("关键设置数据异常,请检查数据: settingType: {0} groupId: {1}", SettingTypeEnum.EFFECTIVE_TIME.getName(), clue.getGroupId())); |
360 | 360 | |
361 | 361 | ClueTask clueTask = clueTaskService.queryOngoingTaskByClueId(clue.getId()); |
... | ... | @@ -629,7 +629,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { |
629 | 629 | if (Objects.nonNull(shop)) { |
630 | 630 | followInitDTO.setShopName(shop.getShopName()); |
631 | 631 | } |
632 | - settingBizService.querySettingByType(clueTask.getType(), SettingTypeEnum.EFFECTIVE_TIME, clueTask.getGroupId(), brandId) | |
632 | + // 除事故车以外,其他待办跟进时长统一配置 | |
633 | + settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.EFFECTIVE_TIME, clueTask.getGroupId(), brandId) | |
633 | 634 | .ifPresent(r -> { |
634 | 635 | LocalDateTime dateTime = calTime(clueTask.getBeginTime(), Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit())), r.getDetailValue()); |
635 | 636 | followInitDTO.setFirstRecordDeadline(DateUtil.localDateTime2Date(dateTime.minusSeconds(1L))); | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java
... | ... | @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.ClueTask; |
8 | 8 | import cn.fw.valhalla.domain.db.follow.FollowClue; |
9 | 9 | import cn.fw.valhalla.domain.dto.CustomerDetailDto; |
10 | 10 | import cn.fw.valhalla.domain.enums.*; |
11 | +import cn.fw.valhalla.domain.vo.setting.SettingVO; | |
11 | 12 | import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; |
12 | 13 | import cn.fw.valhalla.rpc.oop.dto.ShopDTO; |
13 | 14 | import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO; |
... | ... | @@ -26,6 +27,7 @@ import java.util.*; |
26 | 27 | import java.util.stream.Collectors; |
27 | 28 | |
28 | 29 | import static cn.fw.common.businessvalidator.Validator.BV; |
30 | +import static cn.fw.valhalla.service.bus.setting.strategy.SettingStrategy.COMMON_BRAND_ID; | |
29 | 31 | |
30 | 32 | /** |
31 | 33 | * @author : kurisu |
... | ... | @@ -86,10 +88,18 @@ public class IRFollowStrategy extends AbstractFollowStrategy { |
86 | 88 | followClueService.removeById(followClue.getId()); |
87 | 89 | return; |
88 | 90 | } |
91 | + Optional<SettingVO> settingVO = settingBizService.querySettingByType(getFollowType(), SettingTypeEnum.MODE, followClue.getGroupId(), COMMON_BRAND_ID); | |
92 | + // 模式 1、续保角色 2、续保角色+服务接待/新车销售 | |
93 | + final int mode = settingVO.map(SettingVO::getDetailValue).orElse(1); | |
89 | 94 | followClue.setPlateNo(customer.getPlateNo()); |
90 | 95 | final ClueTask clueTask = createNewTask(followClue); |
91 | - List<PostUserDTO> userByRole = userService.getUserByRole(clueTask.getFollowShop(), RoleCode.XBGJ); | |
92 | - BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员"); | |
96 | + List<PostUserDTO> userByRole = new ArrayList<>(); | |
97 | + if (mode == 1) { | |
98 | + userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ); | |
99 | + } else { | |
100 | + userByRole = userService.getShopRolesUser(clueTask.getFollowShop(), RoleCode.XBGJ, RoleCode.FWGW); | |
101 | + } | |
102 | + BV.isNotEmpty(userByRole, () -> String.format("该门店[mode: %s]没有【跟进】人员", mode)); | |
93 | 103 | fillTaskUser(clueTask, userByRole); |
94 | 104 | clueTaskService.save(clueTask); |
95 | 105 | followClue.setClueState(ClueStatusEnum.ONGOING); |
... | ... | @@ -238,7 +248,7 @@ public class IRFollowStrategy extends AbstractFollowStrategy { |
238 | 248 | redistributionTask.setCloseTime(null); |
239 | 249 | redistributionTask.setFinishUserName(null); |
240 | 250 | redistributionTask.setReason(null); |
241 | - redistributionTask.setRpcSuccess(Boolean.FALSE); | |
251 | + redistributionTask.setRpcSuccess(Boolean.FALSE);// todo 销售顾问跟进的场景 | |
242 | 252 | List<PostUserDTO> userByRole = userService.getUserByRole(oldTask.getFollowShop(), RoleCode.XBGJ); |
243 | 253 | BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员"); |
244 | 254 | List<PostUserDTO> newUserRole = userByRole.stream().filter(userDTO -> !userDTO.getUserId().equals(oldTask.getFollowUser())).collect(Collectors.toList()); | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubDistributeBizService.java
0 → 100644
1 | +package cn.fw.valhalla.service.bus.pub; | |
2 | + | |
3 | +import cn.fw.valhalla.domain.db.customer.Customer; | |
4 | +import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo; | |
5 | +import cn.fw.valhalla.domain.enums.PubStandRang; | |
6 | +import cn.fw.valhalla.domain.enums.PubStandType; | |
7 | +import cn.fw.valhalla.rpc.ehr.EhrRpcService; | |
8 | +import cn.fw.valhalla.rpc.oop.OopService; | |
9 | +import cn.fw.valhalla.rpc.oop.dto.ShopDTO; | |
10 | +import cn.fw.valhalla.rpc.shirasawa.ShirasawaRpcService; | |
11 | +import cn.fw.valhalla.service.data.CustomerService; | |
12 | +import cn.fw.valhalla.service.data.PubStandStaffInfoService; | |
13 | +import cn.fw.valhalla.service.data.PublicPoolService; | |
14 | +import cn.hutool.core.collection.ListUtil; | |
15 | +import lombok.RequiredArgsConstructor; | |
16 | +import lombok.extern.slf4j.Slf4j; | |
17 | +import org.springframework.stereotype.Service; | |
18 | +import org.springframework.transaction.annotation.Transactional; | |
19 | +import org.springframework.util.CollectionUtils; | |
20 | +import org.springframework.util.StringUtils; | |
21 | + | |
22 | +import java.util.List; | |
23 | +import java.util.Objects; | |
24 | +import java.util.Optional; | |
25 | +import java.util.stream.Collectors; | |
26 | + | |
27 | +/** | |
28 | + * 公共池站岗分配 | |
29 | + * | |
30 | + * @author : kurisu | |
31 | + * @version : 1.0 | |
32 | + * @className : PubDBizService | |
33 | + * @description : 公共池站岗分配 | |
34 | + * @date : 2023-03-11 15:55 | |
35 | + */ | |
36 | +@RequiredArgsConstructor | |
37 | +@Service | |
38 | +@Slf4j | |
39 | +public class PubDistributeBizService { | |
40 | + private final EhrRpcService ehrRpcService; | |
41 | + private final OopService oopService; | |
42 | + private final ShirasawaRpcService shirasawaRpcService; | |
43 | + private final PublicPoolService publicPoolService; | |
44 | + private final CustomerService customerService; | |
45 | + private final PubStandStaffInfoService pubStandStaffInfoService; | |
46 | + | |
47 | + /** | |
48 | + * 分配 | |
49 | + * | |
50 | + * @param id | |
51 | + * @return | |
52 | + */ | |
53 | + @Transactional(rollbackFor = Exception.class) | |
54 | + public Boolean distribute(Long id) { | |
55 | + PubStandStaffInfo staffInfo = pubStandStaffInfoService.getById(id); | |
56 | + if (Objects.isNull(staffInfo)) { | |
57 | + return true; | |
58 | + } | |
59 | + if (staffInfo.getNoInvolved() || !staffInfo.getLining()) { | |
60 | + return true; | |
61 | + } | |
62 | + Boolean checked = checkStaff(staffInfo); | |
63 | + if (null == checked) { | |
64 | + return false; | |
65 | + } else if (!checked) { | |
66 | + return true; | |
67 | + } | |
68 | + List<Long> list = getShopIds(staffInfo); | |
69 | + if (CollectionUtils.isEmpty(list)) { | |
70 | + return false; | |
71 | + } | |
72 | + List<String> vinList = publicPoolService.queryIdListByShops(list); | |
73 | + if (CollectionUtils.isEmpty(vinList)) { | |
74 | + return false; | |
75 | + } | |
76 | + String vin = getBeDistributeVin(staffInfo, vinList); | |
77 | + if (StringUtils.isEmpty(vin)) { | |
78 | + return false; | |
79 | + } | |
80 | + return createClue(vin, staffInfo); | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * 检查人员状态 | |
85 | + * | |
86 | + * @return | |
87 | + */ | |
88 | + public Boolean checkStaff(PubStandStaffInfo staffInfo) { | |
89 | + Boolean aBoolean = shirasawaRpcService.hasOngoingFollow(staffInfo.getStaffId()); | |
90 | + if (null == aBoolean) { | |
91 | + return null; | |
92 | + } | |
93 | + if (Boolean.TRUE.equals(aBoolean)) { | |
94 | + staffInfo.setLining(false); | |
95 | + staffInfo.setReasonOfNoLining("有未完成的跟进待办"); | |
96 | + pubStandStaffInfoService.updateById(staffInfo); | |
97 | + return false; | |
98 | + } | |
99 | + return true; | |
100 | + } | |
101 | + | |
102 | + /** | |
103 | + * 查询门店 | |
104 | + * | |
105 | + * @param staffInfo | |
106 | + * @return | |
107 | + */ | |
108 | + private List<Long> getShopIds(final PubStandStaffInfo staffInfo) { | |
109 | + List<Long> shopIdList = ListUtil.toList(); | |
110 | + PubStandRang standRang = Optional.ofNullable(staffInfo.getStandRang()).orElse(PubStandRang.SHOP); | |
111 | + switch (standRang) { | |
112 | + case SHOP: | |
113 | + shopIdList = ListUtil.toList(staffInfo.getShopId()); | |
114 | + break; | |
115 | + case AREA: | |
116 | + shopIdList = oopService.areaShops(staffInfo.getAreaCode()) | |
117 | + .stream().map(ShopDTO::getId) | |
118 | + .filter(r -> !r.equals(staffInfo.getShopId())) | |
119 | + .collect(Collectors.toList()); | |
120 | + break; | |
121 | + default: | |
122 | + break; | |
123 | + } | |
124 | + return shopIdList; | |
125 | + } | |
126 | + | |
127 | + /** | |
128 | + * 分配给人员 档案 | |
129 | + * | |
130 | + * @param staffInfo | |
131 | + * @param vinList | |
132 | + * @return | |
133 | + */ | |
134 | + private String getBeDistributeVin(PubStandStaffInfo staffInfo, List<String> vinList) { | |
135 | + String vin = null; | |
136 | + PubStandType standType = Optional.ofNullable(staffInfo.getStandType()).orElse(PubStandType.PUB); | |
137 | + switch (standType) { | |
138 | + case PUB: | |
139 | + vin = vinList.get(0); | |
140 | + break; | |
141 | + case ACTIVITY: | |
142 | + vin = determineMkt(vinList, staffInfo); | |
143 | + break; | |
144 | + default: | |
145 | + break; | |
146 | + } | |
147 | + return vin; | |
148 | + } | |
149 | + | |
150 | + /** | |
151 | + * 查询档案用户能否参与活动 | |
152 | + * | |
153 | + * @param vinList | |
154 | + * @param staffInfo | |
155 | + * @return | |
156 | + */ | |
157 | + private String determineMkt(List<String> vinList, PubStandStaffInfo staffInfo) { | |
158 | + for (String vin : vinList) { | |
159 | + // todo: 查询活动判断能否参与 | |
160 | + if (!vin.isEmpty()) { | |
161 | + return vin; | |
162 | + } | |
163 | + } | |
164 | + return null; | |
165 | + } | |
166 | + | |
167 | + /** | |
168 | + * 创建线索和分配记录 | |
169 | + * @param vin | |
170 | + * @param staffInfo | |
171 | + * @return | |
172 | + */ | |
173 | + public boolean createClue(String vin, PubStandStaffInfo staffInfo) { | |
174 | + // TODO: 2023/3/17 创建线索 | |
175 | + Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId()); | |
176 | + if (Objects.isNull(customer)) { | |
177 | + publicPoolService.removeByVin(vin, staffInfo.getGroupId()); | |
178 | + return false; | |
179 | + } | |
180 | + return true; | |
181 | + } | |
182 | +} | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubDistributeBizService.kt deleted
1 | -package cn.fw.valhalla.service.bus.pub; | |
2 | - | |
3 | -import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo | |
4 | -import cn.fw.valhalla.rpc.ehr.EhrRpcService | |
5 | -import cn.fw.valhalla.service.data.PubStandStaffInfoService | |
6 | -import lombok.extern.slf4j.Slf4j | |
7 | -import org.springframework.stereotype.Service | |
8 | - | |
9 | -/** | |
10 | - * 公共池站岗分配 | |
11 | - * | |
12 | - * @author : kurisu | |
13 | - * @version : 1.0 | |
14 | - * @className : PubDBizService | |
15 | - * @description : 公共池站岗分配 | |
16 | - * @date : 2023-03-11 15:55 | |
17 | - */ | |
18 | -@Service | |
19 | -@Slf4j | |
20 | -class PubDistributeBizService( | |
21 | - private val ehrRpcService: EhrRpcService, | |
22 | - private val pubStandStaffInfoService: PubStandStaffInfoService | |
23 | -) { | |
24 | - | |
25 | - /** | |
26 | - * 执行分配 | |
27 | - * | |
28 | - * @param id | |
29 | - */ | |
30 | - fun distribute(id: Long): Boolean { | |
31 | - val staffInfo: PubStandStaffInfo = pubStandStaffInfoService.getById(id) ?: return true | |
32 | - if (staffInfo.noInvolved || !staffInfo.lining) { | |
33 | - return true | |
34 | - } | |
35 | - | |
36 | - // TODO: 2023/3/15 分配 | |
37 | - return true; | |
38 | - } | |
39 | - | |
40 | -} |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubFollowBizService.java
0 → 100644
1 | +package cn.fw.valhalla.service.bus.pub; | |
2 | + | |
3 | +import lombok.extern.slf4j.Slf4j; | |
4 | +import org.springframework.stereotype.Service; | |
5 | + | |
6 | +/** | |
7 | + * 公共池跟进处理 | |
8 | + * | |
9 | + * @author : kurisu | |
10 | + * @version : 1.0 | |
11 | + * @className : PubFollowBizService | |
12 | + * @description : 公共池跟进处理 | |
13 | + * @date : 2023-03-17 17:23 | |
14 | + */ | |
15 | +@Service | |
16 | +@Slf4j | |
17 | +public class PubFollowBizService { | |
18 | +} | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/pub/PubStandBizService.java
... | ... | @@ -95,7 +95,6 @@ public class PubStandBizService { |
95 | 95 | * |
96 | 96 | * @param staffId |
97 | 97 | */ |
98 | - @Transactional(rollbackFor = Exception.class) | |
99 | 98 | public void join(final Long staffId) { |
100 | 99 | this.join(staffId, true); |
101 | 100 | } |
... | ... | @@ -118,7 +117,7 @@ public class PubStandBizService { |
118 | 117 | ShopDTO shop = oopService.shop(shopId); |
119 | 118 | BV.notNull(shop, () -> "门店信息读取失败,请稍后重试"); |
120 | 119 | final String shopName = shop.getShortName(); |
121 | - boolean hasTodo = shirasawaRpcService.hasOngoingFollow(staffId); | |
120 | + boolean hasTodo = Boolean.FALSE.equals(shirasawaRpcService.hasOngoingFollow(staffId)); | |
122 | 121 | BV.isFalse(hasTodo, () -> "还有未完成的跟进待办,无法站岗"); |
123 | 122 | final Long groupId = user.getGroupId(); |
124 | 123 | |
... | ... | @@ -153,8 +152,31 @@ public class PubStandBizService { |
153 | 152 | staffInfo.ifPresent(r -> { |
154 | 153 | r.setLining(Boolean.FALSE); |
155 | 154 | r.setNoInvolved(Boolean.FALSE); |
156 | - pubStandStaffInfoService.updateById(r); | |
157 | - CompletableFuture.runAsync(() -> syncQueue(groupId)); | |
155 | + r.setReasonOfNoLining("主动退出"); | |
156 | + boolean updated = pubStandStaffInfoService.updateById(r); | |
157 | + if (updated) { | |
158 | + CompletableFuture.runAsync(() -> syncQueue(groupId)); | |
159 | + } | |
160 | + }); | |
161 | + } | |
162 | + | |
163 | + /** | |
164 | + * 退出队列 | |
165 | + * | |
166 | + * @param userId | |
167 | + * @param groupId | |
168 | + */ | |
169 | + @Transactional(rollbackFor = Exception.class) | |
170 | + public void exitStand(final Long userId, final Long groupId, final String reason) { | |
171 | + Optional<PubStandStaffInfo> staffInfo = pubStandStaffInfoService.queryStaffByGroupId(userId, groupId); | |
172 | + staffInfo.ifPresent(r -> { | |
173 | + r.setLining(Boolean.FALSE); | |
174 | + r.setNoInvolved(Boolean.FALSE); | |
175 | + r.setReasonOfNoLining(reason); | |
176 | + boolean updated = pubStandStaffInfoService.updateById(r); | |
177 | + if (updated) { | |
178 | + CompletableFuture.runAsync(() -> syncQueue(groupId)); | |
179 | + } | |
158 | 180 | }); |
159 | 181 | } |
160 | 182 | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/PublicPoolService.java
... | ... | @@ -18,6 +18,7 @@ import java.util.Optional; |
18 | 18 | public interface PublicPoolService extends IService<PublicPool> { |
19 | 19 | /** |
20 | 20 | * 根据车牌号查询 |
21 | + * | |
21 | 22 | * @param plateNo |
22 | 23 | * @param groupId |
23 | 24 | * @return |
... | ... | @@ -26,12 +27,20 @@ public interface PublicPoolService extends IService<PublicPool> { |
26 | 27 | |
27 | 28 | /** |
28 | 29 | * 移除公共池 |
30 | + * | |
29 | 31 | * @param customerId |
30 | 32 | * @param groupId |
31 | 33 | */ |
32 | 34 | @Transactional(rollbackFor = Exception.class) |
33 | 35 | void removeByCustomerId(Long customerId, Long groupId); |
34 | - | |
36 | + /** | |
37 | + * 移除公共池 | |
38 | + * | |
39 | + * @param vin | |
40 | + * @param groupId | |
41 | + */ | |
42 | + @Transactional(rollbackFor = Exception.class) | |
43 | + void removeByVin(String vin, Long groupId); | |
35 | 44 | /** |
36 | 45 | * 查询公共池 |
37 | 46 | * |
... | ... | @@ -47,4 +56,11 @@ public interface PublicPoolService extends IService<PublicPool> { |
47 | 56 | * @return |
48 | 57 | */ |
49 | 58 | Long publicListCount(PublicPoolQueryVO queryVO); |
59 | + | |
60 | + /** | |
61 | + * 根据门店id查询对应车架号 | |
62 | + * @param shopIds | |
63 | + * @return | |
64 | + */ | |
65 | + List<String> queryIdListByShops(List<Long> shopIds); | |
50 | 66 | } | ... | ... |
fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/PublicPoolServiceImpl.java
... | ... | @@ -10,8 +10,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
10 | 10 | import lombok.extern.slf4j.Slf4j; |
11 | 11 | import org.springframework.stereotype.Service; |
12 | 12 | import org.springframework.transaction.annotation.Transactional; |
13 | +import org.springframework.util.CollectionUtils; | |
13 | 14 | |
14 | 15 | import java.util.ArrayList; |
16 | +import java.util.Collections; | |
15 | 17 | import java.util.List; |
16 | 18 | import java.util.Optional; |
17 | 19 | |
... | ... | @@ -43,6 +45,15 @@ public class PublicPoolServiceImpl extends ServiceImpl<PublicPoolMapper, PublicP |
43 | 45 | ); |
44 | 46 | } |
45 | 47 | |
48 | + @Transactional(rollbackFor = Exception.class) | |
49 | + @Override | |
50 | + public void removeByVin(final String vin, final Long groupId) { | |
51 | + remove(Wrappers.<PublicPool>lambdaQuery() | |
52 | + .eq(PublicPool::getFrameNo, vin) | |
53 | + .eq(PublicPool::getGroupId, groupId) | |
54 | + ); | |
55 | + } | |
56 | + | |
46 | 57 | @Override |
47 | 58 | public List<PublicPoolDTO> publicList(PublicPoolQueryVO queryVO) { |
48 | 59 | Integer current = queryVO.getCurrent(); |
... | ... | @@ -55,4 +66,13 @@ public class PublicPoolServiceImpl extends ServiceImpl<PublicPoolMapper, PublicP |
55 | 66 | public Long publicListCount(PublicPoolQueryVO queryVO) { |
56 | 67 | return Optional.ofNullable(getBaseMapper().publicListCount(queryVO)).orElse(0L); |
57 | 68 | } |
69 | + | |
70 | + @Override | |
71 | + public List<String> queryIdListByShops(final List<Long> shopIds) { | |
72 | + if (CollectionUtils.isEmpty(shopIds)) { | |
73 | + return Collections.emptyList(); | |
74 | + } | |
75 | + // mybatis plus 性能有问题 不使用 | |
76 | + return Optional.ofNullable(this.getBaseMapper().queryIdListByShops(shopIds)).orElse(Collections.emptyList()); | |
77 | + } | |
58 | 78 | } | ... | ... |