package cn.fw.valhalla.service.bus.cust; import cn.fw.common.util.ValidationUtils; import cn.fw.common.web.annotation.DisLock; import cn.fw.common.web.auth.LoginAuthBean; import cn.fw.valhalla.common.constant.RoleCode; import cn.fw.valhalla.common.utils.DateUtil; import cn.fw.valhalla.common.utils.StringUtils; import cn.fw.valhalla.domain.db.customer.AccidentPool; 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.db.pool.CustomerCluePool; import cn.fw.valhalla.domain.dto.AccidentPoolDTO; import cn.fw.valhalla.domain.enums.*; import cn.fw.valhalla.rpc.backlog.TodoRpcService; import cn.fw.valhalla.rpc.backlog.dto.BackLogItemDTO; import cn.fw.valhalla.rpc.erp.UserService; import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; import cn.fw.valhalla.rpc.oop.OopService; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.service.bus.setting.SettingBizService; import cn.fw.valhalla.service.data.*; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import static cn.fw.common.businessvalidator.Validator.BV; import static cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy.getCalendarType; /** * @author : kurisu * @className : AccidentPoolBizService * @description : 事故池 * @date: 2020-08-15 15:20 */ @Service @Slf4j @RequiredArgsConstructor public class AccidentPoolBizService { private final AccidentPoolService accidentPoolService; private final FollowTaskService followTaskService; private final FollowRecordService followRecordService; private final UserService userService; private final OopService oopService; private final SettingBizService settingBizService; private final TodoRpcService todoRpcService; private final CustomerCluePoolService customerCluePoolService; private final CustomerService customerService; @Value("${spring.cache.custom.global-prefix}:AccidentPool") @Getter private String keyPrefix; @Value("${follow.todo.ACCode}") @Getter private String ACCode; @Transactional(rollbackFor = Exception.class) @DisLock(prefix = "#this.getKeyPrefix()", key = "#currentUser.groupId + ':' + #poolDTO.plateNo", message = "请勿重复提交") public Long add2Pool(LoginAuthBean currentUser, AccidentPoolDTO poolDTO) { boolean isPlateNo = ValidationUtils.checkCarPlate(poolDTO.getPlateNo()); BV.isTrue(isPlateNo, () -> "车牌号不正确,请检查是否包含I、O或特殊字符"); if (!Boolean.TRUE.equals(poolDTO.getForce())) { AccidentPool repetition = isRepetition(currentUser.getGroupId(), poolDTO.getPlateNo()); if (Objects.nonNull(repetition)) { return repetition.getCreateTime().getTime(); } } if (StringUtils.isEmpty(poolDTO.getMobile())) { poolDTO.setMobile(poolDTO.getReportMobile()); } AccidentPool pool = conversion2db(poolDTO, currentUser); pool.setShopId(poolDTO.getShopId()); pool.setShopName(poolDTO.getShopName()); BV.notNull(pool.getShopId(), () -> "服务站信息不正确,请确认"); accidentPoolService.save(pool); afterAddPool(pool); return 0L; } private void afterAddPool(final AccidentPool pool) { final String plateNo = pool.getPlateNo(); CustomerCluePool cluePool = customerCluePoolService.queryByPlateNo(plateNo, pool.getGroupId(), FollowTypeEnum.AC); if (Objects.nonNull(cluePool) && ClueStatusEnum.ONGOING.equals(cluePool.getClueStatus())) { cluePool.setClueStatus(ClueStatusEnum.FAILURE); cluePool.setCloseTime(new Date()); customerCluePoolService.updateById(cluePool); clearTask(cluePool.getId(), cluePool.getGroupId()); } CustomerCluePool clue = createClue(pool); FollowTask task = createTask(clue); createTaskRecord(task); } private AccidentPool conversion2db(AccidentPoolDTO dto, LoginAuthBean currentUser) { AccidentPool pool = new AccidentPool(); BeanUtils.copyProperties(dto, pool); pool.setAddress(dto.getReportAddress()); pool.setCreateTime(new Date()); pool.setUpdateTime(new Date()); pool.setGroupId(currentUser.getGroupId()); return pool; } private AccidentPool isRepetition(Long groupId, String plateNo) { AccidentPool lastOne = accidentPoolService.getOne(Wrappers.lambdaQuery() .eq(AccidentPool::getPlateNo, plateNo) .eq(AccidentPool::getGroupId, groupId) .orderByDesc(AccidentPool::getCreateTime) .last(" limit 1 ") ); if (Objects.isNull(lastOne)) { return null; } if (LocalDate.now().minusDays(7L).isBefore(DateUtil.date2LocalDate(lastOne.getCreateTime()))) { FollowTask lastOngoingTask = followTaskService.getOne(Wrappers.lambdaQuery() .eq(FollowTask::getCustomerId, lastOne.getId()) .eq(FollowTask::getType, FollowTypeEnum.AC) .eq(FollowTask::getState, TaskStateEnum.ONGOING) .last(" limit 1 ") ); if (Objects.nonNull(lastOngoingTask)) { return lastOne; } } return null; } /** * 清理跟进任务 * * @param clueId * @param groupId */ private void clearTask(Long clueId, Long groupId) { List taskList = followTaskService.list(Wrappers.lambdaQuery() .eq(FollowTask::getGroupId, groupId) .eq(FollowTask::getState, TaskStateEnum.ONGOING) .eq(FollowTask::getClueId, clueId) .eq(FollowTask::getType, FollowTypeEnum.AC) ); if (!CollectionUtils.isEmpty(taskList)) { for (FollowTask task : taskList) { clearRecord(task.getId()); task.setCloseTime(new Date()); task.setReason(TaskDefeatTypeEnum.E); task.setState(TaskStateEnum.DEFEAT); } followTaskService.updateBatchById(taskList); } } /** * 清理对应任务的记录 * * @param taskId */ private void clearRecord(Long taskId) { followRecordService.remove(Wrappers.lambdaQuery() .eq(FollowRecord::getTaskId, taskId) .eq(FollowRecord::getAddTodo, Boolean.FALSE) ); List list = followRecordService.list(Wrappers.lambdaQuery() .eq(FollowRecord::getTaskId, taskId) .eq(FollowRecord::getAddTodo, Boolean.TRUE) .eq(FollowRecord::getOutTime, Boolean.FALSE) .isNull(FollowRecord::getFollowTime) ); if (CollectionUtils.isEmpty(list)) { return; } for (FollowRecord record : list) { record.setLimitTime(DateUtil.localDateTime2Date(LocalDateTime.now())); BackLogItemDTO dto = new BackLogItemDTO(record.getUserId(), getACCode(), String.valueOf(record.getId()), DateUtil.localDateTime2Date(LocalDateTime.now()), record.getShopId()); todoRpcService.cancel(dto); } followRecordService.updateBatchById(list); } /** * 新增线索 * * @param pool * @return */ private CustomerCluePool createClue(final AccidentPool pool) { final Customer customer = customerService.queryByPlateNo(pool.getPlateNo(), pool.getGroupId()); final Date datetime = new Date(); final CustomerCluePool cluePool = new CustomerCluePool(); cluePool.setRefererId(pool.getId()); cluePool.setPlateNo(pool.getPlateNo()); cluePool.setClueType(FollowTypeEnum.AC); cluePool.setAddTime(datetime); cluePool.setStartTime(datetime); settingBizService.querySettingByType(FollowTypeEnum.AC, SettingTypeEnum.FAIL_TIME, pool.getGroupId()) .ifPresent(r -> { Timestamp expired = DateUtil.getExpired(datetime, r.getDetailValue(), getCalendarType(Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit())))); cluePool.setDeadline(expired); }); cluePool.setClueStatus(ClueStatusEnum.ONGOING); cluePool.setRedistribution(Boolean.FALSE); ShopDTO shop = oopService.shop(pool.getShopId()); BV.notNull(shop, () -> "门店信息有误"); List userByRole = userService.getUserByRole(pool.getShopId(), RoleCode.SGCGJ); BV.isFalse(CollectionUtils.isEmpty(userByRole), () -> "该门店没有事故车跟进人员"); int randomIndex = new Random().nextInt(userByRole.size()); PostUserDTO userDTO = userByRole.get(randomIndex); cluePool.setOriginalUserId(userDTO.getUserId()); cluePool.setOriginalUserName(userDTO.getUserName()); if (Objects.nonNull(customer)) { if (shop.getId().equals(customer.getShopId())) { Optional dto = userByRole.stream().filter(u -> u.getUserId().equals(customer.getAdviserId())).findFirst(); dto.ifPresent(d -> { cluePool.setOriginalUserId(d.getUserId()); cluePool.setOriginalUserName(d.getUserName()); }); } } cluePool.setOriginalShopId(shop.getId()); cluePool.setOriginalShopName(shop.getShortName()); cluePool.setGroupId(pool.getGroupId()); cluePool.setCreateTime(new Date()); customerCluePoolService.save(cluePool); return cluePool; } /** * 新增跟进任务 * * @param pool * @return */ private FollowTask createTask(final CustomerCluePool pool) { final FollowTask task = new FollowTask(); task.setClueId(pool.getId()); task.setCustomerId(pool.getRefererId()); task.setType(FollowTypeEnum.AC); task.setState(TaskStateEnum.ONGOING); task.setBeginTime(pool.getStartTime()); task.setRedistribution(Boolean.FALSE); task.setDeadline(pool.getDeadline()); task.setFollowUser(pool.getOriginalUserId()); task.setFollowUserName(pool.getOriginalUserName()); task.setFollowShop(pool.getOriginalShopId()); task.setGroupId(pool.getGroupId()); task.setCreateTime(new Date()); followTaskService.save(task); return task; } /** * 新增跟进代办任务 * * @param task */ private void createTaskRecord(final FollowTask task) { final FollowRecord record = new FollowRecord(); record.setTaskId(task.getId()); record.setType(FollowTypeEnum.AC); record.setCustomerId(task.getCustomerId()); record.setUserId(task.getFollowUser()); record.setUserName(task.getFollowUserName()); record.setPlanTime(task.getBeginTime()); settingBizService.querySettingByType(FollowTypeEnum.AC, SettingTypeEnum.EFFECTIVE_TIME, task.getGroupId()) .ifPresent(r -> { Timestamp expired = DateUtil.getExpired(task.getBeginTime(), r.getDetailValue(), getCalendarType(Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit())))); record.setDeadline(expired); }); record.setOutTime(Boolean.FALSE); record.setAddTodo(Boolean.FALSE); record.setGroupId(task.getGroupId()); record.setShopId(task.getFollowShop()); record.setLimitTime(record.getDeadline()); followRecordService.queryAndSave(record); } }