diff --git a/doc/sql/data处理sql.sql b/doc/v1.0.0/data处理sql.sql index a41cf44..f313dad 100644 --- a/doc/sql/data处理sql.sql +++ b/doc/v1.0.0/data处理sql.sql @@ -1,4 +1,9 @@ -- 订单数据处理 +DELETE FROM follow_task WHERE type = 1; +DELETE FROM follow_record WHERE type = 1; +DELETE FROM follow_notice_record WHERE follow_type = 1; +DELETE FROM original_data WHERE type = 1; + insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time, update_time) SELECT 1, @@ -9,81 +14,97 @@ SELECT 1, w1.group_id, now(), now() -from `fw_order_v2.9.7`.car_order w1 - inner JOIN `fw_order_v2.9.7`.car_delivery_info w2 on w1.id = w2.order_id -where w1.id in ( +from `fw_valhalla`.car_order w1 + inner JOIN `fw_valhalla`.car_delivery_info w2 on w1.id = w2.order_id + INNER JOIN fw_valhalla.customer w3 on w1.car_vin = w3.frame_no +where w3.adviser_id is not NULL and w1.id in ( select max(w1.id) as id - from `fw_order_v2.9.7`.car_order w1 - inner JOIN `fw_order_v2.9.7`.car_delivery_info w2 on w1.id = w2.order_id + from `fw_valhalla`.car_order w1 + inner JOIN `fw_valhalla`.car_delivery_info w2 on w1.id = w2.order_id where w2.delivery_done = 1 and w1.group_id = 2 and w1.order_canceled = 0 - and w2.delivery_date >= DATE_ADD(NOW(), INTERVAL - 9 MONTH) + and w2.delivery_date >= DATE_ADD(NOW(), INTERVAL - 61 DAY ) group by w1.cust_archive_id ); -- 保险数据处理 +DELETE FROM follow_task WHERE type = 4; +DELETE FROM follow_record WHERE type = 4; +DELETE FROM follow_notice_record WHERE follow_type = 4; +DELETE FROM original_data WHERE type = 4; + insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time, update_time) SELECT 4, - w1.cus_id, - DATE_ADD(w1.effective_date, INTERVAL + 1 YEAR), w1.id, - 0, + w1.buy_date, + -1 * w1.id, + 1, w1.group_id, now(), now() -from fw_angel.insurance_policy w1 -where w1.id in ( - select max(w1.id) as id - from fw_angel.insurance_policy w1 - where w1.issue_date >= DATE_ADD(NOW(), INTERVAL - 4 MONTH) - group by w1.cus_id -); +from fw_valhalla.customer w1 WHERE w1.yn=1; + +UPDATE original_data +SET generate_time = DATE_ADD( generate_time, INTERVAL + 1 YEAR ) +WHERE + type=4 and + generate_time < DATE_ADD( + NOW(), + INTERVAL - 304 DAY); + + -- 售后工单首保处理 +DELETE FROM original_data WHERE type = 2; insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time, update_time) SELECT 2, - customer_id, - actual_pickup_time, - id, + t1.customer_id, + t1.actual_pickup_time, + t1.id, 0, - group_id, + t1.group_id, now(), now() -from fw_cas.`order` -where id in ( - select max(id) as id - from fw_cas.`order` - where metal_sheet = 0 - and `status` = 9 - and (FIND_IN_SET(2, type) or FIND_IN_SET(2, type)) - and customer_id is not null - and actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 5 MONTH) - group by customer_id +from fw_cas.`order` t1 inner join fw_valhalla.customer t2 on t1.customer_id = t2.id +where t2.adviser_id is not null and t1.id in ( + select max(t3.id) as id + from fw_cas.`order` t3 + where t3.metal_sheet = 0 + and t3.`status` = 9 + and (FIND_IN_SET(2, t3.type) or FIND_IN_SET(2, t3.type)) + and t3.customer_id is not null + and t3.actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 65 DAY ) + group by t3.customer_id ); -- 流失客户数据处理 +DELETE FROM follow_task WHERE type = 2; +DELETE FROM follow_record WHERE type = 2; +DELETE FROM follow_notice_record WHERE follow_type = 2; +DELETE FROM original_data WHERE type = 5; + insert into fw_valhalla.original_data(type, customer_id, generate_time, detail_id, solved, group_id, create_time, update_time) SELECT 5, - customer_id, - actual_pickup_time, - id, + t1.customer_id, + t1.actual_pickup_time, + t1.id, 0, - group_id, + t2.group_id, now(), now() -from fw_cas.`order` -where id in ( - select max(id) as id - from fw_cas.`order` - where `status` = 9 - and customer_id is not null - and actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 5 MONTH) - group by customer_id +from fw_cas.`order` t1 inner join fw_valhalla.customer t2 on t1.customer_id = t2.id +where t2.adviser_id is not null and t1.id in ( + select max(t3.id) as id + from fw_cas.`order` t3 + where t3.`status` = 9 + and t3.customer_id is not null + and t3.actual_pickup_time >= DATE_ADD(NOW(), INTERVAL - 120 DAY ) + group by t3.customer_id ); diff --git a/doc/fw-valhalla.json b/doc/v1.0.0/fw-valhalla.json index 64c954f..64c954f 100644 --- a/doc/fw-valhalla.json +++ b/doc/v1.0.0/fw-valhalla.json diff --git a/doc/sql/fw-valhalla.sql b/doc/v1.0.0/fw-valhalla.sql index 2ba7d78..2ba7d78 100644 --- a/doc/sql/fw-valhalla.sql +++ b/doc/v1.0.0/fw-valhalla.sql diff --git a/doc/售后CRM.drawio b/doc/v1.0.0/售后CRM.drawio index 9f3d075..9f3d075 100644 --- a/doc/售后CRM.drawio +++ b/doc/v1.0.0/售后CRM.drawio diff --git a/doc/sql/档案数据处理.sql b/doc/v1.0.0/档案数据处理.sql index 0a1e78a..0a1e78a 100644 --- a/doc/sql/档案数据处理.sql +++ b/doc/v1.0.0/档案数据处理.sql diff --git a/doc/v1.0.1/v1.0.1.sql b/doc/v1.0.1/v1.0.1.sql new file mode 100644 index 0000000..5c84755 --- /dev/null +++ b/doc/v1.0.1/v1.0.1.sql @@ -0,0 +1,48 @@ +-- accident_pool changes +alter table accident_pool + add report_mobile varchar(128) not null comment '报案手机号' after mobile; + +alter table accident_pool + modify shop_id bigint not null comment '服务站id'; + +alter table accident_pool + drop column user_id; + +alter table accident_pool + add shop_name varchar(255) not null comment '所属服务站名称' after shop_id; + +alter table accident_pool + add address varchar(255) null comment '报案地址' after shop_name; + +alter table accident_pool + add sms varchar(512) null comment '短信详情' after group_id; + +drop index report_num_group_index on accident_pool; + +-- approve_record changes +alter table approve_record + add type int(3) default 1 not null comment '1: 跟进战败 2:其他' after reason; + +-- leave_need_do +create table leave_need_do +( + id bigint auto_increment, + user_id bigint not null comment '用户id', + user_name varchar(225) null comment '用户名', + type int(3) not null comment '待办类型 10:客户待分配 20: 其他', + shop_id bigint not null comment '用户所属服务站', + reason int(3) not null comment '产生此条待办原因 1:离职 2:调岗 3:其他', + effective_time datetime null comment '变动生效时间', + done tinyint(1) default '0' not null comment '是否已处理 ', + create_time datetime null, + update_time datetime null, + constraint leave_need_do_pk + primary key (id) +) + comment '人员变动待办事项'; + +create index leave_need_do_index + on leave_need_do (user_id, user_name, shop_id); + + + diff --git a/doc/v1.0.1/升级事项.md b/doc/v1.0.1/升级事项.md new file mode 100644 index 0000000..9f4288d --- /dev/null +++ b/doc/v1.0.1/升级事项.md @@ -0,0 +1,29 @@ +##### 新增角色: + + |名称|角色码|备注| + | --|--|--| + |保有客分配 |BYKFP |一个服务站一个| + + +##### 资源路径: + ASCustomerDistribute 保有客分配 菜单 + /app/leave2do/customer/** 保有客分配url + AsCrmOwnFollowUpPool 跟进池 菜单 + /app/pool/follow/** 跟进池列表请求url + +##### 其他配置: +- 待办 + |待办项|待办路径| 通知对象| + | --|--|--| + |保有客离职分配|ASCustomerDistribute| 保有客分配| + +##### 升级内容: + +1. 去掉战败池和成交池 +2. 跟进池调整(菜单只能看自己的) +3. 事故车线索新增备案手机号 +4. 新增离职分配功能(需等人事下个版本) +4. 跟进算法调整 +5. 首保设置新增项目 +7. 报表 +8. 成交、战败 逻辑调整 diff --git a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/constant/RoleCode.java b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/constant/RoleCode.java index 07fc50b..90ba135 100644 --- a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/constant/RoleCode.java +++ b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/constant/RoleCode.java @@ -16,15 +16,11 @@ public interface RoleCode { */ String SGCGJ = "SGCGJ"; /** - * 首保跟进 - */ - String SBGJ = "SBGJ"; - /** * 续保跟进 */ String XBGJ = "XBGJ"; /** - * 流失客户跟进 + * 保有客分配 */ - String LSKHGJ = "LSKHGJ"; + String BYKFP = "BYKFP"; } \ No newline at end of file diff --git a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/AllocationTypeEnum.java b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/AllocationTypeEnum.java new file mode 100644 index 0000000..2e00a30 --- /dev/null +++ b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/AllocationTypeEnum.java @@ -0,0 +1,49 @@ +package cn.fw.valhalla.common.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.Getter; + +/** + * @author : kurisu + * @className : AllocationTypeEnum + * @description : 分配方式 + * @date: 2020-10-16 17:56 + */ +public enum AllocationTypeEnum { + /** + * 指定人员 + */ + ONE(1, "指定人员"), + /** + * 平均分配 + */ + ALL(2, "平均分配"); + + /** + * 值 + */ + private final Integer value; + /** + * 名称 + */ + @Getter + private final String name; + + AllocationTypeEnum(final Integer value, final String name) { + this.value = value; + this.name = name; + } + + /** + * 根据枚举值获取枚举对象 + */ + @JsonCreator + public static AllocationTypeEnum ofValue(final Integer value) { + for (final AllocationTypeEnum typeEnum : AllocationTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum; + } + } + return null; + } +} diff --git a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/DefeatTypeEnum.java b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/DefeatTypeEnum.java new file mode 100644 index 0000000..6689b1c --- /dev/null +++ b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/enums/DefeatTypeEnum.java @@ -0,0 +1,53 @@ +package cn.fw.valhalla.common.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.Getter; + +/** + * @author : kurisu + * @className : DefeatTypeEnum + * @description : 战败类型 + * @date: 2020-10-16 17:56 + */ +public enum DefeatTypeEnum { + /** + * 主动战败 + */ + A(1, "主动战败"), + /** + * 到期划走 + */ + B(2, "到期划走"), + /** + * 到期战败 + */ + C(3, "到期战败"); + + /** + * 值 + */ + private final Integer value; + /** + * 名称 + */ + @Getter + private final String name; + + DefeatTypeEnum(final Integer value, final String name) { + this.value = value; + this.name = name; + } + + /** + * 根据枚举值获取枚举对象 + */ + @JsonCreator + public static DefeatTypeEnum ofValue(final Integer value) { + for (final DefeatTypeEnum typeEnum : DefeatTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum; + } + } + return null; + } +} diff --git a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/DateUtil.java b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/DateUtil.java index 83c69ea..7693b4a 100644 --- a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/DateUtil.java +++ b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/DateUtil.java @@ -7,6 +7,7 @@ import java.time.*; import java.time.temporal.TemporalAdjusters; import java.util.Calendar; import java.util.Date; +import java.util.Objects; /** * 日期处理工具 @@ -453,9 +454,79 @@ public final class DateUtil { return (int) result; } + /** + * 判断是否是凌晨 + * + * @param date + * @return + */ + public static boolean isBeforeDawn(Date date) { + if (Objects.isNull(date)) { + return false; + } + LocalDateTime dateTime = date2LocalDateTime(date); + SimpleDateFormat df = new SimpleDateFormat("HH"); + String str = df.format(localDateTime2Date(dateTime)); + int a = Integer.parseInt(str); + return a >= 0 && a <= 6; + } + + /** + * 判断是否是上午 + * + * @param date + * @return + */ + public static boolean isMorning(Date date) { + if (Objects.isNull(date)) { + return false; + } + LocalDateTime dateTime = date2LocalDateTime(date); + SimpleDateFormat df = new SimpleDateFormat("HH"); + String str = df.format(localDateTime2Date(dateTime)); + int a = Integer.parseInt(str); + return a > 6 && a <= 12; + } + + /** + * 判断是否是下午 + * + * @param date + * @return + */ + public static boolean isAfternoon(Date date) { + if (Objects.isNull(date)) { + return false; + } + LocalDateTime dateTime = date2LocalDateTime(date); + SimpleDateFormat df = new SimpleDateFormat("HH"); + String str = df.format(localDateTime2Date(dateTime)); + int a = Integer.parseInt(str); + return a > 12 && a <= 18; + } + + /** + * 判断是否是晚上 + * + * @param date + * @return + */ + public static boolean isEvening(Date date) { + if (Objects.isNull(date)) { + return false; + } + LocalDateTime dateTime = date2LocalDateTime(date); + SimpleDateFormat df = new SimpleDateFormat("HH"); + String str = df.format(localDateTime2Date(dateTime)); + int a = Integer.parseInt(str); + return a > 18 && a <= 23; + } + public static void main(String[] args) throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date = format.parse("2020-09-09 09:45:30"); + Date date = format.parse("2020-09-19 09:45:30"); System.out.println(startDate(getNowExpiredDay(-1))); + + System.out.println(sub(date, new Date(), "d")); } } diff --git a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/StringUtils.java b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/StringUtils.java index 4dd674a..5fe2139 100644 --- a/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/StringUtils.java +++ b/fw-valhalla-common/src/main/java/cn/fw/valhalla/common/utils/StringUtils.java @@ -1,5 +1,6 @@ package cn.fw.valhalla.common.utils; + import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; @@ -519,8 +520,8 @@ public final class StringUtils { System.out.println(toUUID("1")); System.out.println(removePrefix("abcd123", "ab")); System.out.println(removeSuffix("abcd123", "123")); - System.out.println(toColumnName("usernameid")); - System.out.println(getFieldString(toColumnName("userNameId"))); + System.out.println(toColumnName("usernameId")); + System.out.println(getFieldString("user_name_id")); System.out.println(repeat("?", 10, ",")); length("AAA中国()111222bb"); } diff --git a/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/FollowTaskMapper.java b/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/FollowTaskMapper.java index 0db7963..d2ae49b 100644 --- a/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/FollowTaskMapper.java +++ b/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/FollowTaskMapper.java @@ -18,29 +18,12 @@ import java.util.List; @Repository public interface FollowTaskMapper extends BaseMapper { /** - * 战败池 - * @param startIndex - * @param pageSize - * @param queryVO - * @return - */ - List defeatList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO); - - /** * 跟进池 + * * @param startIndex * @param pageSize * @param queryVO * @return */ List followList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO); - - /** - * 成交池 - * @param startIndex - * @param pageSize - * @param queryVO - * @return - */ - List completeList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize, @Param("condition") FollowPoolQueryVO queryVO); } diff --git a/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/LeaveNeedDoMapper.java b/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/LeaveNeedDoMapper.java new file mode 100644 index 0000000..916b010 --- /dev/null +++ b/fw-valhalla-dao/src/main/java/cn/fw/valhalla/dao/mapper/LeaveNeedDoMapper.java @@ -0,0 +1,15 @@ +package cn.fw.valhalla.dao.mapper; + +import cn.fw.valhalla.domain.db.LeaveNeedDo; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springframework.stereotype.Repository; + +/** + * @author : kurisu + * @className : LeaveNeedDoMapper + * @description : 人员变动待处理事件 + * @date: 2020-10-16 17:00 + */ +@Repository +public interface LeaveNeedDoMapper extends BaseMapper { +} diff --git a/fw-valhalla-dao/src/main/resources/mapper/FollowTaskMapper.xml b/fw-valhalla-dao/src/main/resources/mapper/FollowTaskMapper.xml index f93800e..9de2f05 100644 --- a/fw-valhalla-dao/src/main/resources/mapper/FollowTaskMapper.xml +++ b/fw-valhalla-dao/src/main/resources/mapper/FollowTaskMapper.xml @@ -2,119 +2,138 @@ + where t1.state = 3 + and ((t1.finished = 0 and + t1.deadline >= #{condition.startTime} and t1.deadline < #{condition.endTime}) or + (t1.finished = 1 and + t1.finish_time >= #{condition.startTime} and t1.finish_time < #{condition.endTime})) - + where t1.state = 3 + and t1.type != 3 + and ((t1.finished = 0 and + t1.deadline >= #{condition.startTime} and t1.deadline < #{condition.endTime}) or + (t1.finished = 1 and + t1.finish_time >= #{condition.startTime} and t1.finish_time < #{condition.endTime})) - diff --git a/fw-valhalla-dao/src/main/resources/mapper/LeaveNeedDoMapper.xml b/fw-valhalla-dao/src/main/resources/mapper/LeaveNeedDoMapper.xml new file mode 100644 index 0000000..639c55a --- /dev/null +++ b/fw-valhalla-dao/src/main/resources/mapper/LeaveNeedDoMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/ApproveRecord.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/ApproveRecord.java index 188efe9..682793b 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/ApproveRecord.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/ApproveRecord.java @@ -2,6 +2,7 @@ package cn.fw.valhalla.domain.db; import cn.fw.common.data.entity.BaseAuditableTimeEntity; import cn.fw.valhalla.domain.enums.ApproveStateEnum; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -40,4 +41,8 @@ public class ApproveRecord extends BaseAuditableTimeEntity * 通过与否 */ private Boolean passed; + /** + * 审批类型 + */ + private ApproveTypeEnum type; } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/LeaveNeedDo.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/LeaveNeedDo.java new file mode 100644 index 0000000..6d9a594 --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/LeaveNeedDo.java @@ -0,0 +1,50 @@ +package cn.fw.valhalla.domain.db; + +import cn.fw.common.data.entity.BaseAuditableTimeEntity; +import cn.fw.valhalla.domain.enums.LeaveReasonEnum; +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +/** + * @author : kurisu + * @className : LeaveNeedDo + * @description : 人员变动待处理事项 + * @date: 2020-10-16 16:47 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class LeaveNeedDo extends BaseAuditableTimeEntity { + /** + * 用户id + */ + private Long userId; + /** + * 用户名 + */ + private String userName; + /** + * 事件类型 + */ + private LeaveTodoTypeEnum type; + /** + * 用户所属门店 + */ + private Long shopId; + /** + * 用户变动原因 + */ + private LeaveReasonEnum reason; + /** + * 生效时间 + */ + private Date effectiveTime; + /** + * 是否已完成处理 + */ + private Boolean done; +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/AccidentPool.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/AccidentPool.java index 148f9c7..649a581 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/AccidentPool.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/db/customer/AccidentPool.java @@ -23,6 +23,10 @@ public class AccidentPool extends BaseAuditableTimeEntity { */ private String mobile; /** + * 报案手机号 + */ + private String reportMobile; + /** * 车牌号 */ private String plateNo; @@ -63,15 +67,23 @@ public class AccidentPool extends BaseAuditableTimeEntity { */ private String reportNum; /** - * 服务站id + * 所属门店id */ private Long shopId; /** - * 集团id + * 所属门店 */ - private Long groupId; + private String shopName; + /** + * 报案地点 + */ + private String address; /** - * 跟进人id + * 短信 */ - private Long userId; + private String sms; + /** + * 集团id + */ + private Long groupId; } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/AccidentPoolDTO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/AccidentPoolDTO.java index da90775..327408a 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/AccidentPoolDTO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/AccidentPoolDTO.java @@ -23,9 +23,13 @@ public class AccidentPoolDTO { /** * 电话号码 */ - @NotBlank(message = "电话号码不能为空") private String mobile; /** + * 报案手机号 + */ + @NotBlank(message = "报案手机号不能为空") + private String reportMobile; + /** * 车牌号 */ @NotBlank(message = "车牌号不能为空") @@ -63,7 +67,11 @@ public class AccidentPoolDTO { */ private String insurerName; /** - * 门店id + * 所属门店id */ private Long shopId; + /** + * 报案地点 + */ + private String address; } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/FollowPoolDTO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/FollowPoolDTO.java index 77da1d7..971d7b4 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/FollowPoolDTO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/FollowPoolDTO.java @@ -25,55 +25,55 @@ public class FollowPoolDTO { */ private Integer type; /** - * 原始数据产生时间 + * 二次跟进 */ - private Date originTime; + private Boolean redistribution; /** - * 任务开始时间 + * 人员id */ - private Date beginTime; + private Long userId; /** - * 原始跟进顾问id + * 门店id */ - private Long originUser; + private Long shopId; /** - * 原始跟进门店 - */ - private Long originShop; - /** - * 完成人 + * 跟进次数 */ - private Long finishUser; + private Integer times; /** - * 完成门店 + * 剩余天数 */ - private Long finishShop; + private Integer remaining; /** - * 状态 + * 状态 1:进行中 2:已成交 3:战败 */ private Integer state; /** - * 完成人员更换 + * 成交时间 */ - private Boolean changed; + private Date finishTime; /** - * 当前跟进服务顾问id + * 战败时间 */ - private Long followUser; + private Date defeatTime; /** - * 当前跟进服务站 + * 战败类型 */ - private Long followShop; + private Integer initiative; /** - * 截止日期 + * 集团id */ - private Date deadline; + private Long groupId; + + + private Integer originState; + private Boolean finished; /** - * 是否完成任务 + * 原始跟进门店 */ - private Boolean finished; + private Long originShop; /** - * 完成时间 + * 完成门店 */ - private Date finishTime; + private Long finishShop; } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/LeaveAllocationDTO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/LeaveAllocationDTO.java new file mode 100644 index 0000000..ff76ca0 --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/dto/LeaveAllocationDTO.java @@ -0,0 +1,40 @@ +package cn.fw.valhalla.domain.dto; + +import cn.fw.valhalla.common.enums.AllocationTypeEnum; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * @author : kurisu + * @className : LeaveAllocationDTO + * @description : 离职分配DTO + * @date: 2020-10-16 17:52 + */ +@Data +public class LeaveAllocationDTO { + @NotNull(message = "记录id不能为空") + private Long id; + + @NotNull(message = "分配方式不能为空") + private Integer allocationType; + + /** + * 指定人员id + */ + private Long userId; + + /** + * 门店id (前端无关) + */ + private Long shopId; + + /** + * 分配方式 (前端无关) + */ + private AllocationTypeEnum type; + /** + * 顾问id (前端无关) + */ + private Long adviserId; +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveStateEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveStateEnum.java index bd2968c..bb29d4b 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveStateEnum.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveStateEnum.java @@ -20,6 +20,10 @@ public enum ApproveStateEnum implements IEnum { * 完成回调 */ DONE(2, "完成回调"), + /** + * 已取消 + */ + CANCELED(3, "已取消"), ; /** diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveTypeEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveTypeEnum.java new file mode 100644 index 0000000..39fd5fe --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/ApproveTypeEnum.java @@ -0,0 +1,78 @@ +package cn.fw.valhalla.domain.enums; + +import com.baomidou.mybatisplus.core.enums.IEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.Getter; + +/** + * @author : kurisu + * @className : ApproveTypeEnum + * @description : 审批类型 + * @date: 2020-10-15 17:37 + */ +public enum ApproveTypeEnum implements IEnum { + /** + * 等待回调 + */ + FOLLOW_DEFEAT(1, "跟进战败"), + /** + * 完成回调 + */ + OTHER(2, "其他"), + ; + + /** + * 值 + */ + private final Integer value; + /** + * 名称 + */ + @Getter + private final String name; + + ApproveTypeEnum(final Integer value, final String name) { + this.value = value; + this.name = name; + } + + /** + * 根据枚举值获取枚举对象 + */ + @JsonCreator + public static ApproveTypeEnum ofValue(final Integer value) { + for (final ApproveTypeEnum typeEnum : ApproveTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum; + } + } + return null; + } + + /** + * 获取值 + * + * @return 值 + */ + @JsonValue + @Override + public Integer getValue() { + return value; + } + + /** + * 获取描述 + * + * @return 值 + */ + @JsonCreator + public static String getNameByVale(final Integer value) { + for (final ApproveTypeEnum typeEnum : ApproveTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum.getName(); + } + } + return ""; + } +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveReasonEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveReasonEnum.java new file mode 100644 index 0000000..de725fa --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveReasonEnum.java @@ -0,0 +1,82 @@ +package cn.fw.valhalla.domain.enums; + +import com.baomidou.mybatisplus.core.enums.IEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.Getter; + +/** + * @author : kurisu + * @className : LeaveReasonEnum + * @description : 人员变动类型 + * @date: 2020-08-11 17:37 + */ +public enum LeaveReasonEnum implements IEnum { + /** + * 离职 + */ + LEAVE(1, "离职"), + /** + * 调岗 + */ + CHANGE(2, "调岗"), + /** + * 其他 + */ + OTHER(3, "其他"), + ; + + /** + * 值 + */ + private final Integer value; + /** + * 名称 + */ + @Getter + private final String name; + + LeaveReasonEnum(final Integer value, final String name) { + this.value = value; + this.name = name; + } + + /** + * 根据枚举值获取枚举对象 + */ + @JsonCreator + public static LeaveReasonEnum ofValue(final Integer value) { + for (final LeaveReasonEnum typeEnum : LeaveReasonEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum; + } + } + return null; + } + + /** + * 获取值 + * + * @return 值 + */ + @JsonValue + @Override + public Integer getValue() { + return value; + } + + /** + * 获取描述 + * + * @return 值 + */ + @JsonCreator + public static String getNameByVale(final Integer value) { + for (final LeaveReasonEnum typeEnum : LeaveReasonEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum.getName(); + } + } + return ""; + } +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveTodoTypeEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveTodoTypeEnum.java new file mode 100644 index 0000000..31e6799 --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/LeaveTodoTypeEnum.java @@ -0,0 +1,78 @@ +package cn.fw.valhalla.domain.enums; + +import com.baomidou.mybatisplus.core.enums.IEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.Getter; + +/** + * @author : kurisu + * @className : LeaveTodoTypeEnum + * @description : 人员变动待处理事件类型 + * @date: 2020-08-11 17:37 + */ +public enum LeaveTodoTypeEnum implements IEnum { + /** + * 客户待分配 + */ + CUSTOMER(10, "客户待分配"), + /** + * 其他 + */ + OTHER(20, "其他"), + ; + + /** + * 值 + */ + private final Integer value; + /** + * 名称 + */ + @Getter + private final String name; + + LeaveTodoTypeEnum(final Integer value, final String name) { + this.value = value; + this.name = name; + } + + /** + * 根据枚举值获取枚举对象 + */ + @JsonCreator + public static LeaveTodoTypeEnum ofValue(final Integer value) { + for (final LeaveTodoTypeEnum typeEnum : LeaveTodoTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum; + } + } + return null; + } + + /** + * 获取值 + * + * @return 值 + */ + @JsonValue + @Override + public Integer getValue() { + return value; + } + + /** + * 获取描述 + * + * @return 值 + */ + @JsonCreator + public static String getNameByVale(final Integer value) { + for (final LeaveTodoTypeEnum typeEnum : LeaveTodoTypeEnum.values()) { + if (typeEnum.value.equals(value)) { + return typeEnum.getName(); + } + } + return ""; + } +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java index 1cf7567..47fa73a 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingTypeEnum.java @@ -44,6 +44,10 @@ public enum SettingTypeEnum implements IEnum { * 提醒次数 */ NOTICE_TIMES(8, "提醒次数", 8), + /** + * 首保集团标准最低值(首保用) + */ + REVISE_RATIO(9, "集团标准最低值", 9), ; /** diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java index 80910eb..4ec9564 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/enums/SettingUnitEnum.java @@ -32,6 +32,10 @@ public enum SettingUnitEnum implements IEnum { * 月 */ MONTH(5, "月"), + /** + * 百分比 + */ + RATIO(9, "%"), ; /** diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/FollowPoolQueryVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/FollowPoolQueryVO.java index e5cfca9..5082309 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/FollowPoolQueryVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/FollowPoolQueryVO.java @@ -1,15 +1,18 @@ package cn.fw.valhalla.domain.query; import cn.fw.common.page.BasePageQuery; -import cn.fw.valhalla.common.utils.StringUtils; +import cn.fw.valhalla.common.utils.DateUtil; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.springframework.util.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.Objects; /** * 档案查询条件 @@ -22,20 +25,60 @@ import java.util.stream.Collectors; @EqualsAndHashCode(callSuper = true) public class FollowPoolQueryVO extends BasePageQuery { private Integer type; - private String kw; + private String plateNo; private Long userId; - private String shopIds; + private Long shopId; + /** + * 跟进状态 + */ + private Integer state; + /** + * 二次分配 + */ + private Integer redistribution; + /** + * 主动放弃 + */ + private Integer initiative; + private String startTime; + private String endTime; + + /** + * 1升序 2降序 + */ + private Integer order; + private String orderAtt; + + private String orderString; private Long groupId; - private List shopList; - public List getShopList() { - if (StringUtils.isEmpty(this.shopIds)) { + public Integer getInitiative() { + if (Objects.isNull(initiative)) { return null; } - List list = Arrays.stream(this.shopIds.split(",")).filter(StringUtils::isValid).map(Long::valueOf).collect(Collectors.toList()); - if (CollectionUtils.isEmpty(list)) { + return initiative == 1 ? initiative : 0; + } + + public Integer getRedistribution() { + if (Objects.isNull(redistribution)) { return null; } - return list; + return redistribution == 1 ? redistribution : 0; + } + + public Date getStartTime() { + if (StringUtils.isNotBlank(startTime) && NumberUtils.isDigits(startTime)) { + LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(startTime)).atZone(ZoneId.systemDefault()).toLocalDateTime(); + return DateUtil.getBeginInTime(DateUtil.localDateTime2Date(localDateTime)); + } + return DateUtil.getMonthFirstDay(); + } + + public Date getEndTime() { + if (StringUtils.isNotBlank(endTime) && NumberUtils.isDigits(endTime)) { + LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(endTime)).atZone(ZoneId.systemDefault()).toLocalDateTime(); + return DateUtil.getEndInTime(DateUtil.localDateTime2Date(localDateTime)); + } + return new Date(); } } \ No newline at end of file diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/LeaveQueryVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/LeaveQueryVO.java new file mode 100644 index 0000000..e52b388 --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/query/LeaveQueryVO.java @@ -0,0 +1,29 @@ +package cn.fw.valhalla.domain.query; + +import cn.fw.common.page.BasePageQuery; +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Objects; + +/** + * 档案查询条件 + * + * @author kurisu + */ + +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class LeaveQueryVO extends BasePageQuery { + private Integer type; + + public LeaveTodoTypeEnum getType() { + if (Objects.isNull(type)) { + return null; + } + return LeaveTodoTypeEnum.ofValue(type); + } +} \ No newline at end of file diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/LeaveNeedDoVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/LeaveNeedDoVO.java new file mode 100644 index 0000000..4e58a96 --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/LeaveNeedDoVO.java @@ -0,0 +1,61 @@ +package cn.fw.valhalla.domain.vo; + +import cn.fw.valhalla.domain.db.LeaveNeedDo; +import lombok.Data; +import lombok.ToString; +import org.springframework.lang.NonNull; + +import java.util.Date; + +/** + * @author : kurisu + * @className : LeaveNeedDoVO + * @description : 保有客待分配列表 + * @date: 2020-10-16 16:56 + */ +@Data +@ToString(callSuper = true) +public class LeaveNeedDoVO { + private Long id; + /** + * 用户id + */ + private Long userId; + /** + * 用户名 + */ + private String userName; + /** + * 用户所属门店 + */ + private Long shopId; + /** + * 用户变动原因 + */ + private Integer reason; + /** + * 生效时间 + */ + private Date effectiveTime; + /** + * 是否已完成处理 + */ + private Boolean done; + /** + * 保有客数量 + */ + private Integer customerNum; + + public static LeaveNeedDoVO with(@NonNull LeaveNeedDo db, int i) { + LeaveNeedDoVO vo = new LeaveNeedDoVO(); + vo.setId(db.getId()); + vo.setUserId(db.getUserId()); + vo.setUserName(db.getUserName()); + vo.setShopId(db.getShopId()); + vo.setReason(db.getReason().getValue()); + vo.setEffectiveTime(db.getEffectiveTime()); + vo.setDone(db.getDone()); + vo.setCustomerNum(i); + return vo; + } +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/PostUserVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/PostUserVO.java new file mode 100644 index 0000000..51e1bcd --- /dev/null +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/PostUserVO.java @@ -0,0 +1,26 @@ +package cn.fw.valhalla.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author kurisu + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PostUserVO implements Serializable { + private static final long serialVersionUID = -6108591548534160179L; + /** + * 用户id + */ + private Long userId; + + /** + * 用户姓名 + */ + private String userName; +} diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/customer/CustomerDetailVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/customer/CustomerDetailVO.java index 4519b55..1b5575e 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/customer/CustomerDetailVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/customer/CustomerDetailVO.java @@ -5,6 +5,7 @@ import cn.fw.valhalla.common.utils.StringUtils; import lombok.Data; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -97,6 +98,10 @@ public class CustomerDetailVO { * 专属服务顾问名称 */ private String adviserName; + /** + * 购车日期 + */ + private Date buyDate; public List getTags() { if (StringUtils.isValid(this.tags)) { diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/ACDetailVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/ACDetailVO.java index 7d5ef85..dc8776a 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/ACDetailVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/ACDetailVO.java @@ -18,39 +18,27 @@ import java.util.Date; @EqualsAndHashCode(callSuper = true) public class ACDetailVO extends FollowDetailVO { /** - * 报案号 - */ - private String reportNum; - /** * 地址 */ private String address; /** - * 纬度 - */ - private BigDecimal lat; - /** - * 经度 - */ - private BigDecimal lng; - /** - * 事故原因 + * 交强险保险公司名称 */ - private String reason; + private String insComName; /** - * 交强险保险公司名称 + * 报案手机号 */ - private String tclInsComName; + private String reportMobile; /** - * 交强险保险到期时间 + * 所属门店 */ - private Date tclInsExpiration; + private Long shopId; /** - * 商业险保险公司名称 + * 所属门店 */ - private String busInsComName; + private String shopName; /** - * 商业险保险到期时间 + * 短信详情 */ - private Date busInsExpiration; + private String sms; } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowDetailVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowDetailVO.java index e61376d..4c6b2ff 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowDetailVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowDetailVO.java @@ -1,10 +1,14 @@ package cn.fw.valhalla.domain.vo.follow; import cn.fw.common.json.MaskMobilePhone; +import cn.fw.valhalla.common.utils.StringUtils; import lombok.Data; +import java.util.Arrays; import java.util.Date; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; /** * @author : kurisu @@ -77,4 +81,13 @@ public class FollowDetailVO { long ms = deadline.getTime() - System.currentTimeMillis(); return ms / 1000; } + + public List getTags() { + if (StringUtils.isValid(this.tags)) { + return Arrays.stream(this.tags.split(",")) + .filter(StringUtils::isValid) + .collect(Collectors.toList()); + } + return null; + } } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowPoolListVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowPoolListVO.java index 8511269..c57759e 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowPoolListVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/FollowPoolListVO.java @@ -1,8 +1,10 @@ package cn.fw.valhalla.domain.vo.follow; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; import lombok.Data; import java.util.Date; +import java.util.Objects; /** * @author : kurisu @@ -12,6 +14,7 @@ import java.util.Date; */ @Data public class FollowPoolListVO { + private Long id; /** * 车牌 */ @@ -41,11 +44,37 @@ public class FollowPoolListVO { */ private Integer remaining; /** - * 战败类型 + * 跟进状态 */ - private String defeatType; + private Integer state; /** * 成交时间 */ private Date finishTime; + /** + * 战败时间 + */ + private Date defeatTime; + /** + * 战败类型 + */ + private String defeatType; + /** + * 战败描述 (客户流向) + */ + private String defeatDesc; + + public String getRemaining() { + if (Objects.isNull(remaining)) { + return null; + } + StringBuilder sb = new StringBuilder(); + int num = remaining <= 0 ? 0 : remaining; + if (FollowTypeEnum.AC.getValue().equals(type)) { + sb.append(num).append("小时"); + } else { + sb.append(num / 24).append("天"); + } + return sb.toString(); + } } diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/IRDetailVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/IRDetailVO.java index 10747a9..2fdb4b4 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/IRDetailVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/follow/IRDetailVO.java @@ -17,10 +17,6 @@ import java.util.Date; @EqualsAndHashCode(callSuper = true) public class IRDetailVO extends FollowDetailVO { /** - * 购车价 - */ - private Long buyPrice; - /** * 交强险保险公司名称 */ private String tclInsComName; diff --git a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/setting/SettingVO.java b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/setting/SettingVO.java index 2c79185..9faf445 100644 --- a/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/setting/SettingVO.java +++ b/fw-valhalla-domain/src/main/java/cn/fw/valhalla/domain/vo/setting/SettingVO.java @@ -1,6 +1,7 @@ package cn.fw.valhalla.domain.vo.setting; import cn.fw.valhalla.domain.db.setting.FollowSettingDetail; +import cn.fw.valhalla.domain.enums.SettingTypeEnum; import lombok.Data; import lombok.ToString; @@ -40,6 +41,9 @@ public class SettingVO { SettingVO vo = new SettingVO(); vo.setId(detail.getId()); vo.setDetailValue(detail.getDetailValue()); + if (SettingTypeEnum.REVISE_RATIO.equals(detail.getType())) { + vo.setDetailValue(detail.getDetailValue() / 100); + } vo.setSettingId(detail.getSettingId()); vo.setType(detail.getType().getValue()); vo.setUnit(detail.getUnit().getValue()); diff --git a/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserRoleRpcService.java b/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserRoleRpcService.java index 534ad87..edde2ba 100644 --- a/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserRoleRpcService.java +++ b/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/erp/UserRoleRpcService.java @@ -5,6 +5,7 @@ import cn.fw.erp.sdk.api.UserRoleApi; import cn.fw.erp.sdk.api.result.UserRoleDataRange; import cn.fw.erp.sdk.api.result.UserRoleInfo; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -31,11 +32,11 @@ public class UserRoleRpcService { } /** - * 获取用户管理的门店 + * 查询用户角色的数据权限范围(门店) * * @param userId 用户id * @param roleCode 角色码 - * @return 用户管理门店 + * @return 门店ids */ public List getManageShopIds(Long userId, String roleCode) { if (userId == null) { @@ -43,7 +44,7 @@ public class UserRoleRpcService { } try { Message> msg = userRoleApi.queryUserRoleDataRange(userId, roleCode); - log.warn("调用ERP系统查询用户数据范围,userId:{},roleCode:{}, result:{}", userId, roleCode, msg); + log.warn("调用ERP系统查询用户数据范围,userId:{},roleCode:{}, result:{}", userId, roleCode, JSONObject.toJSONString(msg)); if (!msg.isSuccess()) { return Collections.emptyList(); } diff --git a/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/flow/FlowApproveRpc.java b/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/flow/FlowApproveRpc.java index aa751c3..a3953ab 100644 --- a/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/flow/FlowApproveRpc.java +++ b/fw-valhalla-rpc/src/main/java/cn/fw/valhalla/rpc/flow/FlowApproveRpc.java @@ -10,6 +10,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.Objects; import static cn.fw.common.businessvalidator.Validator.BV; @@ -45,4 +46,15 @@ public class FlowApproveRpc { return data.getOrderNo(); } + public boolean cancel(final String orderNo) { + try { + Message msg = flowApi.cancelApproval(Collections.singletonList(orderNo)); + log.info("取消审批FlowApproveRpc.cancelApproval, 参数:[{}] 结果:{}", orderNo, msg.getResult()); + return msg.isSuccess() && Objects.equals(Boolean.TRUE, msg.getData()); + } catch (Exception e) { + log.error("取消审批失败, 参数:[{}]", orderNo); + e.printStackTrace(); + } + return false; + } } diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/AccidentCarController.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/AccidentCarController.java index 9719b51..2df8584 100644 --- a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/AccidentCarController.java +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/AccidentCarController.java @@ -45,7 +45,7 @@ public class AccidentCarController { @PostMapping("/pool/save") public Message save(@CurrentUser LoginAuthBean currentUser, @RequestBody @Valid final AccidentPoolDTO accidentPoolDTO) { - final String msg = "手动新增事故池[/pool/save]"; + final String msg = "手动新增事故池[app/accident/pool/save]"; try { log.info("{}: param[{}]", msg, accidentPoolDTO); accidentPoolBizService.add2Pool(currentUser, accidentPoolDTO); diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/CommonController.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/CommonController.java new file mode 100644 index 0000000..1dd7a82 --- /dev/null +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/CommonController.java @@ -0,0 +1,78 @@ +package cn.fw.valhalla.controller.app; + +import cn.fw.data.base.domain.common.Message; +import cn.fw.security.auth.client.annotation.Authorization; +import cn.fw.security.auth.client.annotation.IgnoreAuth; +import cn.fw.security.auth.client.annotation.IgnoreUserToken; +import cn.fw.security.auth.client.enums.AuthType; +import cn.fw.valhalla.domain.vo.PostUserVO; +import cn.fw.valhalla.service.bus.CommonService; +import cn.fw.valhalla.service.bus.LeaveNeedDoBizService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotNull; +import java.util.List; + +import static cn.fw.common.web.util.ExceptionHandler.handleException; +import static cn.fw.common.web.util.ResultBuilder.failureWithMessage; +import static cn.fw.common.web.util.ResultBuilder.success; +import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE; + +/** + * @author : kurisu + * @className : CommonController + * @description : 公共接口 + * @date: 2020-10-22 11:06 + */ +@Slf4j +@RestController +@Authorization(AuthType.APP) +@Validated +@RequestMapping("/app/common") +public class CommonController { + private final CommonService commonService; + private final LeaveNeedDoBizService leaveNeedDoBizService; + + @Autowired + public CommonController(final CommonService commonService, + final LeaveNeedDoBizService leaveNeedDoBizService) { + this.commonService = commonService; + this.leaveNeedDoBizService = leaveNeedDoBizService; + } + + @GetMapping("/staff/list") + @IgnoreAuth + public Message> list(@NotNull(message = "服务站ID不能为空") final Long shopId, + @NotNull(message = "跟进类型不能为空") final Integer type) { + final String msg = "查询跟进人员[app/common/staff/list]"; + try { + log.info("{}: param[shopId: {} type: {}]", msg, shopId, type); + List list = commonService.getUsers(shopId, type); + return success(list, data -> log.info("{}", data)); + } catch (Exception ex) { + handleException(ex, e -> log.error("{}失败:param[shopId: {} type: {}]", msg, shopId, type, e)); + return failureWithMessage(SAVE_FAILURE); + } + } + + @PutMapping("/leave/add") + @Authorization(AuthType.NONE) + public Message add(@NotNull(message = "服务站ID不能为空") final Long shopId, + @NotNull(message = "用户ID不能为空") final Long userId) { + final String msg = "添加离职待分配数据[app/common/leave/add]"; + try { + log.info("{}: param[shopId: {} userId: {}]", msg, shopId, userId); + leaveNeedDoBizService.add(userId, shopId); + return success(); + } catch (Exception ex) { + handleException(ex, e -> log.error("{}失败:param[shopId: {} userId: {}]", msg, shopId, userId, e)); + return failureWithMessage(SAVE_FAILURE); + } + } +} diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowController.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowController.java index 6b83d4d..6aea373 100644 --- a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowController.java +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowController.java @@ -98,6 +98,7 @@ public class FollowController { } @GetMapping("/todo/record") + @IgnoreAuth public Message> todoRecord(@NotNull(message = "跟进任务id不能为空") final Long taskId, @NotNull(message = "跟进类型不能为空") final Integer type) { final String msg = "查询跟进历史记录[follow/todo/record]"; diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowPoolController.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowPoolController.java index 26ffcfe..374dd5e 100644 --- a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowPoolController.java +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/FollowPoolController.java @@ -9,7 +9,9 @@ import cn.fw.security.auth.client.annotation.IgnoreAuth; import cn.fw.security.auth.client.enums.AuthType; import cn.fw.valhalla.domain.query.FollowPoolQueryVO; import cn.fw.valhalla.domain.vo.customer.PublicPoolVO; +import cn.fw.valhalla.domain.vo.follow.FollowDetailVO; import cn.fw.valhalla.domain.vo.follow.FollowPoolListVO; +import cn.fw.valhalla.service.bus.follow.FollowBizService; import cn.fw.valhalla.service.bus.follow.FollowPoolBizService; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import lombok.extern.slf4j.Slf4j; @@ -19,6 +21,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.constraints.NotNull; + import static cn.fw.common.web.util.ExceptionHandler.handleException; import static cn.fw.common.web.util.ResultBuilder.failureWithMessage; import static cn.fw.common.web.util.ResultBuilder.success; @@ -39,19 +43,21 @@ import static cn.fw.valhalla.common.constant.MessageStr.QUERY_FAILURE; public class FollowPoolController { private final FollowPoolBizService followPoolBizService; + private final FollowBizService followBizService; @Autowired - public FollowPoolController(final FollowPoolBizService followPoolBizService) { + public FollowPoolController(final FollowPoolBizService followPoolBizService, + final FollowBizService followBizService) { this.followPoolBizService = followPoolBizService; + this.followBizService = followBizService; } - @GetMapping("/defeat/list") - public Message> defeatList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { - final String msg = "查询战败池列表[follow/pool/defeat/list]"; + @GetMapping("/follow/own/list") + public Message> ownFollowList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { + final String msg = "查询自己的跟进池列表[pool/own/follow/list]"; try { log.info("{}: param[{}]", msg, queryVO); - queryVO.setGroupId(currentUser.getGroupId()); - AppPage page = followPoolBizService.defeatList(currentUser, queryVO); + AppPage page = followPoolBizService.followList(currentUser, queryVO); return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size())); } catch (Exception ex) { handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e)); @@ -60,12 +66,13 @@ public class FollowPoolController { } @GetMapping("/follow/list") + @IgnoreAuth public Message> followList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { - final String msg = "查询跟进池列表[follow/pool/defeat/list]"; + final String msg = "查询跟进池列表[pool/follow/list]"; try { log.info("{}: param[{}]", msg, queryVO); queryVO.setGroupId(currentUser.getGroupId()); - AppPage page = followPoolBizService.followList(currentUser, queryVO); + AppPage page = followPoolBizService.followList(null, queryVO); return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size())); } catch (Exception ex) { handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e)); @@ -73,13 +80,14 @@ public class FollowPoolController { } } - @GetMapping("/complete/list") - public Message> completeList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { - final String msg = "查询成交池列表[follow/pool/defeat/list]"; + @GetMapping("/public/list") + @IgnoreAuth + public Message> publicList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { + final String msg = "查询公共池列表[pool/public/list]"; try { log.info("{}: param[{}]", msg, queryVO); queryVO.setGroupId(currentUser.getGroupId()); - AppPage page = followPoolBizService.completeList(currentUser, queryVO); + AppPage page = followPoolBizService.publicList(queryVO); return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size())); } catch (Exception ex) { handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e)); @@ -87,16 +95,16 @@ public class FollowPoolController { } } - @GetMapping("/public/list") - public Message> publicList(@CurrentUser LoginAuthBean currentUser, final FollowPoolQueryVO queryVO) { - final String msg = "查询公共池列表[follow/pool/public/list]"; + @GetMapping("/follow/detail") + @IgnoreAuth + public Message detail(@NotNull(message = "跟进池id不能为空") final Long taskId) { + final String msg = "查询跟进池详情[pool/follow/detail]"; try { - log.info("{}: param[{}]", msg, queryVO); - queryVO.setGroupId(currentUser.getGroupId()); - AppPage page = followPoolBizService.publicList(queryVO); - return success(page, data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size())); + log.info("{}: param[{}]", msg, taskId); + FollowDetailVO detailVO = followBizService.followPoolDetail(taskId); + return success(detailVO, data -> log.info("{}", data)); } catch (Exception ex) { - handleException(ex, e -> log.error("{}失败:param[{}]", msg, queryVO.getType(), e)); + handleException(ex, e -> log.error("{}失败:param[{}]", msg, taskId, e)); return failureWithMessage(QUERY_FAILURE); } } diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/LeaveNeedDoController.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/LeaveNeedDoController.java new file mode 100644 index 0000000..045dac1 --- /dev/null +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/app/LeaveNeedDoController.java @@ -0,0 +1,75 @@ +package cn.fw.valhalla.controller.app; + +import cn.fw.common.page.AppPage; +import cn.fw.common.web.auth.LoginAuthBean; +import cn.fw.common.web.auth.annotation.CurrentUser; +import cn.fw.data.base.domain.common.Message; +import cn.fw.security.auth.client.annotation.Authorization; +import cn.fw.security.auth.client.enums.AuthType; +import cn.fw.valhalla.domain.dto.LeaveAllocationDTO; +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum; +import cn.fw.valhalla.domain.query.LeaveQueryVO; +import cn.fw.valhalla.domain.vo.LeaveNeedDoVO; +import cn.fw.valhalla.service.bus.LeaveNeedDoBizService; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +import static cn.fw.common.web.util.ExceptionHandler.handleException; +import static cn.fw.common.web.util.ResultBuilder.failureWithMessage; +import static cn.fw.common.web.util.ResultBuilder.success; +import static cn.fw.valhalla.common.constant.MessageStr.QUERY_FAILURE; +import static cn.fw.valhalla.common.constant.MessageStr.SAVE_FAILURE; + +/** + * @author : kurisu + * @className : LeaveNeedDoController + * @description : 人员变动待处理事件 + * @date: 2020-08-15 14:52 + */ +@Slf4j +@RestController +@Authorization(AuthType.APP) +@Validated +@RequestMapping("/app/leave2do") +public class LeaveNeedDoController { + + private final LeaveNeedDoBizService leaveNeedDoBizService; + + @Autowired + public LeaveNeedDoController(final LeaveNeedDoBizService leaveNeedDoBizService) { + this.leaveNeedDoBizService = leaveNeedDoBizService; + } + + @GetMapping("/customer/list") + public Message> save(@CurrentUser LoginAuthBean currentUser, final LeaveQueryVO queryVO) { + final String msg = "保有客档案待分配人员列表[app/leave2do/customer/list]"; + try { + queryVO.setType(LeaveTodoTypeEnum.CUSTOMER.getValue()); + log.info("{}: param[{}]", msg, queryVO); + return success(leaveNeedDoBizService.getList(currentUser, queryVO), + data -> log.info("dataSize: {}", CollectionUtils.isEmpty(data.getData()) ? 0 : data.getData().size())); + } catch (Exception ex) { + handleException(ex, e -> log.error("{}失败: param[{}]", msg, queryVO, e)); + return failureWithMessage(QUERY_FAILURE); + } + } + + + @PostMapping("/customer/allocation") + public Message allocation(@CurrentUser LoginAuthBean currentUser, @RequestBody @Valid LeaveAllocationDTO dto) { + final String msg = "保有客档案分配[app/leave2do/customer/allocation]"; + try { + log.info("{}: param[{}]", msg, dto); + leaveNeedDoBizService.allocation(currentUser, dto); + return success(); + } catch (Exception ex) { + handleException(ex, e -> log.error("{}失败: param[{}]", msg, dto, e)); + return failureWithMessage(SAVE_FAILURE); + } + } +} diff --git a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/FollowTaskDealTask.java b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/FollowTaskDealTask.java index 72d9fea..80a6ad7 100644 --- a/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/FollowTaskDealTask.java +++ b/fw-valhalla-server/src/main/java/cn/fw/valhalla/controller/task/FollowTaskDealTask.java @@ -2,16 +2,18 @@ package cn.fw.valhalla.controller.task; import cn.fw.valhalla.common.utils.DateUtil; import cn.fw.valhalla.domain.db.follow.FollowTask; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; import cn.fw.valhalla.service.bus.cust.CustomerBizService; import cn.fw.valhalla.service.bus.cust.CustomerChangeBizService; import cn.fw.valhalla.service.bus.follow.FollowBizService; import cn.fw.valhalla.service.data.FollowTaskService; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.scheduling.annotation.Async; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -21,6 +23,8 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Objects; +import static cn.fw.valhalla.common.utils.DateUtil.getNowExpiredDay; + /** * @author : kurisu * @className : FollowTask @@ -34,16 +38,19 @@ public class FollowTaskDealTask { private final FollowBizService followBizService; private final CustomerChangeBizService customerChangeBizService; private final CustomerBizService customerBizService; + private final ApplicationEventPublisher eventPublisher; @Autowired public FollowTaskDealTask(final FollowTaskService followTaskService, final FollowBizService followBizService, final CustomerChangeBizService customerChangeBizService, - final CustomerBizService customerBizService) { + final CustomerBizService customerBizService, + final ApplicationEventPublisher eventPublisher) { this.followTaskService = followTaskService; this.followBizService = followBizService; this.customerChangeBizService = customerChangeBizService; this.customerBizService = customerBizService; + this.eventPublisher = eventPublisher; } /** @@ -54,6 +61,7 @@ public class FollowTaskDealTask { public void startTask() { List list = followTaskService.list(Wrappers.lambdaQuery() .eq(FollowTask::getState, TaskStateEnum.WAITING) + .ge(FollowTask::getBeginTime, DateUtil.startDate(getNowExpiredDay(-7))) .le(FollowTask::getBeginTime, DateUtil.localDateTime2Date(LocalDateTime.now())) .eq(FollowTask::getFinished, Boolean.FALSE) .last("limit 0, 500") @@ -85,10 +93,12 @@ public class FollowTaskDealTask { if (CollectionUtils.isEmpty(list)) { return; } - list.forEach(r -> { + for (FollowTask r : list) { r.setState(TaskStateEnum.END); customerBizService.abandon(r); - }); + CancelApproveEvent event = new CancelApproveEvent(r.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); + } followTaskService.updateBatchById(list); } @@ -110,9 +120,9 @@ public class FollowTaskDealTask { } list.forEach(task -> { if (FollowTypeEnum.IR.equals(task.getType())) { - customerChangeBizService.changeInsFollowUser(task); + customerChangeBizService.changeInsFollowUser(task, true); } else { - customerChangeBizService.changeFollowUser(task); + customerChangeBizService.changeFollowUser(task, true); } }); } diff --git a/fw-valhalla-server/src/main/resources/application-gray.yml b/fw-valhalla-server/src/main/resources/application-gray.yml index a2dd804..360ee0f 100644 --- a/fw-valhalla-server/src/main/resources/application-gray.yml +++ b/fw-valhalla-server/src/main/resources/application-gray.yml @@ -51,3 +51,4 @@ follow: RMCode: 'Zb33mjtjVy' IRCode: 'RsavIrkhZm' ACCode: 'gWPMkrjkjH' + leave2do: 'uF08Vd38fi' diff --git a/fw-valhalla-server/src/main/resources/application-prd.yml b/fw-valhalla-server/src/main/resources/application-prd.yml index 94cbddc..3b534b0 100644 --- a/fw-valhalla-server/src/main/resources/application-prd.yml +++ b/fw-valhalla-server/src/main/resources/application-prd.yml @@ -50,3 +50,4 @@ follow: RMCode: 'Zb33mjtjVy' IRCode: 'RsavIrkhZm' ACCode: 'gWPMkrjkjH' + leave2do: 'uF08Vd38fi' diff --git a/fw-valhalla-server/src/main/resources/application-test.yml b/fw-valhalla-server/src/main/resources/application-test.yml index 2fa3964..d65866e 100644 --- a/fw-valhalla-server/src/main/resources/application-test.yml +++ b/fw-valhalla-server/src/main/resources/application-test.yml @@ -53,4 +53,5 @@ follow: FMCode: '50rmamxGp7' RMCode: 'Zb33mjtjVy' IRCode: 'RsavIrkhZm' - ACCode: 'gWPMkrjkjH' \ No newline at end of file + ACCode: 'gWPMkrjkjH' + leave2do: 'kLKIpyNNQf' \ No newline at end of file diff --git a/fw-valhalla-server/src/main/resources/application.yml b/fw-valhalla-server/src/main/resources/application.yml index 8725714..cff44f7 100644 --- a/fw-valhalla-server/src/main/resources/application.yml +++ b/fw-valhalla-server/src/main/resources/application.yml @@ -127,3 +127,4 @@ follow: RMCode: 'Zb33mjtjVy' IRCode: 'RsavIrkhZm' ACCode: 'gWPMkrjkjH' + leave2do: 'kLKIpyNNQf' diff --git a/fw-valhalla-server/src/test/java/cn/fw/valhalla/ValhallaAppTests.java b/fw-valhalla-server/src/test/java/cn/fw/valhalla/ValhallaAppTests.java index 1191176..114550a 100644 --- a/fw-valhalla-server/src/test/java/cn/fw/valhalla/ValhallaAppTests.java +++ b/fw-valhalla-server/src/test/java/cn/fw/valhalla/ValhallaAppTests.java @@ -27,9 +27,11 @@ class ValhallaAppTests { @Test public void exampleTest() throws Exception { - this.mvc.perform(get("/test/todo").header("Authorization", "9E6864D1C56A0A6090AEFECF477A8519B407D23ECDC0763C4AD3F5D069B8DEB30025FC54917666CD0639489E2AB7D3C2")) + this.mvc.perform( + get("/app/accident/demo") + .header("Authorization", "4B70342B7CC9709C7D76A982217570ADB407D23ECDC0763C4AD3F5D069B8DEB33C5FCE9E493D9F6DE05D532E7A8B5DD1") + .param("val", "12345")) .andExpect(status().isOk()) - .andExpect(content().string("ok")) .andDo(MockMvcResultHandlers.print()); } diff --git a/fw-valhalla-server/src/test/java/cn/fw/valhalla/demo.lua b/fw-valhalla-server/src/test/java/cn/fw/valhalla/demo.lua new file mode 100644 index 0000000..7792a5a --- /dev/null +++ b/fw-valhalla-server/src/test/java/cn/fw/valhalla/demo.lua @@ -0,0 +1,21 @@ +-- +-- Created by IntelliJ IDEA. +-- User: kurisu +-- Date: 2020/10/10 +-- Time: 16:53 +-- To change this template use File | Settings | File Templates. + +-- 解锁 + if redis.call('get',KEYS[1]) == ARGV[1] then + return redis.call('del',KEYS[1]) == 1 + else + return false + end + + +-- 设置锁 + if redis.call('exists',KEYS[1]) == 1 then + return redis.call('get',KEYS[1]) + else + return redis.call('set',KEYS[1], ARGV[1]) + end \ No newline at end of file diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CommonService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CommonService.java new file mode 100644 index 0000000..2367dd3 --- /dev/null +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CommonService.java @@ -0,0 +1,52 @@ +package cn.fw.valhalla.service.bus; + +import cn.fw.valhalla.common.constant.RoleCode; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; +import cn.fw.valhalla.domain.vo.PostUserVO; +import cn.fw.valhalla.rpc.erp.UserService; +import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static cn.fw.common.businessvalidator.Validator.BV; + +/** + * @author : kurisu + * @className : CommonService + * @description : 公共服务 + * @date: 2020-10-22 11:07 + */ +@Service +@Slf4j +public class CommonService { + private final UserService userService; + + @Autowired + public CommonService(final UserService userService) { + this.userService = userService; + } + + public List getUsers(final Long shopId, final Integer type) { + FollowTypeEnum typeEnum = FollowTypeEnum.ofValue(type); + BV.notNull(typeEnum, () -> "跟进类型错误"); + List userByRole = userService.getUserByRole(shopId, getRoleCode(typeEnum)); + return userByRole.stream().map(user -> new PostUserVO(user.getUserId(), user.getUserName())).collect(Collectors.toList()); + } + + private String getRoleCode(FollowTypeEnum followTypeEnum) { + switch (followTypeEnum) { + case AC: + return RoleCode.SGCGJ; + case IR: + return RoleCode.XBGJ; + case FM: + case RM: + default: + return RoleCode.FWGW; + } + } +} diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CustomEventListener.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CustomEventListener.java index 786f7f9..fe13238 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CustomEventListener.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/CustomEventListener.java @@ -1,14 +1,17 @@ package cn.fw.valhalla.service.bus; +import cn.fw.valhalla.domain.db.ApproveRecord; import cn.fw.valhalla.domain.db.follow.FollowTask; +import cn.fw.valhalla.domain.enums.ApproveStateEnum; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.vo.setting.SettingVO; +import cn.fw.valhalla.rpc.flow.FlowApproveRpc; import cn.fw.valhalla.service.bus.follow.FollowBizService; import cn.fw.valhalla.service.bus.setting.SettingBizService; -import cn.fw.valhalla.service.event.PublicPoolEvent; -import cn.fw.valhalla.service.event.SettingChangeEvent; -import cn.fw.valhalla.service.event.StopTaskEvent; -import cn.fw.valhalla.service.event.TaskCancelEvent; +import cn.fw.valhalla.service.data.ApproveRecordService; +import cn.fw.valhalla.service.event.*; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; @@ -29,12 +32,18 @@ import java.util.Optional; public class CustomEventListener { private final SettingBizService settingBizService; private final FollowBizService followBizService; + private final ApproveRecordService approveRecordService; + private final FlowApproveRpc flowApproveRpc; @Autowired public CustomEventListener(final SettingBizService settingBizService, - final FollowBizService followBizService) { + final FollowBizService followBizService, + final ApproveRecordService approveRecordService, + final FlowApproveRpc flowApproveRpc) { this.settingBizService = settingBizService; this.followBizService = followBizService; + this.approveRecordService = approveRecordService; + this.flowApproveRpc = flowApproveRpc; } /** @@ -83,4 +92,27 @@ public class CustomEventListener { FollowTask task = event.getTask(); followBizService.stopTask(task); } + + /** + * 取消审批 + * @param event + */ + @EventListener(CancelApproveEvent.class) + public void cancelApprove(final CancelApproveEvent event) { + Long taskId = event.getTaskId(); + ApproveTypeEnum typeEnum = event.getTypeEnum(); + ApproveRecord approveRecord = approveRecordService.getOne(Wrappers.lambdaQuery() + .eq(ApproveRecord::getDataId, taskId) + .eq(ApproveRecord::getType, typeEnum) + .eq(ApproveRecord::getState, ApproveStateEnum.WAIT) + .last("limit 1") + ); + if (Objects.isNull(approveRecord)) { + return; + } + //FIXME 优化项 处理审批取消失败的场景 + boolean canceled = flowApproveRpc.cancel(approveRecord.getOrderNo()); + approveRecord.setState(ApproveStateEnum.CANCELED); + approveRecordService.updateById(approveRecord); + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java new file mode 100644 index 0000000..858f97c --- /dev/null +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/LeaveNeedDoBizService.java @@ -0,0 +1,459 @@ +package cn.fw.valhalla.service.bus; + +import cn.fw.common.cache.locker.DistributedLocker; +import cn.fw.common.data.mybatis.pagination.PageData; +import cn.fw.common.page.AppPage; +import cn.fw.common.web.auth.LoginAuthBean; +import cn.fw.data.base.domain.common.Message; +import cn.fw.third.push.sdk.api.ImSendMessage; +import cn.fw.third.push.sdk.api.para.im.MsgPara; +import cn.fw.valhalla.common.constant.RoleCode; +import cn.fw.valhalla.common.enums.AllocationTypeEnum; +import cn.fw.valhalla.common.utils.DateUtil; +import cn.fw.valhalla.domain.db.LeaveNeedDo; +import cn.fw.valhalla.domain.db.customer.Customer; +import cn.fw.valhalla.domain.db.follow.FollowRecord; +import cn.fw.valhalla.domain.db.follow.FollowTask; +import cn.fw.valhalla.domain.dto.LeaveAllocationDTO; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; +import cn.fw.valhalla.domain.enums.LeaveReasonEnum; +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum; +import cn.fw.valhalla.domain.enums.TaskStateEnum; +import cn.fw.valhalla.domain.query.LeaveQueryVO; +import cn.fw.valhalla.domain.vo.LeaveNeedDoVO; +import cn.fw.valhalla.rpc.erp.TodoRpcService; +import cn.fw.valhalla.rpc.erp.UserService; +import cn.fw.valhalla.rpc.erp.dto.BackLogItemDTO; +import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; +import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO; +import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; +import cn.fw.valhalla.service.data.CustomerService; +import cn.fw.valhalla.service.data.FollowRecordService; +import cn.fw.valhalla.service.data.FollowTaskService; +import cn.fw.valhalla.service.data.LeaveNeedDoService; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; +import org.redisson.api.RLock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.BoundListOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static cn.fw.common.businessvalidator.Validator.BV; + +/** + * @author : kurisu + * @className : LeaveNeedDoBizService + * @description : 人员变动处理 + * @date: 2020-10-16 17:04 + */ +@Service +@Slf4j +public class LeaveNeedDoBizService { + private final LeaveNeedDoService leaveNeedDoService; + private final CustomerService customerService; + private final UserService userService; + private final FollowTaskService followTaskService; + private final FollowRecordService followRecordService; + private final DistributedLocker distributedLocker; + private final ImSendMessage imSendMessage; + private final TodoRpcService todoRpcService; + /** + * Redis工具 + */ + private final StringRedisTemplate redisTemplate; + + @Value("${spring.cache.custom.global-prefix}:LeaveNeedDo") + @Getter + private String keyPrefix; + + @Value("${follow.todo.leave2do}") + @Getter + private String leave2doCode; + + @Autowired + public LeaveNeedDoBizService(final LeaveNeedDoService leaveNeedDoService, + final CustomerService customerService, + final UserService userService, + final FollowTaskService followTaskService, + final FollowRecordService followRecordService, + final DistributedLocker distributedLocker, + final ImSendMessage imSendMessage, + final TodoRpcService todoRpcService, + final StringRedisTemplate redisTemplate) { + this.leaveNeedDoService = leaveNeedDoService; + this.customerService = customerService; + this.userService = userService; + this.followTaskService = followTaskService; + this.followRecordService = followRecordService; + this.distributedLocker = distributedLocker; + this.imSendMessage = imSendMessage; + this.todoRpcService = todoRpcService; + this.redisTemplate = redisTemplate; + } + + + @Transactional(rollbackFor = Exception.class) + public void add(final Long userId, final Long shopId) { + String lockKey = String.format("%s:add:lock:%s:%s", getKeyPrefix(), shopId, userId); + Pair pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 30); + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交"); + try { + List postUserDTOS = userService.getUserByRole(shopId, RoleCode.BYKFP); + BV.isFalse(CollectionUtils.isEmpty(postUserDTOS), () -> "该门店没有配置保有客分配人员"); + LeaveNeedDo db = addable(userId, shopId); + leaveNeedDoService.save(db); + push2Todo(db.getId(), postUserDTOS.get(0).getUserId()); + } catch (Exception e) { + distributedLocker.unlock(lockKey); + throw e; + } + } + + public AppPage getList(LoginAuthBean currentUser, LeaveQueryVO queryVO) { + List dataRange = userService.getUserRoleDataRange(currentUser.getUserId(), RoleCode.BYKFP); + List shopIds = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList()); + BV.isFalse(CollectionUtils.isEmpty(shopIds), () -> "无权限操作,请检查角色权限是否正确"); + PageData pageData = leaveNeedDoService.page(new PageData<>(queryVO), Wrappers.lambdaQuery() + .in(LeaveNeedDo::getShopId, shopIds) + .eq(LeaveNeedDo::getDone, Boolean.FALSE) + .eq(Objects.nonNull(queryVO.getType()), LeaveNeedDo::getType, queryVO.getType()) + ); + AppPage page = AppPage.empty(queryVO); + List list = new ArrayList<>(); + List records = Optional.ofNullable(pageData.getRecords()).orElse(new ArrayList<>()); + for (LeaveNeedDo needDo : records) { + int i = customerService.count(Wrappers.lambdaQuery() + .eq(Customer::getAdviserId, needDo.getUserId()) + .eq(Customer::getYn, Boolean.TRUE) + ); + list.add(LeaveNeedDoVO.with(needDo, i)); + } + page.setData(list); + return page; + } + + @Transactional(rollbackFor = Exception.class) + public void allocation(LoginAuthBean user, LeaveAllocationDTO dto) { + final String key = generateKey(dto.getId()); + final String lockKey = getLockKey(dto.getId()); + Pair pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 30); + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交"); + try { + //准备分配 常规校验 + prepareAllocation(dto); + //变更档案 + List customerList = doAllocation(dto, key); + //分配跟进任务 + dealFollowTask(customerList); + //完成分配发送消息提醒等 + finish(user.getUserName(), dto.getId(), key); + } catch (Exception e) { + clearKey(key); + distributedLocker.unlock(lockKey); + throw e; + } + } + + private void prepareAllocation(LeaveAllocationDTO dto) { + AllocationTypeEnum typeEnum = AllocationTypeEnum.ofValue(dto.getAllocationType()); + BV.notNull(typeEnum, () -> "分配方式不正确,请重试"); + dto.setType(typeEnum); + LeaveNeedDo needDo = leaveNeedDoService.queryProcessableById(dto.getId()); + BV.notNull(needDo, () -> "该条记录已处理或不存在,请刷新后重试"); + dto.setAdviserId(needDo.getUserId()); + if (AllocationTypeEnum.ONE.equals(typeEnum)) { + BV.notNull(dto.getUserId(), () -> "指定人员不能为空"); + List dataRange = userService.getUserRoleDataRange(dto.getUserId(), RoleCode.FWGW); + List shopIdList = dataRange.stream().map(UserRoleDataRangeDTO::getRangeValue).collect(Collectors.toList()); + BV.isNotEmpty(shopIdList, () -> "指定人员非服务顾问角色,请核对"); + Long shopId = shopIdList.get(0); + BV.isTrue(needDo.getShopId().equals(shopId), () -> "指定人员所属门店与档案归属门店不符"); + dto.setShopId(shopId); + } + + if (AllocationTypeEnum.ALL.equals(dto.getType())) { + dto.setShopId(needDo.getShopId()); + } + } + + /** + * 处理数据 + * + * @param dto + * @return 处理完的档案 + */ + private List doAllocation(LeaveAllocationDTO dto, String key) { + List customerList = customerService.queryByAdviserId(dto.getAdviserId()); + if (CollectionUtils.isEmpty(customerList)) { + return null; + } + if (AllocationTypeEnum.ONE.equals(dto.getType())) { + allocation(key, customerList, dto); + } + if (AllocationTypeEnum.ALL.equals(dto.getType())) { + allocation(key, customerList, dto.getShopId()); + } + return customerList; + } + + /** + * 分配给指定人员 + * + * @param list + * @param dto + */ + private void allocation(String key, List list, LeaveAllocationDTO dto) { + for (Customer customer : list) { + customer.setShopId(dto.getShopId()); + customer.setAdviserId(dto.getUserId()); + } + customerService.updateBatchById(list); + setToCache(key, new UserInfo(dto.getUserId(), "", list.size())); + } + + /** + * 门店内平均分配 + * + * @param list + * @param shopId + */ + private void allocation(String key, List list, Long shopId) { + List users = userService.getUserByRole(shopId, RoleCode.FWGW); + BV.isNotEmpty(users, () -> "该门店没有服务顾问,请检查配置是否正确"); + LinkedList queue = new LinkedList<>(); + for (PostUserDTO user : users) { + queue.offer(new UserInfo(user.getUserId(), user.getUserName())); + } + for (Customer customer : list) { + UserInfo info = queue.poll(); + customer.setShopId(shopId); + customer.setAdviserId(Objects.requireNonNull(info, "服务顾问信息获取异常,请重试").getUserId()); + info.setCount(info.getCount() + 1); + queue.offer(info); + } + customerService.updateBatchById(list); + setToCache(key, queue); + } + + /** + * 完成分配的后续处理逻辑 + * + * @param list + */ + private void dealFollowTask(List list) { + List enumList = Arrays.asList(FollowTypeEnum.FM, FollowTypeEnum.RM); + if (!CollectionUtils.isEmpty(list)) { + //处理待办等信息 + for (Customer customer : list) { + final Long customerId = customer.getId(); + final Long shopId = customer.getShopId(); + final Long adviserId = customer.getAdviserId(); + List taskList = followTaskService.getListByCustomerId(customerId, enumList); + taskList.forEach(task -> { + task.setFollowUser(adviserId); + task.setFollowShop(shopId); + if (TaskStateEnum.WAITING.equals(task.getState())) { + task.setOriginUser(adviserId); + task.setOriginShop(shopId); + } else { + task.setChanged(Boolean.TRUE); + } + }); + List recordList = followRecordService.getRecordListByCustomer(customerId, enumList); + recordList.forEach(record -> { + record.setUserId(adviserId); + record.setShopId(shopId); + }); + if (taskList.size() > 0) { + followTaskService.updateBatchById(taskList); + } + if (recordList.size() > 0) { + followRecordService.updateBatchById(recordList); + } + } + } + } + + private void finish(String userName, Long leaveId, String key) { + leaveNeedDoService.dealById(leaveId); + List list = getAllFromCache(key); + for (UserInfo info : list) { + try { + String text = String.format("%s通过资源分配给你%s台保有客", userName, info.getCount()); + final MsgPara msgPara = MsgPara.getOfflineTxetPara(text, null, "保有客分配", + "保有客分配", null, info.getUserId()).build(); + final Message msg = imSendMessage.sendMsg(msgPara); + log.info("给[{}]推送im消息结果:[{}]", info, msg.getResult()); + } catch (Exception e) { + log.error("给[{}]推送im消息失败:]", info, e); + } + } + clearKey(key); + BackLogItemDTO backLogItemDTO = new BackLogItemDTO(null, getLeave2doCode(), String.valueOf(leaveId), new Date()); + todoRpcService.complete(backLogItemDTO); + } + + private String getLockKey(final Long leaveId) { + BV.notNull(leaveId, "leaveId cannot be null"); + + return String.format("%s:lock:%s", getKeyPrefix(), leaveId); + } + + private String generateKey(final Long leaveId) { + Assert.notNull(leaveId, "leaveId cannot be null"); + + return String.format("%s:allocation:%s", getKeyPrefix(), leaveId); + } + + public List getAllFromCache(final String key) { + try { + Boolean hasKey = redisTemplate.hasKey(key); + if (!Boolean.TRUE.equals(hasKey)) { + return new ArrayList<>(); + } + BoundListOperations ops = redisTemplate.boundListOps(key); + List stringList = ops.range(0, -1); + if (CollectionUtils.isEmpty(stringList)) { + return new ArrayList<>(); + } + List dtos = stringList.stream().map(str -> JSONObject.parseObject(str, UserInfo.class)).collect(Collectors.toList()); + redisTemplate.delete(key); + return dtos; + } catch (Exception e) { + log.error("缓存设置信息失败 key[{}]", key, e); + return new ArrayList<>(); + } + } + + private void setToCache(final String key, final UserInfo userInfo) { + try { + BoundListOperations ops = redisTemplate.boundListOps(key); + String jsonString = JSONObject.toJSONString(userInfo); + ops.rightPush(jsonString); + } catch (Exception e) { + log.error("缓存设置信息失败 key[{}]", key, e); + } + } + + private void setToCache(final String key, final LinkedList userInfos) { + try { + if (CollectionUtils.isEmpty(userInfos)) { + return; + } + BoundListOperations ops = redisTemplate.boundListOps(key); + String[] users = userInfos.stream().map(JSONObject::toJSONString).toArray(String[]::new); + ops.rightPushAll(users); + } catch (Exception e) { + log.error("缓存设置信息失败 key[{}]", key, e); + } + } + + private void clearKey(final String key) { + try { + redisTemplate.delete(key); + } catch (Exception e) { + log.error("清空缓存信息失败 key[{}]", key, e); + } + } + + private LeaveNeedDo addable(final Long userId, final Long shopId) { + List dataRange = userService.getUserRoleDataRange(userId, RoleCode.FWGW); + boolean ok = CollectionUtils.isEmpty(dataRange) || !Objects.equals(dataRange.get(0).getRangeValue(), shopId); + BV.isTrue(ok, () -> "请先移除对对应服务站服务顾问角色后操作"); + int count = leaveNeedDoService.count(Wrappers.lambdaQuery() + .eq(LeaveNeedDo::getUserId, userId) + .eq(LeaveNeedDo::getShopId, shopId) + .eq(LeaveNeedDo::getDone, Boolean.FALSE) + ); + BV.isTrue(count == 0, () -> "已存在待分配记录,请勿重复添加"); + UserInfoDTO user = userService.user(userId); + BV.notNull(user, () -> "用户不存在"); + boolean bool = customerService.count(Wrappers.lambdaQuery() + .eq(Customer::getAdviserId, userId) + .eq(Customer::getShopId, shopId) + .eq(Customer::getYn, Boolean.TRUE) + ) > 0; + BV.isTrue(bool, () -> "该顾问没有可用档案无需分配保有客"); + LeaveNeedDo db = new LeaveNeedDo(); + db.setDone(Boolean.FALSE); + db.setEffectiveTime(DateUtil.getMonthEndDay(new Date())); + db.setReason(LeaveReasonEnum.OTHER); + db.setType(LeaveTodoTypeEnum.CUSTOMER); + db.setShopId(shopId); + db.setUserId(userId); + db.setUserName(user.getUserName()); + db.setCreateTime(new Date()); + db.setUpdateTime(new Date()); + return db; + } + + private void push2Todo(Long id, Long userId) { + BackLogItemDTO dto = new BackLogItemDTO(userId, getLeave2doCode(), String.valueOf(id), new Date()); + todoRpcService.push(dto); + } + + static class UserInfo { + private Long userId; + private String userName; + private int count; + + public UserInfo() { + } + + public UserInfo(Long userId, String userName) { + this.userId = userId; + this.userName = userName; + } + + public UserInfo(Long userId, String userName, int count) { + this.userId = userId; + this.userName = userName; + this.count = count; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + @Override + public String toString() { + return "UserInfo{" + + "userId=" + userId + + ", userName='" + userName + '\'' + + ", count=" + count + + '}'; + } + } +} diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AccidentPoolBizService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AccidentPoolBizService.java index efbde71..1874014 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AccidentPoolBizService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/AccidentPoolBizService.java @@ -82,12 +82,14 @@ public class AccidentPoolBizService { public void add2Pool(LoginAuthBean currentUser, AccidentPoolDTO poolDTO) { final String lockKey = getLockKey(poolDTO.getPlateNo(), currentUser.getGroupId()); Pair pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15); + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交"); try { BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交"); boolean repetition = isRepetition(currentUser.getGroupId(), poolDTO.getPlateNo()); BV.isFalse(repetition, () -> "该记录已存在,请勿重复添加"); AccidentPool pool = conversion2db(poolDTO, currentUser); pool.setShopId(poolDTO.getShopId()); + pool.setShopName(poolDTO.getName()); accidentPoolService.save(pool); createAccPoolTask(pool); } catch (Exception e) { @@ -141,7 +143,6 @@ public class AccidentPoolBizService { private AccidentPool conversion2db(AccidentPoolDTO dto, LoginAuthBean currentUser) { AccidentPool pool = new AccidentPool(); BeanUtils.copyProperties(dto, pool); - pool.setUserId(currentUser.getUserId()); pool.setCreateTime(new Date()); pool.setUpdateTime(new Date()); pool.setGroupId(currentUser.getGroupId()); diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerChangeBizService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerChangeBizService.java index 375b6fd..7f43c7f 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerChangeBizService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/cust/CustomerChangeBizService.java @@ -20,9 +20,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.CustomerChangeDto; import cn.fw.valhalla.domain.dto.CustomerDetailDto; -import cn.fw.valhalla.domain.enums.CustomerChangeTypeEnum; -import cn.fw.valhalla.domain.enums.DefeatReasonEnum; -import cn.fw.valhalla.domain.enums.TaskStateEnum; +import cn.fw.valhalla.domain.enums.*; import cn.fw.valhalla.domain.vo.customer.CustomerChangeInfoVO; import cn.fw.valhalla.domain.vo.customer.CustomerChangeQrCodeVO; import cn.fw.valhalla.rpc.angel.dto.InsuranceDTO; @@ -39,11 +37,13 @@ import cn.fw.valhalla.service.data.AffiliationRecordService; import cn.fw.valhalla.service.data.FollowRecordService; import cn.fw.valhalla.service.data.FollowTaskService; import cn.fw.valhalla.service.data.PublicPoolService; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -74,6 +74,7 @@ public class CustomerChangeBizService extends AbstractCustomerService { private final FollowRecordService followRecordService; private final AffiliationRecordService affiliationRecordService; private final PublicPoolService publicPoolService; + private final ApplicationEventPublisher eventPublisher; @Autowired @@ -83,7 +84,8 @@ public class CustomerChangeBizService extends AbstractCustomerService { final FollowTaskService followTaskService, final FollowRecordService followRecordService, final AffiliationRecordService affiliationRecordService, - final PublicPoolService publicPoolService) { + final PublicPoolService publicPoolService, + final ApplicationEventPublisher eventPublisher) { this.redisUtil = redisUtil; this.passportService = passportService; this.memberRpcService = memberRpcService; @@ -91,6 +93,7 @@ public class CustomerChangeBizService extends AbstractCustomerService { this.followRecordService = followRecordService; this.affiliationRecordService = affiliationRecordService; this.publicPoolService = publicPoolService; + this.eventPublisher = eventPublisher; } /** @@ -290,7 +293,7 @@ public class CustomerChangeBizService extends AbstractCustomerService { return true; } Long adviserId = changeAdviserReq.getAdviserId(); - if (changeAdviserReq.getAdviserId().equals(customer.getAdviserId())) { + if (changeAdviserReq.getAdviserId().equals(customer.getAdviserId())) { return true; } List dataRange = userService.getUserRoleDataRange(adviserId, RoleCode.FWGW); @@ -363,6 +366,15 @@ public class CustomerChangeBizService extends AbstractCustomerService { } } + @Transactional(rollbackFor = Exception.class) + public void changeFollowUser(FollowTask task, boolean needCancelApprove) { + changeFollowUser(task); + if (needCancelApprove) { + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); + } + } + /** * 更换跟进人 @@ -429,6 +441,15 @@ public class CustomerChangeBizService extends AbstractCustomerService { } } + @Transactional(rollbackFor = Exception.class) + public void changeInsFollowUser(FollowTask task, boolean needCancelApprove) { + changeInsFollowUser(task); + if (needCancelApprove) { + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); + } + } + /** * 修改档案 @@ -543,7 +564,8 @@ public class CustomerChangeBizService extends AbstractCustomerService { } private void changeFirstFollower(Long customerId, Long follower, Long shopId) { - List list = followTaskService.getWaitListByCustomerId(customerId); + List enumList = Arrays.asList(FollowTypeEnum.FM, FollowTypeEnum.RM); + List list = followTaskService.getWaitListByCustomerId(customerId, enumList); if (CollectionUtils.isEmpty(list)) { return; } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowBizService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowBizService.java index 2f4929b..1143ed3 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowBizService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowBizService.java @@ -1,5 +1,6 @@ package cn.fw.valhalla.service.bus.follow; +import cn.fw.common.cache.locker.DistributedLocker; import cn.fw.common.page.AppPage; import cn.fw.common.web.auth.LoginAuthBean; import cn.fw.valhalla.common.utils.DateUtil; @@ -9,6 +10,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.FollowAttachmentDTO; import cn.fw.valhalla.domain.enums.ApproveStateEnum; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; import cn.fw.valhalla.domain.query.FollowQueryVO; @@ -29,6 +31,8 @@ import cn.fw.valhalla.service.event.TaskCancelEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; +import org.redisson.api.RLock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -38,6 +42,7 @@ import org.springframework.util.CollectionUtils; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static cn.fw.common.businessvalidator.Validator.BV; @@ -60,24 +65,31 @@ public class FollowBizService { private final FollowTaskService followTaskService; private final FollowRecordService followRecordService; private final UserService userService; + private final DistributedLocker distributedLocker; @Value("${follow.flowNo}") @Getter private String flowNo; + @Value("${spring.cache.custom.global-prefix}:defeat") + @Getter + private String keyPrefix; + @Autowired public FollowBizService(final List followStrategyList, final FlowApproveRpc flowApproveRpc, final ApproveRecordService approveRecordService, final FollowTaskService followTaskService, final FollowRecordService followRecordService, - final UserService userService) { + final UserService userService, + final DistributedLocker distributedLocker) { this.followMap = followStrategyList.stream().collect(Collectors.toMap(FollowStrategy::getFollowType, v -> v)); this.flowApproveRpc = flowApproveRpc; this.approveRecordService = approveRecordService; this.followTaskService = followTaskService; this.followRecordService = followRecordService; this.userService = userService; + this.distributedLocker = distributedLocker; } /** @@ -126,6 +138,20 @@ public class FollowBizService { } /** + * 查询跟进池详情 + * + * @param taskId + * @return + */ + public FollowDetailVO followPoolDetail(Long taskId) { + FollowTask task = followTaskService.getById(taskId); + BV.notNull(task, () -> "跟进线索不存在,请刷新列表"); + FollowStrategy strategy = followMap.get(task.getType()); + Assert.notNull(strategy, "strategy cannot be null"); + return strategy.followPoolDetail(task); + } + + /** * 完成跟进 * * @param id @@ -173,28 +199,54 @@ public class FollowBizService { */ @Transactional(rollbackFor = Exception.class) public void defeat(LoginAuthBean currentUser, String reason, Long recordId) { - FollowRecord record = followRecordService.getById(recordId); - BV.notNull(record, () -> "跟进记录不存在"); - FollowTask task = followTaskService.getById(record.getTaskId()); - BV.notNull(task, () -> "跟进信息不存在"); - FlowDto flowDto = FlowDto.create(currentUser.getGroupId(), getFlowNo(), currentUser.getUserId(), currentUser.getUserName(), task.getFollowShop()); - HashMap param = new HashMap<>(2); - param.put("recordId", recordId.toString()); - param.put("type", task.getType().getValue().toString()); - flowDto.setParam(param); - List list = Collections.singletonList("跟进类型: " + task.getType().getName()); - flowDto.setBriefContentList(list); - String orderNo = flowApproveRpc.initiate(flowDto); - ApproveRecord approveRecord = new ApproveRecord(); - approveRecord.setDataId(task.getId()); - approveRecord.setUserId(currentUser.getUserId()); - approveRecord.setOrderNo(orderNo); - approveRecord.setReason(reason); - approveRecord.setState(ApproveStateEnum.WAIT); - approveRecord.setPassed(Boolean.FALSE); - approveRecord.setCreateTime(DateUtil.localDateTime2Date(LocalDateTime.now())); - approveRecord.setUpdateTime(DateUtil.localDateTime2Date(LocalDateTime.now())); - approveRecordService.save(approveRecord); + final String lockKey = getLockKey(recordId); + Pair pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15); + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), () -> "请勿重复提交"); + try { + FollowRecord record = followRecordService.getById(recordId); + BV.notNull(record, () -> "跟进记录不存在"); + FollowTask task = followTaskService.getById(record.getTaskId()); + BV.notNull(task, () -> "跟进信息不存在"); + boolean repetition = isRepetition(record.getTaskId().toString()); + BV.isFalse(repetition, () -> "正在审批处理中,请勿重复申请"); + FlowDto flowDto = FlowDto.create(currentUser.getGroupId(), getFlowNo(), currentUser.getUserId(), currentUser.getUserName(), task.getFollowShop()); + HashMap param = new HashMap<>(2); + param.put("recordId", recordId.toString()); + param.put("type", task.getType().getValue().toString()); + flowDto.setParam(param); + String name = ""; + String plate = ""; + FollowStrategy strategy = followMap.get(task.getType()); + Assert.notNull(strategy, "strategy cannot be null"); + FollowDetailVO vo = strategy.followPoolDetail(task); + if (Objects.nonNull(vo)) { + name = vo.getName(); + plate = vo.getPlateNo(); + } + List list = Arrays.asList( + "申请人: " + currentUser.getUserName(), + "客户: " + name, + "车辆: " + plate, + "跟进类型: " + task.getType().getName(), + "战败原因: " + reason + ); + flowDto.setBriefContentList(list); + String orderNo = flowApproveRpc.initiate(flowDto); + ApproveRecord approveRecord = new ApproveRecord(); + approveRecord.setDataId(task.getId()); + approveRecord.setUserId(currentUser.getUserId()); + approveRecord.setOrderNo(orderNo); + approveRecord.setReason(reason); + approveRecord.setState(ApproveStateEnum.WAIT); + approveRecord.setType(ApproveTypeEnum.FOLLOW_DEFEAT); + approveRecord.setPassed(Boolean.FALSE); + approveRecord.setCreateTime(DateUtil.localDateTime2Date(LocalDateTime.now())); + approveRecord.setUpdateTime(DateUtil.localDateTime2Date(LocalDateTime.now())); + approveRecordService.save(approveRecord); + } catch (Exception e) { + distributedLocker.unlock(lockKey); + throw e; + } } /** @@ -332,4 +384,24 @@ public class FollowBizService { return null; } } + + private String getLockKey(Long recordId) { + BV.notNull(recordId, "recordId cannot be null"); + + return String.format("%s:lock:%s", getKeyPrefix(), recordId); + } + + /** + * 审批防重 + * + * @param taskId + * @return + */ + private boolean isRepetition(String taskId) { + return approveRecordService.count(Wrappers.lambdaQuery() + .eq(ApproveRecord::getDataId, taskId) + .eq(ApproveRecord::getType, ApproveTypeEnum.FOLLOW_DEFEAT) + .eq(ApproveRecord::getState, ApproveStateEnum.WAIT) + ) > 0; + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowPoolBizService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowPoolBizService.java index 9577f9c..70a2e14 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowPoolBizService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/FollowPoolBizService.java @@ -2,23 +2,19 @@ package cn.fw.valhalla.service.bus.follow; import cn.fw.common.page.AppPage; import cn.fw.common.web.auth.LoginAuthBean; -import cn.fw.valhalla.common.constant.RoleCode; +import cn.fw.valhalla.common.enums.DefeatTypeEnum; import cn.fw.valhalla.common.utils.DateUtil; import cn.fw.valhalla.common.utils.StringUtils; import cn.fw.valhalla.domain.db.PublicPool; -import cn.fw.valhalla.domain.db.follow.FollowRecord; import cn.fw.valhalla.domain.dto.FollowPoolDTO; -import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; import cn.fw.valhalla.domain.query.FollowPoolQueryVO; import cn.fw.valhalla.domain.vo.customer.PublicPoolVO; import cn.fw.valhalla.domain.vo.follow.FollowPoolListVO; import cn.fw.valhalla.rpc.erp.UserService; import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO; -import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; import cn.fw.valhalla.rpc.oop.OopService; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; -import cn.fw.valhalla.service.data.FollowRecordService; import cn.fw.valhalla.service.data.FollowTaskService; import cn.fw.valhalla.service.data.PublicPoolService; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; @@ -29,11 +25,9 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import static cn.fw.common.businessvalidator.Validator.BV; @@ -47,70 +41,34 @@ import static cn.fw.common.businessvalidator.Validator.BV; @Service public class FollowPoolBizService { private final FollowTaskService followTaskService; - private final FollowRecordService followRecordService; private final PublicPoolService publicPoolService; private final OopService oopService; private final UserService userService; + private final static Integer MONTH_DAY = 31; @Autowired public FollowPoolBizService(final FollowTaskService followTaskService, - final FollowRecordService followRecordService, final PublicPoolService publicPoolService, final OopService oopService, final UserService userService) { this.followTaskService = followTaskService; - this.followRecordService = followRecordService; this.publicPoolService = publicPoolService; this.oopService = oopService; this.userService = userService; } /** - * 战败池 - * - * @param currentUser - * @param queryVO - * @return - */ - public AppPage defeatList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) { - if (CollectionUtils.isEmpty(queryVO.getShopList())) { - queryVO.setUserId(currentUser.getUserId()); - } - List list = followTaskService.defeatList(queryVO); - List defeatList = new ArrayList<>(); - for (FollowPoolDTO followPoolDTO : list) { - FollowPoolListVO vo1 = transform4Origin(followPoolDTO); - defeatList.add(vo1); - if (!FollowTypeEnum.AC.getValue().equals(followPoolDTO.getType())) { - FollowPoolListVO vo2 = transform4FinishUser(followPoolDTO); - if (Objects.nonNull(vo2)) { - defeatList.add(vo2); - } - } - } - AppPage page = AppPage.empty(queryVO); - page.setData(defeatList); - return page; - } - - /** * 跟进池 * - * @param currentUser * @param queryVO * @return */ - public AppPage followList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) { - if (CollectionUtils.isEmpty(queryVO.getShopList())) { - queryVO.setUserId(currentUser.getUserId()); - } + public AppPage followList(LoginAuthBean user, FollowPoolQueryVO queryVO) { + prepareParams(user, queryVO); List list = followTaskService.followList(queryVO); List followList = new ArrayList<>(); for (FollowPoolDTO followPoolDTO : list) { - FollowPoolListVO vo = trans2Pool(followPoolDTO, followPoolDTO.getFollowUser(), followPoolDTO.getFollowShop()); - vo.setRedistribution(Boolean.TRUE.equals(followPoolDTO.getChanged())); - Integer days = DateUtil.sub(followPoolDTO.getDeadline(), DateUtil.localDateTime2Date(LocalDateTime.now()), "d"); - vo.setRemaining(days); + FollowPoolListVO vo = trans2Pool(followPoolDTO); followList.add(vo); } AppPage page = AppPage.empty(queryVO); @@ -118,31 +76,6 @@ public class FollowPoolBizService { return page; } - - /** - * 成交池 - * - * @param currentUser - * @param queryVO - * @return - */ - public AppPage completeList(LoginAuthBean currentUser, FollowPoolQueryVO queryVO) { - if (CollectionUtils.isEmpty(queryVO.getShopList())) { - queryVO.setUserId(currentUser.getUserId()); - } - List list = followTaskService.completeList(queryVO); - List completeList = new ArrayList<>(); - for (FollowPoolDTO followPoolDTO : list) { - FollowPoolListVO vo = trans2Pool(followPoolDTO, followPoolDTO.getFinishUser(), followPoolDTO.getFinishShop()); - vo.setRedistribution(!followPoolDTO.getOriginUser().equals(followPoolDTO.getFinishUser())); - vo.setFinishTime(followPoolDTO.getFinishTime()); - completeList.add(vo); - } - AppPage page = AppPage.empty(queryVO); - page.setData(completeList); - return page; - } - /** * 公共池 * @@ -152,8 +85,7 @@ public class FollowPoolBizService { public AppPage publicList(FollowPoolQueryVO queryVO) { Page opage = new Page<>(queryVO.getCurrent(), queryVO.getPageSize()); opage = publicPoolService.page(opage, Wrappers.lambdaQuery() - .eq(StringUtils.isValid(queryVO.getKw()), PublicPool::getPlateNo, "%" + queryVO.getKw() + "%") - .in(CollectionUtils.isNotEmpty(queryVO.getShopList()), PublicPool::getShopId, queryVO.getShopList()) + .eq(StringUtils.isValid(queryVO.getPlateNo()), PublicPool::getPlateNo, "%" + queryVO.getPlateNo() + "%") .eq(Objects.nonNull(queryVO.getType()), PublicPool::getType, queryVO.getType()) .eq(Objects.nonNull(queryVO.getGroupId()), PublicPool::getGroupId, queryVO.getGroupId()) ); @@ -174,55 +106,52 @@ public class FollowPoolBizService { } - private FollowPoolListVO trans2Pool(FollowPoolDTO poolDTO, Long userId, Long shopId) { + private FollowPoolListVO trans2Pool(FollowPoolDTO poolDTO) { FollowPoolListVO vo = new FollowPoolListVO(); - vo.setPlateNo(poolDTO.getPlateNo()); - vo.setType(poolDTO.getType()); - UserInfoDTO user = userService.user(userId); + BeanUtils.copyProperties(poolDTO, vo); + UserInfoDTO user = userService.user(poolDTO.getUserId()); if (Objects.nonNull(user)) { vo.setFollower(user.getUserName()); } - ShopDTO shop = oopService.shop(shopId); + ShopDTO shop = oopService.shop(poolDTO.getShopId()); if (Objects.nonNull(shop)) { vo.setShopName(shop.getShopName()); } - int count = followRecordService.count(Wrappers.lambdaQuery() - .eq(FollowRecord::getTaskId, poolDTO.getId()) - .eq(FollowRecord::getUserId, userId) - .isNotNull(FollowRecord::getFollowTime) - ); - vo.setTimes(count); - return vo; - } - - private FollowPoolListVO transform4Origin(FollowPoolDTO poolDTO) { - FollowPoolListVO vo = trans2Pool(poolDTO, poolDTO.getOriginUser(), poolDTO.getOriginShop()); - vo.setRedistribution(false); + DefeatTypeEnum defeatTypeEnum = DefeatTypeEnum.ofValue(poolDTO.getInitiative()); + if (Objects.nonNull(defeatTypeEnum) && poolDTO.getState() == 3) { + vo.setDefeatType(defeatTypeEnum.getName()); + } - if (Boolean.TRUE.equals(poolDTO.getFinished())) { - if (Boolean.TRUE.equals(poolDTO.getChanged()) || !poolDTO.getOriginUser().equals(poolDTO.getFinishUser())) { - vo.setDefeatType("集团内战败"); - } - } else { - vo.setDefeatType("到期未成交"); + if (Boolean.TRUE.equals(poolDTO.getFinished()) && !poolDTO.getOriginShop().equals(poolDTO.getFinishShop())) { + vo.setDefeatDesc("集团内战败"); + } + if (poolDTO.getState() == 3 && DefeatTypeEnum.B.equals(defeatTypeEnum)) { + vo.setDefeatDesc("系统划走"); } + return vo; } - private FollowPoolListVO transform4FinishUser(FollowPoolDTO poolDTO) { - FollowPoolListVO vo = trans2Pool(poolDTO, poolDTO.getFollowUser(), poolDTO.getFollowShop()); - vo.setRedistribution(true); - if (TaskStateEnum.END.getValue().equals(poolDTO.getState())) { - vo.setDefeatType("到期未成交"); + private void prepareParams(LoginAuthBean user, FollowPoolQueryVO queryVO) { + if (Objects.nonNull(user)) { + queryVO.setUserId(user.getUserId()); + queryVO.setGroupId(user.getGroupId()); } else { - return null; + BV.isFalse(Objects.isNull(queryVO.getShopId()) && Objects.isNull(queryVO.getUserId()), () -> "请选择服务站或者人员"); + } + boolean inSection = DateUtil.sub(queryVO.getEndTime(), queryVO.getStartTime(), "d") <= MONTH_DAY; + BV.isTrue(inSection, () -> "暂不支持查询超过一个月区间的数据"); + boolean d = DateUtil.sub(queryVO.getEndTime(), queryVO.getStartTime(), "d") >= 0; + BV.isTrue(d, () -> "截止时间必须大于开始时间"); + if (Objects.nonNull(queryVO.getOrder()) && StringUtils.isValid(queryVO.getOrderAtt())) { + StringBuilder sb = new StringBuilder(" order by "); + sb.append(StringUtils.toColumnName(queryVO.getOrderAtt()).toLowerCase()); + if (queryVO.getOrder() == 1) { + sb.append(" asc "); + } else { + sb.append(" desc "); + } + queryVO.setOrderString(sb.toString()); } - return vo; - } - - private String queryShopId(Long userId, String code) { - List range = userService.getUserRoleDataRange(userId, code); - BV.isTrue(CollectionUtils.isNotEmpty(range), () -> "非管理岗位必须选择服务站"); - return range.stream().map(UserRoleDataRangeDTO::getRangeValue).map(String::valueOf).collect(Collectors.joining(",")); } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java index 82baa2c..88662bf 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/AbstractFollowStrategy.java @@ -12,6 +12,7 @@ import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.CustomerDetailDto; import cn.fw.valhalla.domain.dto.FollowAttachmentDTO; import cn.fw.valhalla.domain.enums.*; +import cn.fw.valhalla.domain.vo.follow.FollowDetailVO; import cn.fw.valhalla.domain.vo.follow.FollowRecordVO; import cn.fw.valhalla.domain.vo.setting.SettingVO; import cn.fw.valhalla.rpc.angel.InsurerRpcService; @@ -192,7 +193,7 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { record.setTaskId(task.getId()); record.setCustomerId(task.getCustomerId()); record.setType(task.getType()); - record.setUserId(customer.getAdviserId()); + record.setUserId(task.getFollowUser()); record.setPlanTime(task.getBeginTime()); settingBizService.querySettingByType(task.getType(), SettingTypeEnum.EFFECTIVE_TIME, task.getGroupId()) @@ -311,6 +312,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { return dto; } + abstract public FollowDetailVO assemble(Long customerId); + /** * 查询档案正在生效的保险信息 * @@ -369,6 +372,32 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { } /** + * 完成生成的跟进待办 + * + * @param taskId + */ + protected void completeTodo(Long taskId) { + List list = Optional.ofNullable(followRecordService.list(Wrappers.lambdaQuery() + .eq(FollowRecord::getTaskId, taskId) + .eq(FollowRecord::getOutTime, Boolean.FALSE) + .isNull(FollowRecord::getFollowTime) + .ge(FollowRecord::getDeadline, new Date()) + )).orElse(new ArrayList<>()); + if (CollectionUtils.isEmpty(list)) { + return; + } + for (FollowRecord record : list) { + if (Boolean.TRUE.equals(record.getAddTodo())) { + BackLogItemDTO dto = new BackLogItemDTO(record.getUserId(), getItemCode(record.getType()), String.valueOf(record.getId()), record.getPlanTime()); + todoRpcService.complete(dto); + } + record.setFollowTime(new Date()); + record.setOutTime(Boolean.FALSE); + } + followRecordService.updateBatchById(list); + } + + /** * 回滚完成的跟进 * * @param task @@ -565,6 +594,7 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { return null; } Integer value = vo.getDetailValue(); + SettingUnitEnum unit = Objects.requireNonNull(SettingUnitEnum.ofValue(vo.getUnit())); if (value == null || value <= 0) { log.info("关键设置数据异常,请检查数据 : settingType[{}] settingId[{}]", vo.getType(), vo.getId()); return null; @@ -572,7 +602,12 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { if (reverse) { value = -1 * value; } - return DateUtil.getExpired(origin, value, getCalendarType(Objects.requireNonNull(SettingUnitEnum.ofValue(vo.getUnit())))); + Timestamp expired = DateUtil.getExpired(origin, value, getCalendarType(unit)); + DateUtil.date2LocalDateTime(expired); + if (SettingUnitEnum.DAY.equals(unit) && !DateUtil.isBeforeDawn(expired)) { + expired = DateUtil.getExpired(DateUtil.startDate(expired), 1, Calendar.DATE); + } + return expired; } protected String getItemCode(FollowTypeEnum type) { @@ -684,8 +719,8 @@ public abstract class AbstractFollowStrategy implements FollowStrategy { private Timestamp getValidTime(SettingVO setting, Date origin) { Timestamp timestamp = calDate(setting, origin, false); - if (!Objects.requireNonNull(timestamp).after(DateUtil.localDateTime2Date(LocalDateTime.now()))) { - return calDate(setting, DateUtil.localDateTime2Date(LocalDateTime.now()), false); + while (!timestamp.after(DateUtil.localDateTime2Date(LocalDateTime.now()))) { + timestamp = calDate(setting, timestamp, false); } return timestamp; } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java index 8810369..dbd733e 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/FollowStrategy.java @@ -115,4 +115,12 @@ public interface FollowStrategy { * @param task */ void stopFollowTask(FollowTask task); + + /** + * 查询跟进池详情 + * + * @param task + * @return + */ + FollowDetailVO followPoolDetail(FollowTask task); } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/ACFollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/ACFollowStrategy.java index 93a019d..58a217c 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/ACFollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/ACFollowStrategy.java @@ -12,6 +12,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecordAttachments; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.CustomerDetailDto; import cn.fw.valhalla.domain.dto.FollowAttachmentDTO; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; import cn.fw.valhalla.domain.vo.follow.*; @@ -20,6 +21,7 @@ import cn.fw.valhalla.rpc.angel.dto.InsuranceDTO; import cn.fw.valhalla.rpc.erp.dto.BackLogItemDTO; import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy; import cn.fw.valhalla.service.data.AccidentPoolService; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -81,36 +83,10 @@ public class ACFollowStrategy extends AbstractFollowStrategy { public FollowDetailVO getDetail(Long id) { FollowRecord followRecord = followRecordService.getById(id); BV.notNull(followRecord, "跟进记录不存在"); - AccidentPool accidentPool = accidentPoolService.getById(followRecord.getCustomerId()); - BV.notNull(accidentPool, "事故车信息不存在"); - Customer customer = customerService.queryByPlateNo(accidentPool.getPlateNo(), accidentPool.getGroupId()); - ACDetailVO vo = new ACDetailVO(); + ACDetailVO vo = assemble(followRecord.getCustomerId()); vo.setId(followRecord.getId()); - vo.setName(accidentPool.getName()); - vo.setMobile(accidentPool.getMobile()); - vo.setRegion(MobileUtil.attribution(accidentPool.getMobile())); - vo.setRealMobile(accidentPool.getMobile()); vo.setTaskId(followRecord.getTaskId()); vo.setDeadline(followRecord.getDeadline()); - vo.setPlateNo(accidentPool.getPlateNo()); - vo.setTclInsComName(accidentPool.getInsurerName()); - vo.setBusInsComName(accidentPool.getInsurerName()); - vo.setCarModel(accidentPool.getBrandName() + " " + accidentPool.getSeriesName()); - vo.setReportNum(accidentPool.getReportNum()); - if (Objects.nonNull(customer)) { - CustomerDetailDto customerDetailDto = queryCustomerInfo(customer.getId()); - vo.setCustomerId(customer.getId()); - vo.setAdviserId(customerDetailDto.getAdviserId()); - vo.setAdviserName(customerDetailDto.getAdviserName()); - vo.setVin(customerDetailDto.getFrameNo()); - Optional insuranceDTO = queryInsuInfo(customer.getId()); - insuranceDTO.ifPresent(ins -> { - vo.setTclInsComName(ins.getTciInsurerName()); - vo.setTclInsExpiration(ins.getTciExpiryDate()); - vo.setBusInsComName(ins.getInsurerName()); - vo.setBusInsExpiration(ins.getExpiryDate()); - }); - } return vo; } @@ -172,7 +148,9 @@ public class ACFollowStrategy extends AbstractFollowStrategy { return true; } if (task.getFinished()) { - cancelFollowTodo(task.getId()); + completeTodo(task.getId()); + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); } return followTaskService.updateById(task); } @@ -189,7 +167,7 @@ public class ACFollowStrategy extends AbstractFollowStrategy { record.setTaskId(task.getId()); record.setCustomerId(task.getCustomerId()); record.setType(task.getType()); - record.setUserId(task.getOriginUser()); + record.setUserId(task.getFollowUser()); record.setPlanTime(task.getBeginTime()); record.setDeadline(task.getDeadline()); record.setOutTime(Boolean.FALSE); @@ -209,6 +187,13 @@ public class ACFollowStrategy extends AbstractFollowStrategy { followRecordService.overdue(record.getId()); } + @Override + public FollowDetailVO followPoolDetail(FollowTask task) { + ACDetailVO vo = assemble(task.getCustomerId()); + vo.setTaskId(task.getId()); + return vo; + } + /** * 处理跟进任务 * @@ -249,4 +234,33 @@ public class ACFollowStrategy extends AbstractFollowStrategy { } return task; } + + @Override + public ACDetailVO assemble(Long customerId) { + AccidentPool accidentPool = accidentPoolService.getById(customerId); + BV.notNull(accidentPool, "事故车信息不存在"); + Customer customer = customerService.queryByPlateNo(accidentPool.getPlateNo(), accidentPool.getGroupId()); + ACDetailVO vo = new ACDetailVO(); + vo.setName(accidentPool.getName()); + vo.setMobile(accidentPool.getMobile()); + vo.setRegion(MobileUtil.attribution(accidentPool.getMobile())); + vo.setRealMobile(accidentPool.getReportMobile()); + vo.setReportMobile(accidentPool.getReportMobile()); + vo.setAddress(accidentPool.getAddress()); + vo.setShopId(accidentPool.getShopId()); + vo.setShopName(accidentPool.getShopName()); + vo.setSms(accidentPool.getSms()); + vo.setPlateNo(accidentPool.getPlateNo()); + vo.setCarModel(accidentPool.getBrandName() + " " + accidentPool.getSeriesName()); + if (Objects.nonNull(customer)) { + CustomerDetailDto customerDetailDto = queryCustomerInfo(customer.getId()); + vo.setCustomerId(customer.getId()); + vo.setAdviserId(customerDetailDto.getAdviserId()); + vo.setAdviserName(customerDetailDto.getAdviserName()); + vo.setVin(customerDetailDto.getFrameNo()); + Optional insuranceDTO = queryInsuInfo(customer.getId()); + insuranceDTO.ifPresent(ins -> vo.setInsComName(ins.getTciInsurerName())); + } + return vo; + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/FMFollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/FMFollowStrategy.java index 3bf39db..da1546a 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/FMFollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/FMFollowStrategy.java @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.CustomerDetailDto; import cn.fw.valhalla.domain.dto.FollowAttachmentDTO; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.SettingTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; @@ -16,6 +17,7 @@ import cn.fw.valhalla.domain.vo.setting.SettingVO; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.sdk.enums.DataTypeEnum; import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -69,24 +71,11 @@ public class FMFollowStrategy extends AbstractFollowStrategy { public FollowDetailVO getDetail(Long id) { FollowRecord followRecord = followRecordService.getById(id); BV.notNull(followRecord, "跟进记录不存在"); - CustomerDetailDto customerDetailDto = queryCustomerInfo(followRecord.getCustomerId()); - FMDetailVO vo = new FMDetailVO(); - vo.setId(followRecord.getId()); - vo.setVin(customerDetailDto.getFrameNo()); - vo.setCustomerId(followRecord.getCustomerId()); - vo.setName(customerDetailDto.getName()); - vo.setMobile(customerDetailDto.getMobile()); - vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile())); - vo.setRealMobile(customerDetailDto.getMobile()); - vo.setTaskId(followRecord.getTaskId()); - vo.setDeadline(followRecord.getDeadline()); - vo.setPlateNo(customerDetailDto.getPlateNo()); - vo.setAdviserId(customerDetailDto.getAdviserId()); - vo.setAdviserName(customerDetailDto.getAdviserName()); - vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName()); - vo.setBuyDate(customerDetailDto.getBuyDate()); FollowTask followTask = followTaskService.getById(followRecord.getTaskId()); BV.notNull(followTask, "跟进信息不存在"); + FMDetailVO vo = assemble(followRecord.getCustomerId()); + vo.setId(followRecord.getId()); + vo.setTaskId(followRecord.getTaskId()); vo.setFMExpiration(followTask.getDeadline()); return vo; } @@ -159,6 +148,14 @@ public class FMFollowStrategy extends AbstractFollowStrategy { } @Override + public FollowDetailVO followPoolDetail(FollowTask task) { + FMDetailVO vo = assemble(task.getCustomerId()); + vo.setTaskId(task.getId()); + vo.setFMExpiration(task.getDeadline()); + return vo; + } + + @Override @Transactional(rollbackFor = Exception.class) public boolean origin2task(OriginalData originalData) { Customer customer = customerService.queryById(originalData.getCustomerId()); @@ -217,15 +214,16 @@ public class FMFollowStrategy extends AbstractFollowStrategy { if (TaskStateEnum.WAITING.equals(task.getState())) { idList.add(task.getId()); } - if (TaskStateEnum.ONGOING.equals(task.getState())) { task.setFinished(Boolean.TRUE); task.setFinishTime(completeTime); task.setState(TaskStateEnum.END); task.setFinishShop(customer.getShopId()); task.setFinishUser(customer.getAdviserId()); - cancelFollowTodo(task.getId()); + completeTodo(task.getId()); taskList.add(task); + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); } } List ids = list.stream().map(FollowTask::getId).collect(Collectors.toList()); @@ -237,4 +235,22 @@ public class FMFollowStrategy extends AbstractFollowStrategy { followTaskService.updateBatchById(taskList); } } + + @Override + public FMDetailVO assemble(Long customerId) { + CustomerDetailDto customerDetailDto = queryCustomerInfo(customerId); + FMDetailVO vo = new FMDetailVO(); + vo.setVin(customerDetailDto.getFrameNo()); + vo.setCustomerId(customerId); + vo.setName(customerDetailDto.getName()); + vo.setMobile(customerDetailDto.getMobile()); + vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile())); + vo.setRealMobile(customerDetailDto.getMobile()); + vo.setPlateNo(customerDetailDto.getPlateNo()); + vo.setAdviserId(customerDetailDto.getAdviserId()); + vo.setAdviserName(customerDetailDto.getAdviserName()); + vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName()); + vo.setBuyDate(customerDetailDto.getBuyDate()); + return vo; + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java index bf36f08..0c0f302 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/IRFollowStrategy.java @@ -19,6 +19,7 @@ import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -76,29 +77,10 @@ public class IRFollowStrategy extends AbstractFollowStrategy { public FollowDetailVO getDetail(Long id) { FollowRecord followRecord = followRecordService.getById(id); BV.notNull(followRecord, "跟进记录不存在"); - CustomerDetailDto detailDto = queryCustomerInfo(followRecord.getCustomerId()); - IRDetailVO vo = new IRDetailVO(); + IRDetailVO vo = assemble(followRecord.getCustomerId()); vo.setId(followRecord.getId()); - vo.setCustomerId(followRecord.getCustomerId()); - vo.setAdviserId(detailDto.getAdviserId()); - vo.setAdviserName(detailDto.getAdviserName()); - vo.setVin(detailDto.getFrameNo()); - vo.setName(detailDto.getName()); - vo.setMobile(detailDto.getMobile()); - vo.setRegion(MobileUtil.attribution(detailDto.getMobile())); - vo.setRealMobile(detailDto.getMobile()); vo.setTaskId(followRecord.getTaskId()); vo.setDeadline(followRecord.getDeadline()); - vo.setPlateNo(detailDto.getPlateNo()); - vo.setBuyPrice(detailDto.getBuyPrice() / 100); - vo.setCarModel(detailDto.getBrandName() + " " + detailDto.getSeriesName()); - Optional insuranceDTO = queryInsuInfo(followRecord.getCustomerId()); - insuranceDTO.ifPresent(ins -> { - vo.setTclInsComName(ins.getTciInsurerName()); - vo.setTclInsExpiration(ins.getTciExpiryDate()); - vo.setBusInsComName(ins.getInsurerName()); - vo.setBusInsExpiration(ins.getExpiryDate()); - }); return vo; } @@ -319,6 +301,13 @@ public class IRFollowStrategy extends AbstractFollowStrategy { super.overdueProcessing(record); } + @Override + public FollowDetailVO followPoolDetail(FollowTask task) { + IRDetailVO vo = assemble(task.getCustomerId()); + vo.setTaskId(task.getId()); + return vo; + } + /** * 生成消息推送 * @@ -374,8 +363,10 @@ public class IRFollowStrategy extends AbstractFollowStrategy { task.setFinished(Boolean.TRUE); task.setState(TaskStateEnum.END); task.setFinishTime(completeTime); - cancelFollowTodo(task.getId()); + completeTodo(task.getId()); taskList.add(task); + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); } } List ids = list.stream().map(FollowTask::getId).collect(Collectors.toList()); @@ -387,4 +378,28 @@ public class IRFollowStrategy extends AbstractFollowStrategy { followTaskService.updateBatchById(taskList); } } + + @Override + public IRDetailVO assemble(Long customerId) { + CustomerDetailDto detailDto = queryCustomerInfo(customerId); + IRDetailVO vo = new IRDetailVO(); + vo.setCustomerId(customerId); + vo.setAdviserId(detailDto.getAdviserId()); + vo.setAdviserName(detailDto.getAdviserName()); + vo.setVin(detailDto.getFrameNo()); + vo.setName(detailDto.getName()); + vo.setMobile(detailDto.getMobile()); + vo.setRegion(MobileUtil.attribution(detailDto.getMobile())); + vo.setRealMobile(detailDto.getMobile()); + vo.setPlateNo(detailDto.getPlateNo()); + vo.setCarModel(detailDto.getBrandName() + " " + detailDto.getSeriesName()); + Optional insuranceDTO = queryInsuInfo(customerId); + insuranceDTO.ifPresent(ins -> { + vo.setTclInsComName(ins.getTciInsurerName()); + vo.setTclInsExpiration(ins.getTciExpiryDate()); + vo.setBusInsComName(ins.getInsurerName()); + vo.setBusInsExpiration(ins.getExpiryDate()); + }); + return vo; + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/RMFollowStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/RMFollowStrategy.java index babecd4..ef055d0 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/RMFollowStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/follow/strategy/impl/RMFollowStrategy.java @@ -8,6 +8,7 @@ import cn.fw.valhalla.domain.db.follow.FollowRecord; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.CustomerDetailDto; import cn.fw.valhalla.domain.dto.FollowAttachmentDTO; +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.enums.SettingTypeEnum; import cn.fw.valhalla.domain.enums.TaskStateEnum; @@ -17,6 +18,7 @@ import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.sdk.enums.DataTypeEnum; import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy; import cn.fw.valhalla.service.data.OriginalDataService; +import cn.fw.valhalla.service.event.CancelApproveEvent; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -90,32 +92,10 @@ public class RMFollowStrategy extends AbstractFollowStrategy { public FollowDetailVO getDetail(Long id) { FollowRecord followRecord = followRecordService.getById(id); BV.notNull(followRecord, "跟进记录不存在"); - CustomerDetailDto customerDetailDto = queryCustomerInfo(followRecord.getCustomerId()); - RMDetailVO vo = new RMDetailVO(); + RMDetailVO vo = assemble(followRecord.getCustomerId()); vo.setId(followRecord.getId()); - vo.setCustomerId(followRecord.getCustomerId()); - vo.setName(customerDetailDto.getName()); - vo.setMobile(customerDetailDto.getMobile()); - vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile())); - vo.setRealMobile(customerDetailDto.getMobile()); vo.setTaskId(followRecord.getTaskId()); vo.setDeadline(followRecord.getDeadline()); - vo.setPlateNo(customerDetailDto.getPlateNo()); - vo.setVin(customerDetailDto.getFrameNo()); - vo.setAdviserId(customerDetailDto.getAdviserId()); - vo.setAdviserName(customerDetailDto.getAdviserName()); - vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName()); - vo.setLastMileage(customerDetailDto.getCurrentMileage()); - OriginalData originalData = originalDataService.getOne(Wrappers.lambdaQuery() - .eq(OriginalData::getCustomerId, followRecord.getCustomerId()) - .eq(OriginalData::getType, DataTypeEnum.FS) - .eq(OriginalData::getGroupId, followRecord.getGroupId()) - .orderByDesc(OriginalData::getGenerateTime) - .last("limit 1") - ); - if (Objects.nonNull(originalData)) { - vo.setDeliveryTime(originalData.getGenerateTime()); - } return vo; } @@ -226,6 +206,13 @@ public class RMFollowStrategy extends AbstractFollowStrategy { super.overdueProcessing(record); } + @Override + public FollowDetailVO followPoolDetail(FollowTask task) { + RMDetailVO vo = assemble(task.getCustomerId()); + vo.setTaskId(task.getId()); + return vo; + } + /** * 完成之前的跟进 * @@ -248,8 +235,10 @@ public class RMFollowStrategy extends AbstractFollowStrategy { task.setState(TaskStateEnum.END); task.setFinishUser(customer.getAdviserId()); task.setFinishShop(customer.getShopId()); - cancelFollowTodo(task.getId()); + completeTodo(task.getId()); taskList.add(task); + CancelApproveEvent event = new CancelApproveEvent(task.getId(), ApproveTypeEnum.FOLLOW_DEFEAT); + eventPublisher.publishEvent(event); } List ids = list.stream().map(FollowTask::getId).collect(Collectors.toList()); followNoticeRecordService.removeByTaskIds(ids); @@ -257,4 +246,32 @@ public class RMFollowStrategy extends AbstractFollowStrategy { followTaskService.updateBatchById(taskList); } } + + @Override + public RMDetailVO assemble(Long customerId) { + CustomerDetailDto customerDetailDto = queryCustomerInfo(customerId); + RMDetailVO vo = new RMDetailVO(); + vo.setCustomerId(customerId); + vo.setName(customerDetailDto.getName()); + vo.setMobile(customerDetailDto.getMobile()); + vo.setRegion(MobileUtil.attribution(customerDetailDto.getMobile())); + vo.setRealMobile(customerDetailDto.getMobile()); + vo.setPlateNo(customerDetailDto.getPlateNo()); + vo.setVin(customerDetailDto.getFrameNo()); + vo.setAdviserId(customerDetailDto.getAdviserId()); + vo.setAdviserName(customerDetailDto.getAdviserName()); + vo.setCarModel(customerDetailDto.getBrandName() + " " + customerDetailDto.getSeriesName()); + vo.setLastMileage(customerDetailDto.getCurrentMileage()); + OriginalData originalData = originalDataService.getOne(Wrappers.lambdaQuery() + .eq(OriginalData::getCustomerId, customerId) + .eq(OriginalData::getType, DataTypeEnum.FS) + .eq(OriginalData::getGroupId, customerDetailDto.getGroupId()) + .orderByDesc(OriginalData::getGenerateTime) + .last("limit 1") + ); + if (Objects.nonNull(originalData)) { + vo.setDeliveryTime(originalData.getGenerateTime()); + } + return vo; + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/setting/strategy/AbstractSettingStrategy.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/setting/strategy/AbstractSettingStrategy.java index c86de27..b2fa292 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/setting/strategy/AbstractSettingStrategy.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/bus/setting/strategy/AbstractSettingStrategy.java @@ -127,8 +127,8 @@ public abstract class AbstractSettingStrategy implements SettingStrategy { protected boolean saveOrUpdate(final FollowTypeEnum type, final Long groupId, final List list) { String lockKey = getLockKey(groupId, type); Pair pair = distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, 0, 15); + BV.isTrue(Boolean.TRUE.equals(pair.getKey()), "请勿重复提交"); try { - BV.isTrue(Boolean.TRUE.equals(pair.getKey()), "请勿重复提交"); final String key = generateKey(groupId, type); FollowSetting setting = settingService.getOne(Wrappers.lambdaQuery() .eq(FollowSetting::getCategory, type) @@ -148,6 +148,9 @@ public abstract class AbstractSettingStrategy implements SettingStrategy { detail.setSettingId(setting.getId()); detail.setId(settingDTO.getId()); detail.setDetailValue(settingDTO.getDetailValue()); + if (SettingTypeEnum.REVISE_RATIO.getValue().equals(settingDTO.getType())) { + detail.setDetailValue(settingDTO.getDetailValue() * 100); + } detail.setType(SettingTypeEnum.ofValue(settingDTO.getType())); detail.setUnit(SettingUnitEnum.ofValue(settingDTO.getUnit())); detail.setYn(Boolean.TRUE); @@ -263,6 +266,7 @@ public abstract class AbstractSettingStrategy implements SettingStrategy { /** * 防重锁 + * * @param groupId * @param type * @return diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/CustomerService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/CustomerService.java index 5fef719..aad39e9 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/CustomerService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/CustomerService.java @@ -5,6 +5,8 @@ import cn.fw.valhalla.domain.db.customer.Customer; import com.baomidou.mybatisplus.extension.service.IService; import cn.fw.valhalla.domain.vo.customer.CustomerListVO; import cn.fw.valhalla.domain.query.CustomerQueryVO; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import java.util.List; @@ -73,4 +75,12 @@ public interface CustomerService extends IService { * @param customerId */ void forbiddenPlate(Long customerId); + + /** + * 查询服务顾问所有档案 + * @param adviserId + * @return + */ + @Nullable + List queryByAdviserId(@NonNull Long adviserId); } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowRecordService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowRecordService.java index 3d3e6b5..a90d5c9 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowRecordService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowRecordService.java @@ -1,6 +1,7 @@ package cn.fw.valhalla.service.data; import cn.fw.valhalla.domain.db.follow.FollowRecord; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; @@ -51,4 +52,12 @@ public interface FollowRecordService extends IService { * @return */ boolean removeByTaskIds(List idList); + + /** + * 查询档案对应的跟进任务 + * @param customerId + * @param list + * @return + */ + List getRecordListByCustomer(final Long customerId, List list); } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowTaskService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowTaskService.java index 7c9e6a6..49c6d34 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowTaskService.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/FollowTaskService.java @@ -2,6 +2,7 @@ package cn.fw.valhalla.service.data; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.dto.FollowPoolDTO; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.domain.query.FollowPoolQueryVO; import com.baomidou.mybatisplus.extension.service.IService; @@ -18,29 +19,25 @@ public interface FollowTaskService extends IService { * 根据档案id查询 * * @param customerId + * @param list * @return */ - List getWaitListByCustomerId(Long customerId); - - /** - * 战败池查询 - * - * @param queryVO - * @return - */ - List defeatList(FollowPoolQueryVO queryVO); + List getWaitListByCustomerId(Long customerId, List list); /** * 跟进池查询 + * * @param queryVO * @return */ List followList(FollowPoolQueryVO queryVO); /** - * 成交池查询 - * @param queryVO + * 查询客户所有的跟进信息 + * + * @param customerId + * @param list * @return */ - List completeList(FollowPoolQueryVO queryVO); + List getListByCustomerId(Long customerId, List list); } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/LeaveNeedDoService.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/LeaveNeedDoService.java new file mode 100644 index 0000000..b1f0422 --- /dev/null +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/LeaveNeedDoService.java @@ -0,0 +1,30 @@ +package cn.fw.valhalla.service.data; + +import cn.fw.valhalla.domain.db.LeaveNeedDo; +import com.baomidou.mybatisplus.extension.service.IService; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; + +/** + * @author : kurisu + * @className : LeaveNeedDoService + * @description : 人员变动待处理事件 + * @date: 2020-10-16 17:02 + */ +public interface LeaveNeedDoService extends IService { + /** + * 通过id查询可处理数据 + * + * @param id + * @return + */ + @Nullable + LeaveNeedDo queryProcessableById(@NonNull Long id); + + /** + * 处理数据 + * + * @param id + */ + void dealById(@NonNull Long id); +} diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/CustomerServiceImpl.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/CustomerServiceImpl.java index 83068dd..88df255 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/CustomerServiceImpl.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/CustomerServiceImpl.java @@ -8,6 +8,8 @@ import cn.fw.valhalla.service.data.CustomerService; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -80,4 +82,13 @@ public class CustomerServiceImpl extends ServiceImpl i updateById(customer); } } + + @Override + @Nullable + public List queryByAdviserId(@NonNull Long adviserId) { + return this.list(Wrappers.lambdaQuery() + .eq(Customer::getAdviserId, adviserId) + .eq(Customer::getYn, Boolean.TRUE) + ); + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowRecordServiceImpl.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowRecordServiceImpl.java index b4fbbfe..1cc7f76 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowRecordServiceImpl.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowRecordServiceImpl.java @@ -2,6 +2,7 @@ package cn.fw.valhalla.service.data.impl; import cn.fw.valhalla.dao.mapper.FollowRecordMapper; import cn.fw.valhalla.domain.db.follow.FollowRecord; +import cn.fw.valhalla.domain.enums.FollowTypeEnum; import cn.fw.valhalla.service.data.FollowRecordService; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -10,7 +11,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * @author : kurisu @@ -72,4 +75,14 @@ public class FollowRecordServiceImpl extends ServiceImpl getRecordListByCustomer(Long customerId, List list) { + return Optional.ofNullable(list(Wrappers.lambdaQuery() + .eq(FollowRecord::getCustomerId, customerId) + .eq(FollowRecord::getOutTime, Boolean.FALSE) + .eq(FollowRecord::getAddTodo, Boolean.FALSE) + .in(!CollectionUtils.isEmpty(list), FollowRecord::getType, list) + )).orElse(new ArrayList<>()); + } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowTaskServiceImpl.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowTaskServiceImpl.java index 05dfd2d..5013f6f 100644 --- a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowTaskServiceImpl.java +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/FollowTaskServiceImpl.java @@ -11,8 +11,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -26,24 +28,16 @@ import java.util.Optional; @Slf4j public class FollowTaskServiceImpl extends ServiceImpl implements FollowTaskService { @Override - public List getWaitListByCustomerId(Long customerId) { + public List getWaitListByCustomerId(Long customerId, List list) { return Optional.ofNullable(list(Wrappers.lambdaQuery() .eq(FollowTask::getCustomerId, customerId) .eq(FollowTask::getFinished, Boolean.FALSE) .eq(FollowTask::getState, TaskStateEnum.WAITING) - .ne(FollowTask::getType, FollowTypeEnum.IR) + .in(!CollectionUtils.isEmpty(list), FollowTask::getType, list) )).orElse(new ArrayList<>()); } @Override - public List defeatList(FollowPoolQueryVO queryVO) { - Integer current = queryVO.getCurrent(); - Integer pageSize = queryVO.getPageSize(); - Integer startIndex = (current-1) * pageSize; - return Optional.ofNullable(getBaseMapper().defeatList(startIndex, pageSize, queryVO)).orElse(new ArrayList<>()); - } - - @Override public List followList(FollowPoolQueryVO queryVO) { Integer current = queryVO.getCurrent(); Integer pageSize = queryVO.getPageSize(); @@ -52,10 +46,12 @@ public class FollowTaskServiceImpl extends ServiceImpl completeList(FollowPoolQueryVO queryVO) { - Integer current = queryVO.getCurrent(); - Integer pageSize = queryVO.getPageSize(); - Integer startIndex = (current-1) * pageSize; - return Optional.ofNullable(getBaseMapper().completeList(startIndex, pageSize, queryVO)).orElse(new ArrayList<>()); + public List getListByCustomerId(Long customerId, List list) { + return Optional.ofNullable(list(Wrappers.lambdaQuery() + .eq(FollowTask::getCustomerId, customerId) + .eq(FollowTask::getFinished, Boolean.FALSE) + .ne(FollowTask::getState, TaskStateEnum.END) + .in(!CollectionUtils.isEmpty(list), FollowTask::getType, list) + )).orElse(new ArrayList<>()); } } diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/LeaveNeedDoServiceImpl.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/LeaveNeedDoServiceImpl.java new file mode 100644 index 0000000..adaceff --- /dev/null +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/data/impl/LeaveNeedDoServiceImpl.java @@ -0,0 +1,48 @@ +package cn.fw.valhalla.service.data.impl; + +import cn.fw.valhalla.dao.mapper.LeaveNeedDoMapper; +import cn.fw.valhalla.domain.db.LeaveNeedDo; +import cn.fw.valhalla.domain.enums.LeaveTodoTypeEnum; +import cn.fw.valhalla.service.data.LeaveNeedDoService; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * @author : kurisu + * @className : LeaveNeedDoServiceImpl + * @description : 人员变动待处理事件 + * @date: 2020-08-12 11:05 + */ +@Service +@Slf4j +public class LeaveNeedDoServiceImpl extends ServiceImpl implements LeaveNeedDoService { + + @Override + @Nullable + public LeaveNeedDo queryProcessableById(@NonNull Long id) { + List list = list(Wrappers.lambdaQuery() + .eq(LeaveNeedDo::getId, id) + .eq(LeaveNeedDo::getDone, Boolean.FALSE) + .eq(LeaveNeedDo::getType, LeaveTodoTypeEnum.CUSTOMER) + ); + if (CollectionUtils.isEmpty(list)) { + return null; + } + return list.get(0); + } + + @Override + public void dealById(@NonNull Long id) { + update(Wrappers.lambdaUpdate() + .set(LeaveNeedDo::getDone, Boolean.TRUE) + .eq(LeaveNeedDo::getId, id) + ); + } +} diff --git a/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/event/CancelApproveEvent.java b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/event/CancelApproveEvent.java new file mode 100644 index 0000000..579f6dc --- /dev/null +++ b/fw-valhalla-service/src/main/java/cn/fw/valhalla/service/event/CancelApproveEvent.java @@ -0,0 +1,18 @@ +package cn.fw.valhalla.service.event; + +import cn.fw.valhalla.domain.enums.ApproveTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author : kurisu + * @className : CancelApproveEvent + * @description : 取消审批事件 + * @date: 2020-10-15 17:26 + */ +@Data +@AllArgsConstructor +public class CancelApproveEvent { + private Long taskId; + private ApproveTypeEnum typeEnum; +}