IRFollowStrategy.java 13.6 KB
package cn.fw.valhalla.service.bus.follow.strategy.impl;

import cn.fw.valhalla.common.constant.RoleCode;
import cn.fw.valhalla.common.utils.StringUtils;
import cn.fw.valhalla.domain.db.OriginalData;
import cn.fw.valhalla.domain.db.customer.Customer;
import cn.fw.valhalla.domain.db.follow.ClueTask;
import cn.fw.valhalla.domain.db.follow.FollowClue;
import cn.fw.valhalla.domain.dto.CustomerDetailDto;
import cn.fw.valhalla.domain.enums.*;
import cn.fw.valhalla.rpc.erp.dto.PostUserDTO;
import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
import cn.fw.valhalla.rpc.shirasawa.dto.FollowInitDTO;
import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.fw.common.businessvalidator.Validator.BV;

/**
 * @author : kurisu
 * @className : IRFollowStrategy
 * @description : 续保策略
 * @date: 2020-08-17 10:48
 */
@Slf4j
@Component
@SuppressWarnings("Duplicates")
public class IRFollowStrategy extends AbstractFollowStrategy {
    @Override
    public FollowTypeEnum getFollowType() {
        return FollowTypeEnum.IR;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean origin2task(OriginalData originalData) {
        Customer customer = null;
        if (StringUtils.isValid(originalData.getFrameNo())) {
            customer = customerService.queryByFrameNo(originalData.getFrameNo(), originalData.getGroupId());
        }
        if (Objects.isNull(customer)) {
            customer = customerService.queryById(originalData.getCustomerId());
        }
        BV.notNull(customer, () -> "档案不存在");
        FollowClue completeClue = followClueService.getOne(Wrappers.<FollowClue>lambdaQuery()
                        .eq(FollowClue::getVin, customer.getFrameNo())
                        .eq(FollowClue::getClueType, getFollowType())
                        .eq(FollowClue::getClueState, ClueStatusEnum.ONGOING)
                , Boolean.FALSE);
        finishClue(originalData, completeClue);

        FollowClue wattingClue = followClueService.getOne(Wrappers.<FollowClue>lambdaQuery()
                        .eq(FollowClue::getVin, customer.getFrameNo())
                        .eq(FollowClue::getClueType, getFollowType())
                        .eq(FollowClue::getClueState, ClueStatusEnum.WAITING)
                , Boolean.FALSE);
        if (Objects.nonNull(wattingClue)) {
            followClueService.removeById(wattingClue.getId());
        }
        FollowClue clue = createClueInfo(originalData, getFollowType(), customer);
        followClueService.save(clue);
        createFirstNotice(clue, customer.getId(), customer.getBrandId());
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void startClue(FollowClue followClue) {
        if (!ClueStatusEnum.WAITING.equals(followClue.getClueState())) {
            return;
        }
        Customer customer = customerService.queryByFrameNo(followClue.getVin(), followClue.getGroupId());
        if (Objects.isNull(customer)) {
            followClueService.removeById(followClue.getId());
            return;
        }
        followClue.setPlateNo(customer.getPlateNo());
        final ClueTask clueTask = createNewTask(followClue);
        List<PostUserDTO> userByRole = userService.getUserByRole(clueTask.getFollowShop(), RoleCode.XBGJ);
        BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员");
        fillTaskUser(clueTask, userByRole);
        clueTaskService.save(clueTask);
        followClue.setClueState(ClueStatusEnum.ONGOING);
        final FollowInitDTO followInitDTO = creteFollowInitDTO(followClue, clueTask);
        followClue.setNextTime(clueTask.getDeadline().plusDays(1L));
        shirasawaRpcService.createFollowData(followInitDTO);
        followClueService.updateById(followClue);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeTask(ClueTask task) {
        boolean redistribution = Boolean.TRUE.equals(task.getRedistribution());
        final Long clueId = task.getClueId();
        FollowClue clue = followClueService.getById(clueId);
        BV.notNull(clue, () -> "跟进线索不存在: " + clueId);
        redistribution = redistribution || task.getDeadline().toLocalDate().isEqual(clue.getEndTime().toLocalDate());
        task.setState(TaskStateEnum.DEFEAT);
        task.setCloseTime(task.getDeadline().minusSeconds(1L));
        task.setReason(TaskDefeatTypeEnum.C);
        if (!redistribution) {
            task.setReason(TaskDefeatTypeEnum.B);
        }
        boolean rpcSucess = rpcStopTask(task);
        BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
        task.setRpcSuccess(rpcSucess);
        if (Objects.nonNull(clue) && redistribution) {
            clue.setClueState(ClueStatusEnum.FAILURE);
            clue.setCloseTime(task.getCloseTime());
            followClueService.updateById(clue);
            redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
            afterStopClue(clue);
        }
        clueTaskService.updateById(task);
        if (Objects.nonNull(clue) && !redistribution) {
            this.createSecondaryTask(clue, task);
        }
    }

    /**
     * [角色变动]结束任务
     *
     * @param task
     */
    @Transactional(rollbackFor = Exception.class)
    public void onRoleChangeCloseTask(ClueTask task) {
        boolean redistribution = Boolean.TRUE.equals(task.getRedistribution());
        Long clueId = task.getClueId();
        FollowClue clue = followClueService.getById(clueId);
        BV.notNull(clue, () -> "跟进线索不存在: " + clueId);
        redistribution = redistribution || task.getDeadline().toLocalDate().isEqual(clue.getEndTime().toLocalDate());
        task.setState(TaskStateEnum.DEFEAT);
        task.setCloseTime(LocalDateTime.now());
        task.setReason(TaskDefeatTypeEnum.D);
        boolean rpcSucess = rpcStopTask(task);
        BV.isTrue(rpcSucess, () -> "跟进系统终止任务失败");
        task.setRpcSuccess(rpcSucess);
        if (Objects.nonNull(clue) && redistribution) {
            clue.setClueState(ClueStatusEnum.FAILURE);
            clue.setCloseTime(task.getCloseTime());
            followClueService.updateById(clue);
            afterStopClue(clue);
            redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
        }
        clueTaskService.updateById(task);
        if (Objects.nonNull(clue) && !redistribution) {
            this.createSecondaryTask(clue, task);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void forceStopTask(ClueTask task) {
        Long clueId = task.getClueId();
        FollowClue clue = followClueService.getById(clueId);
        task.setState(TaskStateEnum.DEFEAT);
        task.setCloseTime(LocalDateTime.now());
        task.setReason(TaskDefeatTypeEnum.A);
        boolean rpcSucess = rpcStopTask(task);
        task.setRpcSuccess(rpcSucess);
        clueTaskService.updateById(task);
        if (Objects.nonNull(clue)) {
            clue.setClueState(ClueStatusEnum.FAILURE);
            clue.setCloseTime(LocalDateTime.now());
            followClueService.updateById(clue);
            afterStopClue(clue);
            redisTemplate.opsForSet().add(generateStopKey(), String.valueOf(clueId));
        }
    }

    @Override
    protected ClueTask createNewTask(FollowClue followClue) {
        final FollowTypeEnum followTypeEnum = followClue.getClueType();
        final ClueTask clueTask = new ClueTask();
        clueTask.setClueId(followClue.getId());
        clueTask.setType(followTypeEnum);
        clueTask.setBeginTime(followClue.getStartTime());
        clueTask.setRedistribution(Boolean.FALSE);
        clueTask.setDeadline(followClue.getEndTime());
        clueTask.setState(TaskStateEnum.ONGOING);
        clueTask.setGroupId(followClue.getGroupId());
        Long userId = null;
        Long shopId = null;
        if (StringUtils.isValid(followClue.getVin())) {
            Customer customer = customerService.queryByFrameNo(followClue.getVin(), followClue.getGroupId());
            if (Objects.nonNull(customer)) {
                userId = customer.getAdviserId();
                shopId = customer.getShopId();
                ShopDTO shop = oopService.shop(shopId);
                if (Objects.isNull(shop)) {
                    userId = null;
                    shopId = followClue.getSuggestShopId();
                }
            }
        }
        if (Objects.isNull(shopId)) {
            shopId = followClue.getSuggestShopId();
        }
        if (shopId == 146L) {
            ArrayList<Long> arrayList = ListUtil.toList(67L, 65L, 66L);
            int randomIndex = new Random().nextInt(arrayList.size());
            shopId = arrayList.get(randomIndex);
        }
        clueTask.setFollowShop(shopId);
        clueTask.setFollowUser(userId);
        return clueTask;
    }

    protected void createSecondaryTask(FollowClue clue, ClueTask oldTask) {
        LocalDate endTime = clue.getEndTime().toLocalDate();
        if (!LocalDate.now().isBefore(endTime)) {
            clue.setCloseTime(clue.getEndTime());
            clue.setClueState(ClueStatusEnum.FAILURE);
            followClueService.updateById(clue);
            return;
        }
        ClueTask redistributionTask = new ClueTask();
        BeanUtils.copyProperties(oldTask, redistributionTask);
        redistributionTask.setId(null);
        redistributionTask.setRedistribution(Boolean.TRUE);
        redistributionTask.setBeginTime(LocalDate.now().atStartOfDay());
        redistributionTask.setDeadline(clue.getEndTime());
        redistributionTask.setState(TaskStateEnum.ONGOING);
        redistributionTask.setFinishShop(null);
        redistributionTask.setFinishUser(null);
        redistributionTask.setCloseTime(null);
        redistributionTask.setFinishUserName(null);
        redistributionTask.setReason(null);
        redistributionTask.setRpcSuccess(Boolean.FALSE);
        List<PostUserDTO> userByRole = userService.getUserByRole(oldTask.getFollowShop(), RoleCode.XBGJ);
        BV.isNotEmpty(userByRole, () -> "该门店没有【续保跟进】人员");
        List<PostUserDTO> newUserRole = userByRole.stream().filter(userDTO -> !userDTO.getUserId().equals(oldTask.getFollowUser())).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(newUserRole)) {
            redistributionTask.setFollowUser(oldTask.getFollowUser());
            redistributionTask.setFollowUserName(oldTask.getFollowUserName());
        } else {
            int randomIndex = new Random().nextInt(newUserRole.size());
            PostUserDTO userDTO = newUserRole.get(randomIndex);
            redistributionTask.setFollowUser(userDTO.getUserId());
            redistributionTask.setFollowUserName(userDTO.getUserName());
        }
        clueTaskService.save(redistributionTask);
        FollowInitDTO followInitDTO = creteRedistributionFollowInitDTO(clue, redistributionTask);
        shirasawaRpcService.createFollowData(followInitDTO);
        clue.setNextTime(redistributionTask.getDeadline().plusDays(1L));
        followClueService.updateById(clue);
    }

    private void afterStopClue(FollowClue clue) {
        String vin = clue.getVin();
        Long groupId = clue.getGroupId();
        LocalDate originTime = clue.getOriginTime().plusYears(1L).toLocalDate();
        CustomerDetailDto customer = customerBizService.queryByFrameNo(vin, groupId);
        if (Objects.isNull(customer)) {
            return;
        }
        final FollowClue newClue = new FollowClue();
        newClue.setVin(vin);
        newClue.setPlateNo(customer.getPlateNo());
        newClue.setOriginTime(clue.getOriginTime().plusYears(1L));
        newClue.setClueState(ClueStatusEnum.WAITING);
        newClue.setClueType(clue.getClueType());
        newClue.setGroupId(groupId);
        newClue.setSuggestShopId(Objects.isNull(customer.getShopId()) ? clue.getSuggestShopId() : customer.getShopId());
        newClue.setSuggestMobile(StringUtils.isEmpty(customer.getMobile()) ? clue.getSuggestMobile() : customer.getMobile());

        settingBizService.querySettingByType(clue.getClueType(), SettingTypeEnum.FIRST_TRIGGER_TIME, groupId, customer.getBrandId())
                .ifPresent(r -> {
                    int detailValue = Optional.ofNullable(r.getDetailValue()).orElse(0);
                    SettingUnitEnum unitEnum = Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit()), "时间单位缺失");
                    LocalDateTime localDateTime = calTime(originTime.atStartOfDay(), unitEnum, detailValue * -1);
                    newClue.setStartTime(localDateTime);
                });

        settingBizService.querySettingByType(clue.getClueType(), SettingTypeEnum.FAIL_TIME, groupId, customer.getBrandId())
                .ifPresent(r -> {
                    int detailValue = Optional.ofNullable(r.getDetailValue()).orElse(0);
                    SettingUnitEnum unitEnum = Objects.requireNonNull(SettingUnitEnum.ofValue(r.getUnit()), "时间单位缺失");
                    LocalDateTime localDateTime = calTime(originTime.atStartOfDay(), unitEnum, detailValue);
                    newClue.setEndTime(localDateTime);
                });
        followClueService.save(newClue);
        createFirstNotice(newClue, customer.getId(), customer.getBrandId());
    }
}