PubFollowBizService.java 11 KB
package cn.fw.valhalla.service.bus.pub;

import cn.fw.common.constant.CommonConstant;
import cn.fw.valhalla.common.utils.StringUtils;
import cn.fw.valhalla.common.utils.ThreadPoolUtil;
import cn.fw.valhalla.domain.db.customer.Customer;
import cn.fw.valhalla.domain.db.customer.CustomerBaseInfo;
import cn.fw.valhalla.domain.db.follow.ClueTask;
import cn.fw.valhalla.domain.db.pool.PublicPool;
import cn.fw.valhalla.domain.db.pub.PubCluePool;
import cn.fw.valhalla.domain.enums.*;
import cn.fw.valhalla.domain.vo.pool.PubPoolSimpleVO;
import cn.fw.valhalla.rpc.oop.OopService;
import cn.fw.valhalla.rpc.oop.dto.ShopDTO;
import cn.fw.valhalla.service.bus.follow.strategy.impl.PubFollowStrategy;
import cn.fw.valhalla.service.data.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

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

/**
 * 公共池跟进处理
 *
 * @author : kurisu
 * @version : 1.0
 * @className : PubFollowBizService
 * @description : 公共池跟进处理
 * @date : 2023-03-17 17:23
 */
@Slf4j
@Service
public class PubFollowBizService {
    private final PubCluePoolService pubCluePoolService;
    private final PublicPoolService publicPoolService;
    private final StammkundePoolService stammkundePoolService;
    private final CustomerService customerService;
    private final CustomerBaseInfoService customerBaseInfoService;
    private final ClueTaskService clueTaskService;
    private final StringRedisTemplate stringRedisTemplate;
    private final OopService oopService;
    private final PubFollowStrategy pubFollowStrategy;
    @Value("${follow.todo.PubFollowCode}")
    @Getter(AccessLevel.PRIVATE)
    private String pubFollowCode;

    @Value("${spring.cache.custom.global-prefix}:role-change-need-close:clue")
    @Getter(AccessLevel.PRIVATE)
    private String roleChangeNeedCloseClueKey;

    @Autowired
    public PubFollowBizService(final PubCluePoolService pubCluePoolService,
                               final PublicPoolService publicPoolService,
                               final StammkundePoolService stammkundePoolService,
                               final CustomerService customerService,
                               final CustomerBaseInfoService customerBaseInfoService,
                               final ClueTaskService clueTaskService,
                               final StringRedisTemplate stringRedisTemplate,
                               final OopService oopService,
                               final PubFollowStrategy pubFollowStrategy) {
        this.pubCluePoolService = pubCluePoolService;
        this.publicPoolService = publicPoolService;
        this.stammkundePoolService = stammkundePoolService;
        this.customerService = customerService;
        this.customerBaseInfoService = customerBaseInfoService;
        this.clueTaskService = clueTaskService;
        this.stringRedisTemplate = stringRedisTemplate;
        this.oopService = oopService;
        this.pubFollowStrategy = pubFollowStrategy;
    }

    /**
     * 人员角色变动或缓存需要战败的vin
     *
     * @param userId
     * @param shopId
     */
    public void onRoleChange(Long userId, Long shopId) {
        List<PubCluePool> list = pubCluePoolService.list(Wrappers.<PubCluePool>lambdaQuery()
                .eq(PubCluePool::getAdviserId, userId)
                .eq(PubCluePool::getState, PublicClueStateEnum.ONGOING)
        );
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        BoundSetOperations<String, String> setOps = stringRedisTemplate.boundSetOps(getRoleChangeNeedCloseClueKey());
        for (PubCluePool pool : list) {
            setOps.add(String.valueOf(pool.getId()));
        }
    }

    /**
     * 开始线索
     *
     * @param pool
     */
    @Transactional(rollbackFor = Exception.class)
    public void startClue(PubCluePool pool) {
        pubFollowStrategy.startClue(pool);
        pool.setBegun(Boolean.TRUE);
        pubCluePoolService.updateById(pool);
    }

    /**
     * 关闭线索
     *
     * @param str
     */
    @Transactional(rollbackFor = Exception.class)
    public void closeClue(String str) {
        String[] dataArr = str.split(CommonConstant.Symbol.AT);
        if (dataArr.length < 4) {
            log.info("关闭公共池线索失败:{}", str);
            return;
        }
        String vin = dataArr[0];
        Long adviserId = Long.parseLong(dataArr[1]);
        Long groupId = Long.parseLong(dataArr[2]);
        Long shopId = Long.parseLong(dataArr[3]);

        PubCluePool pool = pubCluePoolService.getOne(Wrappers.<PubCluePool>lambdaQuery()
                        .eq(PubCluePool::getVin, vin)
                        .eq(PubCluePool::getGroupId, groupId)
                        .eq(PubCluePool::getState, PublicClueStateEnum.ONGOING)
                , Boolean.FALSE
        );

        if (Objects.isNull(pool)) {
            return;
        }
        if (pool.getAdviserId().equals(adviserId)) {
            pubFollowStrategy.clueConvertSuccess(pool);
            return;
        }
        pubFollowStrategy.clueConvertFailed(pool, adviserId, shopId);

    }

