RMFollowStrategy.java 12.1 KB
package cn.fw.valhalla.service.bus.follow.strategy.impl;

import cn.fw.valhalla.common.utils.DateUtil;
import cn.fw.valhalla.common.utils.MobileUtil;
import cn.fw.valhalla.domain.db.OriginalData;
import cn.fw.valhalla.domain.db.customer.Customer;
import cn.fw.valhalla.domain.db.follow.FollowRecord;
import cn.fw.valhalla.domain.db.follow.FollowRecordLog;
import cn.fw.valhalla.domain.db.follow.FollowTask;
import cn.fw.valhalla.domain.db.pool.CustomerCluePool;
import cn.fw.valhalla.domain.dto.CustomerDetailDto;
import cn.fw.valhalla.domain.dto.FollowAttachmentDTO;
import cn.fw.valhalla.domain.enums.AttTypeEnum;
import cn.fw.valhalla.domain.enums.ClueStatusEnum;
import cn.fw.valhalla.domain.enums.FollowTypeEnum;
import cn.fw.valhalla.domain.enums.SettingTypeEnum;
import cn.fw.valhalla.domain.vo.follow.*;
import cn.fw.valhalla.domain.vo.setting.SettingVO;
import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO;
import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
import cn.fw.valhalla.sdk.enums.DataTypeEnum;
import cn.fw.valhalla.sdk.param.ChangeAdviserReq;
import cn.fw.valhalla.service.bus.cust.CustomerChangeBizService;
import cn.fw.valhalla.service.bus.follow.strategy.AbstractFollowStrategy;
import cn.fw.valhalla.service.data.OriginalDataService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

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

/**
 * @author : kurisu
 * @className : RMFollowStrategy
 * @description : 流失客户策略
 * @date: 2020-08-17 10:48
 */
@Slf4j
@Component
public class RMFollowStrategy extends AbstractFollowStrategy {
    private final OriginalDataService originalDataService;
    private final CustomerChangeBizService changeBizService;

    @Autowired
    public RMFollowStrategy(final OriginalDataService originalDataService,
                            final CustomerChangeBizService changeBizService) {
        this.originalDataService = originalDataService;
        this.changeBizService = changeBizService;
    }

    @Override
    public FollowTypeEnum getFollowType() {
        return FollowTypeEnum.RM;
    }

