StammkundeBizService.java 10.4 KB
package cn.fw.valhalla.service.bus;

import cn.fw.valhalla.common.utils.DateUtil;
import cn.fw.valhalla.common.utils.GeoDistanceUtils;
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.StammkundeAnalyseDTO;
import cn.fw.valhalla.domain.enums.FollowTypeEnum;
import cn.fw.valhalla.domain.enums.TaskStateEnum;
import cn.fw.valhalla.domain.query.StammkundeAnalyseQueryVO;
import cn.fw.valhalla.domain.vo.customer.StammkundeAddressAnalyseVO;
import cn.fw.valhalla.domain.vo.customer.StammkundeAnalyseVO;
import cn.fw.valhalla.service.data.ClueTaskService;
import cn.fw.valhalla.service.data.CustomerService;
import cn.fw.valhalla.service.data.FollowClueService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

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

/**
 * @author : kurisu
 * @className : StammkundeBizService
 * @description : 保有客分析业务service
 * @date: 2021-01-21 15:29
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class StammkundeBizService {

    private final ClueTaskService clueTaskService;
    private final CustomerService customerService;
    private final FollowClueService followClueService;

    public List<StammkundeAnalyseVO> stammkundeList(final StammkundeAnalyseQueryVO queryVO) {
        boolean verifyPoi = Objects.nonNull(queryVO.getLat()) && Objects.nonNull(queryVO.getLng());
        BV.isTrue(verifyPoi, () -> "中心点经纬度不正确");
        Double radius = queryVO.getRadius();
        boolean verifyRadius = Objects.nonNull(radius) && radius > 0;
        BV.isTrue(verifyRadius, () -> "半径范围不正确");
        BV.isTrue(radius <= 30000, () -> "半径范围不能大于30公里");

        preparePoint(queryVO);
        if (StringUtils.isNotBlank(queryVO.getTimeHorizon()) || Boolean.TRUE.equals(queryVO.getUnderway())) {
            verifyParamsTime(queryVO);
            Integer followType = queryVO.getFollowType();
            FollowTypeEnum typeEnum = FollowTypeEnum.ofValue(followType);
            BV.notNull(typeEnum, () -> "跟进类型不正确");
            boolean underway = Boolean.TRUE.equals(queryVO.getUnderway());
            TaskStateEnum stateEnum = underway ? TaskStateEnum.ONGOING : TaskStateEnum.DEFEAT;
            List<ClueTask> tasks = clueTaskService.list(Wrappers.<ClueTask>lambdaQuery()
                    .eq(ClueTask::getType, typeEnum)
                    .eq(ClueTask::getState, stateEnum)
                    .in(!CollectionUtils.isEmpty(queryVO.getShopIds()), ClueTask::getFollowShop, queryVO.getShopIds())
                    .between(!underway, ClueTask::getCloseTime, queryVO.getStartTime(), queryVO.getEndTime())
            );
            if (CollectionUtils.isEmpty(tasks)) {
                return new ArrayList<>();
            }
            fillCustomer(tasks, queryVO);
        }

        List<StammkundeAnalyseDTO> list = customerService.analyseList(queryVO);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        final GeoDistanceUtils.Poi centerPoint = new GeoDistanceUtils.Poi(queryVO.getLng().doubleValue(), queryVO.getLat().doubleValue());
        final double distance = queryVO.getRadius();
        return list.stream().filter(r -> GeoDistanceUtils.getDistanceByBd09(centerPoint, new GeoDistanceUtils.Poi(r.getLng().doubleValue(), r.getLat().doubleValue())) <= distance)
                .map(StammkundeAnalyseVO::with).collect(Collectors.toList());
    }

    public List<StammkundeAnalyseVO> allCustomerList(final StammkundeAnalyseQueryVO queryVO) {
        preparePoint(queryVO);
        List<StammkundeAnalyseDTO> list;
        if (StringUtils.isNotBlank(queryVO.getTimeHorizon()) || Boolean.TRUE.equals(queryVO.getUnderway())) {
            verifyParamsTime(queryVO);
            Integer followType = queryVO.getFollowType();
            FollowTypeEnum typeEnum = FollowTypeEnum.ofValue(followType);
            BV.notNull(typeEnum, () -> "跟进类型不正确");
            list = getFollowStammkundeList(queryVO);
        } else {
            list = customerService.analyseList(queryVO);
        }
        return list.stream().filter(r -> Objects.nonNull(r.getLat()) && Objects.nonNull(r.getLng())).map(StammkundeAnalyseVO::with).collect(Collectors.toList());
    }

    private List<StammkundeAnalyseDTO> getFollowStammkundeList(final StammkundeAnalyseQueryVO queryVO) {
        boolean underway = Boolean.TRUE.equals(queryVO.getUnderway());
        FollowTypeEnum typeEnum = FollowTypeEnum.ofValue(queryVO.getFollowType());
        TaskStateEnum stateEnum = underway ? TaskStateEnum.ONGOING : TaskStateEnum.DEFEAT;
        List<ClueTask> tasks = clueTaskService.list(Wrappers.<ClueTask>lambdaQuery()
                .eq(ClueTask::getType, typeEnum)
                .eq(ClueTask::getState, stateEnum)
                .in(!CollectionUtils.isEmpty(queryVO.getShopIds()), ClueTask::getFollowShop, queryVO.getShopIds())
                .between(!underway, ClueTask::getCloseTime, queryVO.getStartTime(), queryVO.getEndTime())
        );
        if (CollectionUtils.isEmpty(tasks)) {
            return new ArrayList<>();
        }
        queryVO.setShopIds(null);
        fillCustomer(tasks, queryVO);
        return customerService.analyseList(queryVO);
    }

    private List<StammkundeAddressAnalyseVO> transfer2VO(List<StammkundeAnalyseDTO> list, StammkundeAnalyseQueryVO queryVO) {
        if (queryVO.hasRange()) {
            final GeoDistanceUtils.Poi centerPoint = new GeoDistanceUtils.Poi(queryVO.getLng().doubleValue(), queryVO.getLat().doubleValue());
            final double distance = queryVO.getRadius();
            list = list.stream().filter(r -> GeoDistanceUtils.getDistanceByBd09(centerPoint, new GeoDistanceUtils.Poi(r.getLng().doubleValue(), r.getLat().doubleValue())) <= distance).collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<StammkundeAddressAnalyseVO> analyseList = new ArrayList<>();
        Map<String, List<StammkundeAnalyseDTO>> map = list.stream().collect(Collectors.groupingBy(StammkundeAnalyseDTO::getRegionCode));
        for (Map.Entry<String, List<StammkundeAnalyseDTO>> entry : map.entrySet()) {
            StammkundeAddressAnalyseVO vo = new StammkundeAddressAnalyseVO();
            vo.setQuantity(entry.getValue().size());
            StammkundeAnalyseDTO dto = entry.getValue().get(0);
            vo.setRegionCode(dto.getRegionCode());
            vo.setRegionName(dto.getRegionName());
            analyseList.add(vo);
        }
        return analyseList;
    }


    private void verifyParamsTime(final StammkundeAnalyseQueryVO queryVO) {
        String timeHorizon = queryVO.getTimeHorizon();
        if (!Boolean.TRUE.equals(queryVO.getUnderway())) {
            BV.isNotBlank(timeHorizon, "时间范围不能为空");
            String[] times = timeHorizon.split(",");
            BV.isTrue(times.length > NumberUtils.INTEGER_ZERO, () -> "时间范围不正确");

            if (StringUtils.isNotBlank(times[0]) && NumberUtils.isDigits(times[0])) {
                LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(times[0])).atZone(ZoneId.systemDefault()).toLocalDateTime();
                queryVO.setStartTime(DateUtil.getBeginInTime(DateUtil.localDateTime2Date(localDateTime)));
            }
            if (times.length >= 2) {
                if (StringUtils.isNotBlank(times[1]) && NumberUtils.isDigits(times[1])) {
                    LocalDateTime localDateTime = Instant.ofEpochMilli(NumberUtils.toLong(times[1])).atZone(ZoneId.systemDefault()).toLocalDateTime();
                    queryVO.setEndTime(DateUtil.getEndInTime(DateUtil.localDateTime2Date(localDateTime)));
                }
            }
        }
    }


    private void preparePoint(final StammkundeAnalyseQueryVO queryVO) {
        Double radius = queryVO.getRadius();
        if (Objects.isNull(radius) || radius <= 0) {
            return;
        }
        BigDecimal lat = queryVO.getLat();
        BigDecimal lng = queryVO.getLng();
        boolean bool = Objects.nonNull(lat) && Objects.nonNull(lng);
        if (!bool) {
            return;
        }
        GeoDistanceUtils.Square square = GeoDistanceUtils.calSquarePoint(new GeoDistanceUtils.Poi(lng.doubleValue(), lat.doubleValue()), radius);
        double minLat = square.getRightBottomPoint().getLatitude();
        double maxLat = square.getLeftTopPoint().getLatitude();

        double minLng = square.getLeftBottomPoint().getLongitude();
        double maxLng = square.getRightTopPoint().getLongitude();

        queryVO.setMinLat(BigDecimal.valueOf(minLat));
        queryVO.setMaxLat(BigDecimal.valueOf(maxLat));
        queryVO.setMinLng(BigDecimal.valueOf(minLng));
        queryVO.setMaxLng(BigDecimal.valueOf(maxLng));
    }

    private void fillCustomer(List<ClueTask> taskList, StammkundeAnalyseQueryVO queryVO) {
        Set<Long> clueIdArr = taskList.stream().map(ClueTask::getClueId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(clueIdArr)) {
            return;
        }
        List<FollowClue> list = followClueService.list(Wrappers.<FollowClue>lambdaQuery()
                .eq(FollowClue::getGroupId, queryVO.getGroupId())
                .in(FollowClue::getId, clueIdArr)
        );
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Set<String> vinArr = list.stream().map(FollowClue::getVin).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(vinArr)) {
            return;
        }
        List<Customer> custList = customerService.list(Wrappers.<Customer>lambdaQuery()
                .eq(Customer::getGroupId, queryVO.getGroupId())
                .in(Customer::getFrameNo, vinArr)
        );
        if (CollectionUtils.isEmpty(custList)) {
            return;
        }
        Set<Long> customerIds = custList.stream().map(Customer::getId).collect(Collectors.toSet());
        queryVO.setCustomerIds(customerIds);
    }
}