    /**
     * 查询最近分配的20条线索
     *
     * @param userId
     * @param groupId
     * @return
     */
    public List<PubPoolSimpleVO> log(Long userId, Long groupId) {
        List<PubCluePool> list = pubCluePoolService.list(Wrappers.<PubCluePool>lambdaQuery()
                .eq(PubCluePool::getAdviserId, userId)
                .eq(PubCluePool::getGroupId, groupId)
                .orderByDesc(PubCluePool::getStartTime)
                .last(" limit 20")
        );
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<PubPoolSimpleVO> simpleList = list.stream()
                .map(PubPoolSimpleVO::with)
                .collect(Collectors.toList());
        CompletableFuture<Void>[] futureArr = simpleList.stream()
                .map(pool -> CompletableFuture.runAsync(() -> {
                    Customer customer = customerService.queryByFrameNo(pool.getVin(), pool.getGroupId());
                    if (Objects.nonNull(customer)) {
                        pool.setPlateNo(customer.getPlateNo());
                        String brandName = StringUtils.isEmpty(customer.getBrandName()) ? "" : customer.getBrandName() + " ";
                        String seriesName = StringUtils.isEmpty(customer.getSeriesName()) ? "" : customer.getSeriesName() + " ";
                        String specName = StringUtils.isEmpty(customer.getSpecName()) ? "" : customer.getSpecName();
                        String carName = String.format("%s%s%s", brandName, seriesName, specName);
                        pool.setCarName(carName);
                    }
                }, ThreadPoolUtil.getInstance().getExecutor())).<CompletableFuture<Void>>toArray(CompletableFuture[]::new);

        try {
            CompletableFuture.allOf(futureArr).get();
        } catch (Exception e) {
            log.error("数据查询失败", e);
        }
        return simpleList;
    }

    /**
     * 角色变动结束线索
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public void roleChangeDefeatClue(String id) {
        PubCluePool pool = pubCluePoolService.getById(Long.valueOf(id));
        if (Objects.isNull(pool)) {
            return;
        }
        Customer customer = customerService.queryByFrameNo(pool.getVin(), pool.getGroupId());
        endClue(pool);
        if (Objects.nonNull(customer)) {
            customerRemoval(customer);
        }
    }

    /**
     * 结束线索
     *
     * @param pool
     */
    @Transactional(rollbackFor = Exception.class)
    public void endClue(PubCluePool pool) {
        ClueTask task = clueTaskService.getOne(Wrappers.<ClueTask>lambdaQuery()
                        .eq(ClueTask::getClueId, pool.getId())
                        .eq(ClueTask::getType, FollowTypeEnum.PL)
                        .eq(ClueTask::getState, TaskStateEnum.ONGOING)
                , Boolean.FALSE);

        if (Objects.nonNull(task)) {
            pubFollowStrategy.onRoleChangeCloseTask(task);
        }
        pool.setState(PublicClueStateEnum.DEFEAT);
        pool.setCloseTime(LocalDateTime.now());
        pool.setDefeatReason(TaskDefeatTypeEnum.D);
        pubCluePoolService.updateById(pool);
    }

    /**
     * 移除档案到公共池
     *
     * @param customer
     */
    private void customerRemoval(Customer customer) {
        PublicPool publicPool = createPublicPool(customer);
        publicPoolService.save(publicPool);
        stammkundePoolService.reject(customer.getId(), customer.getGroupId(), DefeatReasonEnum.RC);

        customerService.update(Wrappers.<Customer>lambdaUpdate()
                .set(Customer::getTemporary, null)
                .set(Customer::getShopId, null)
                .set(Customer::getAdviserId, null)
                .eq(Customer::getId, customer.getId())
        );

    }

    private PublicPool createPublicPool(Customer customer) {
        final Long shopId = Optional.ofNullable(customer.getLastArrivalShop()).orElse(customer.getShopId());
        ShopDTO shop = oopService.shop(shopId);
        BV.notNull(shop, () -> String.format("门店[%s]信息获取失败", shopId));
        String shopName = shop.getShortName();
        final Long baseId = customer.getBaseId();
        CustomerBaseInfo baseInfo = customerBaseInfoService.getById(baseId);
        BV.notNull(baseInfo, () -> String.format("档案车主信息获取失败[%s]", baseId));
        PublicPool pool = new PublicPool();
        pool.setCustomerId(customer.getId());
        pool.setCustomerName(baseInfo.getName());
        pool.setPlateNo(customer.getPlateNo());
        pool.setFrameNo(customer.getFrameNo());
        pool.setBrandId(customer.getBrandId());
        pool.setBrandName(customer.getBrandName());
        pool.setSeriesId(customer.getSeriesId());
        pool.setSeriesName(customer.getSeriesName());
        pool.setSpecId(customer.getSpecId());
        pool.setSpecName(customer.getSpecName());
        pool.setAddress(baseInfo.getAddress());
        pool.setCompany(baseInfo.getCompanyName());
        pool.setType(PublicPoolTypeEnum.RC);
        pool.setShopId(shopId);
        pool.setShopName(shopName);
        pool.setTimes(customer.getArrivalCount());
        pool.setReason(PublicPoolTypeEnum.RC.getName());
        pool.setGroupId(customer.getGroupId());
        return pool;
    }

}