    @Override
    public List<FollowTodoListVO> getList(Integer startIndex, Integer pageSize, Long userId) {
        List<FollowRecord> list = list(startIndex, pageSize, userId, getFollowType());
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<FollowTodoListVO> voList = new ArrayList<>();
        for (FollowRecord followRecord : list) {
            RMTodoListVO vo = new RMTodoListVO();
            vo.setId(followRecord.getId());
            vo.setTaskId(followRecord.getTaskId());
            vo.setCustomerId(followRecord.getCustomerId());
            vo.setDeadline(followRecord.getDeadline());
            CustomerDetailDto customerDetailDto = customerBizService.queryById(followRecord.getCustomerId());
            if (Objects.isNull(customerDetailDto)) {
                onCustomerIsNil(followRecord);
                continue;
            }
            vo.setName(customerDetailDto.getName());
            vo.setCarImage(customerDetailDto.getCarImage());
            vo.setPlateNo(customerDetailDto.getPlateNo());
            vo.setLastMileage(customerDetailDto.getCurrentMileage());
            OriginalData originalData = originalDataService.getOne(Wrappers.<OriginalData>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());
            }
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public FollowDetailVO getDetail(Long id) {
        FollowRecord followRecord = followRecordService.getById(id);
        BV.notNull(followRecord, "跟进记录不存在");
        FollowTask followTask = followTaskService.getById(followRecord.getTaskId());
        BV.notNull(followTask, "跟进信息不存在");
        RMDetailVO vo = assemble(followRecord.getCustomerId());
        int count = followRecordLogService.count(Wrappers.<FollowRecordLog>lambdaQuery()
                .eq(FollowRecordLog::getAttType, AttTypeEnum.SMART_PHONE)
                .eq(FollowRecordLog::getTaskId, followRecord.getTaskId())
        );
        vo.setHadCall(count > 0);
        vo.setId(followRecord.getId());
        vo.setTaskId(followRecord.getTaskId());
        vo.setDeadline(followRecord.getDeadline());
        queryTimes(followTask.getClueId(), vo);
        return vo;
    }

    @Override
    public List<FollowRecordVO> getRecordList(Long taskId) {
        return super.getRecordList(taskId);
    }

    @Override
    public void uploadAtt(FollowAttachmentDTO dto, Long userId) {
        super.uploadAtt(dto, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelFollowTask(Long customerId, Date time, Long groupId) {
        CustomerCluePool cluePool = customerCluePoolService.queryByRefererId(customerId, groupId, getFollowType());
        if (Objects.isNull(cluePool)) {
            return;
        }
        if (ClueStatusEnum.WAITING.equals(cluePool.getClueStatus())) {
            customerCluePoolService.removeById(cluePool.getId());
            followNoticeRecordService.removeByClueId(cluePool.getId());
        }
        if (ClueStatusEnum.ONGOING.equals(cluePool.getClueStatus())) {
            customerCluePoolService.removeById(cluePool.getId());
            followNoticeRecordService.removeByClueId(cluePool.getId());
            cancelFollowTodo(cluePool.getRefererId(), getFollowType());
        }
        //暂不考虑退单回滚的情况
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settingChanged(List<SettingVO> setting, Long groupId) {
        List<CustomerCluePool> poolList = customerCluePoolService.list(Wrappers.<CustomerCluePool>lambdaQuery()
                .eq(CustomerCluePool::getClueType, getFollowType())
                .eq(CustomerCluePool::getGroupId, groupId)
                .eq(CustomerCluePool::getClueStatus, ClueStatusEnum.WAITING)
        );

        if (CollectionUtils.isEmpty(poolList)) {
            return;
        }
        updateClue(poolList, setting);

        SettingVO noticeSetting = setting.stream().filter(r -> SettingTypeEnum.FIRST_NOTICE_TIME.getValue().equals(r.getType())).findFirst().orElse(new SettingVO());
        updateNoticeRecord(poolList, noticeSetting);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean origin2task(OriginalData originalData) throws Exception {
        Customer customer = customerService.queryById(originalData.getCustomerId());
        BV.notNull(customer, () -> "档案不存在");
        CustomerCluePool cluePool = customerCluePoolService.queryByRefererId(customer.getId(), customer.getGroupId(), getFollowType());
        completeClue(cluePool, originalData);
        boolean bool = Objects.isNull(customer.getAdviserId()) || Objects.isNull(customer.getShopId());
        if (Objects.nonNull(originalData.getShopId()) && Objects.nonNull(originalData.getUserId()) && bool) {
            ChangeAdviserReq req = new ChangeAdviserReq();
            req.setAdviserId(originalData.getUserId());
            req.setCusId(customer.getId());
            if (changeBizService.changeAdviser(req)) {
                customer.setAdviserId(originalData.getUserId());
                customer.setShopId(originalData.getShopId());
                bool = false;
            }
        }
        BV.isFalse(bool, () -> "档案信息不完整");

        CustomerCluePool clue = createClueInfo(originalData, getFollowType(), customer);
        customerCluePoolService.save(clue);
        createFirstNotice(clue, originalData.getGenerateTime());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void overdueProcessing(FollowRecord record) {
        super.overdueProcessing(record);
    }

    @Override
    public FollowDetailVO followPoolDetail(FollowTask task) {
        RMDetailVO vo = assemble(task.getCustomerId());
        vo.setTaskId(task.getId());
        queryTimes(task.getClueId(), vo);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTask(Long customerId) {
        Customer customer = customerService.queryById(customerId);
        if (Objects.isNull(customer) || Objects.isNull(customer.getAdviserId()) || Objects.isNull(customer.getShopId())) {
            return;
        }
        CustomerCluePool cluePool = customerCluePoolService.queryByRefererId(customerId, customer.getGroupId(), getFollowType());
        super.renewalTask(customer, cluePool);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void completeClue(CustomerCluePool cluePool, OriginalData originalData) {
        if (Objects.isNull(cluePool)) {
            return;
        }
        if (ClueStatusEnum.COMPLETE.equals(cluePool.getClueStatus()) || ClueStatusEnum.FAILURE.equals(cluePool.getClueStatus())) {
            return;
        }
        if (ClueStatusEnum.WAITING.equals(cluePool.getClueStatus())) {
            customerCluePoolService.removeById(cluePool.getId());
            return;
        }
        LocalDateTime deadline = DateUtil.date2LocalDateTime(cluePool.getDeadline());
        if (deadline.isAfter(DateUtil.date2LocalDateTime(originalData.getGenerateTime()))) {
            cluePool.setFinishShopId(originalData.getShopId());
            cluePool.setFinishUserId(originalData.getUserId());
            UserInfoDTO user = userService.user(originalData.getUserId());
            if (Objects.nonNull(user)) {
                cluePool.setFinishUserName(user.getUserName());
            }
            ShopDTO shop = oopService.shop(originalData.getShopId());
            if (Objects.nonNull(shop)) {
                cluePool.setFinishShopName(shop.getShortName());
            }
            cluePool.setCloseTime(originalData.getGenerateTime());
            cluePool.setClueStatus(ClueStatusEnum.COMPLETE);
            customerCluePoolService.updateById(cluePool);
            completeTask(cluePool);
        }
    }


    @Override
    public RMDetailVO assemble(Long customerId) {
        CustomerDetailDto customerDetailDto = customerBizService.queryById(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());
        vo.setCusLevel(customerDetailDto.getCusLevel());
        vo.setArrivalCount(customerDetailDto.getArrivalCount());
        OriginalData originalData = originalDataService.getOne(Wrappers.<OriginalData>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;
    }
}