AccidentPoolBizService.java 12 KB
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.<AccidentPool>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.<FollowTask>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<FollowTask> taskList = followTaskService.list(Wrappers.<FollowTask>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.<FollowRecord>lambdaQuery()
                .eq(FollowRecord::getTaskId, taskId)
                .eq(FollowRecord::getAddTodo, Boolean.FALSE)
        );
        List<FollowRecord> list = followRecordService.list(Wrappers.<FollowRecord>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<PostUserDTO> 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<PostUserDTO> 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);
    }
}