CustomerRetentionRatioBizService.java 12.9 KB
package cn.fw.valhalla.service.bus;

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.CustomerReachLog;
import cn.fw.valhalla.domain.db.follow.ClueTask;
import cn.fw.valhalla.domain.db.pool.StammkundePool;
import cn.fw.valhalla.domain.db.report.CustomerRetentionRatio;
import cn.fw.valhalla.domain.enums.*;
import cn.fw.valhalla.rpc.ehr.EhrRpcService;
import cn.fw.valhalla.rpc.ehr.dto.StaffInfoDTO;
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.data.ClueTaskService;
import cn.fw.valhalla.service.data.CustomerReachLogService;
import cn.fw.valhalla.service.data.CustomerRetentionRatioService;
import cn.fw.valhalla.service.data.StammkundePoolService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Stream;

/**
 * @author : kurisu
 * @className : CustomerRetentionRatioBizService
 * @description : 客户保持率
 * @date: 2020-11-24 15:59
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CustomerRetentionRatioBizService {
    private final OopService oopService;
    private final UserService userService;
    private final EhrRpcService ehrRpcService;
    private final CustomerRetentionRatioService customerRetentionRatioService;
    private final StammkundePoolService stammkundePoolService;
    private final ClueTaskService clueTaskService;
    private final CustomerReachLogService customerReachLogService;

    @Transactional(rollbackFor = Exception.class)
    public void extracting(Date nowDate) {
        log.info("开始抽取保有客保持率数据,日期:{}", DateUtil.getStringDateShort(nowDate));
        Stream.of(1L, 2L).forEach(groupId -> {
            List<StammkundePool> pools = Optional.ofNullable(stammkundePoolService.list(Wrappers.<StammkundePool>query()
                    .select("DISTINCT shop_id").eq("group_id", groupId))
            ).orElse(new ArrayList<>());
            List<ShopDTO> allShops = Optional.ofNullable(oopService.getAllShops(groupId)).orElse(new ArrayList<>());
            Set<ShopInfo> set = new HashSet<>();
            for (StammkundePool pool : pools) {
                ShopDTO shop = oopService.shop(pool.getShopId());
                if (Objects.nonNull(shop)) {
                    set.add(new ShopInfo(pool.getShopId(), shop.getShortName()));
                } else {
                    set.add(new ShopInfo(pool.getShopId(), String.valueOf(pool.getShopId())));
                }
            }
            for (ShopDTO allShop : allShops) {
                set.add(new ShopInfo(allShop.getId(), allShop.getShortName()));
            }
            if (CollectionUtils.isEmpty(set)) {
                return;
            }
            Timestamp day = DateUtil.getExpiredDay(nowDate, -1);
            customerRetentionRatioService.removeByDate(DateUtil.startDate(day));
            for (ShopInfo shop : set) {
                if (146L == shop.getId()) {
                    continue;
                }
                extractingPerson(shop, day);
            }
        });
    }

    private void extractingPerson(ShopInfo shop, Date nowDate) {
        final String dayString = DateUtil.getStringDateShort(nowDate);
        Date monthStart = DateUtil.localDateTime2Date(DateUtil.date2LocalDate(nowDate).minusYears(1L).atStartOfDay());
        final String monthStartStr = DateUtil.getStringDateShort(monthStart);
        List<StammkundePool> pools = Optional.ofNullable(stammkundePoolService.list(Wrappers.<StammkundePool>query()
                        .select("DISTINCT adviser_id", "adviser_name")
                        .eq("pool_status", 1)
                        .eq("shop_id", shop.getId())
                        .apply("(DATE_FORMAT(reject_time, '%Y-%m-%d') >= {0} or reject_time is null) and DATE_FORMAT(activation_time, '%Y-%m-%d') <= {1}", monthStartStr, dayString)
                )
        ).orElse(new ArrayList<>());
        List<PostUserDTO> userDTOS = Optional.ofNullable(userService.getUserByRole(shop.getId(), RoleCode.FWGW)).orElse(new ArrayList<>());
        Set<UserInfo> set = new HashSet<>();
        for (StammkundePool pool : pools) {
            Long adviserId = pool.getAdviserId();
            String adviserName = pool.getAdviserName();
            if (StringUtils.isEmpty(adviserName)) {
                StaffInfoDTO staffInfoDTO = ehrRpcService.queryStaffInfo(adviserId);
                adviserName = Objects.nonNull(staffInfoDTO) ? staffInfoDTO.getName() : adviserName;
            }
            set.add(new UserInfo(adviserId, adviserName));
        }
        for (PostUserDTO pool : userDTOS) {
            set.add(new UserInfo(pool.getUserId(), pool.getUserName()));
        }
        if (CollectionUtils.isEmpty(set)) {
            return;
        }
        List<CustomerRetentionRatio> list = new ArrayList<>();
        for (UserInfo userInfo : set) {
            fillPersonData(shop, userInfo, nowDate, list);
        }
        customerRetentionRatioService.saveBatch(list);
    }

    private void fillPersonData(ShopInfo shop, UserInfo userInfo, Date nowDate, List<CustomerRetentionRatio> list) {
        YearMonth yearMonth = YearMonth.from(DateUtil.date2LocalDate(nowDate));
        Date monthStart = DateUtil.localDateTime2Date(yearMonth.atDay(1).atStartOfDay());
        CustomerRetentionRatio ratio = new CustomerRetentionRatio();
        ratio.setDataDate(nowDate);
        ratio.setDimensions(1);
        ratio.setUserId(userInfo.getUserId());
        ratio.setUserName(userInfo.getUserName());
        ratio.setShopId(shop.getId());
        ratio.setShopName(shop.getName());
        int reachCount = customerReachLogService.count(Wrappers.<CustomerReachLog>lambdaUpdate()
                .eq(CustomerReachLog::getAdviserId, userInfo.getUserId())
                .eq(CustomerReachLog::getShopId, shop.getId())
                .gt(CustomerReachLog::getArrivalTime, monthStart)
                .lt(CustomerReachLog::getArrivalTime, DateUtil.getEndInTime(nowDate))
        );
        ratio.setReachNum(reachCount);
        StammkundePool pool = firstOne(userInfo.getUserId(), shop.getId());
        if (Objects.isNull(pool)) {
            ratio.setInitialNum(0);
            ratio.setDefeatNum(0);
            List<CustomerRetentionRatio> allZero = createAllZero(ratio);
            list.addAll(allZero);
        } else {
            int initialNum = initialNum(userInfo.getUserId(), shop.getId(), nowDate);
            ratio.setInitialNum(initialNum);
            ratio.setPublicNum(publicNum(userInfo.getUserId(), shop.getId(), nowDate));
            for (DefeatReasonEnum reasonEnum : DefeatReasonEnum.values()) {
                CustomerRetentionRatio r = new CustomerRetentionRatio();
                BeanUtils.copyProperties(ratio, r);
                r.setType(reasonEnum);
                r.setDefeatNum(defeatNum(userInfo.getUserId(), shop.getId(), reasonEnum, nowDate));
                list.add(r);
            }
        }
    }

    private List<CustomerRetentionRatio> createAllZero(CustomerRetentionRatio ratio) {
        DefeatReasonEnum[] values = DefeatReasonEnum.values();
        List<CustomerRetentionRatio> list = new ArrayList<>(values.length);
        for (DefeatReasonEnum reasonEnum : values) {
            CustomerRetentionRatio r = new CustomerRetentionRatio();
            BeanUtils.copyProperties(ratio, r);
            r.setType(reasonEnum);
            list.add(r);
        }
        return list;
    }

    private StammkundePool firstOne(Long userId, Long shopId) {
        return stammkundePoolService.getOne(Wrappers.<StammkundePool>lambdaQuery()
                .eq(Objects.nonNull(userId), StammkundePool::getAdviserId, userId)
                .eq(StammkundePool::getPoolStatus, StammkundeStatusEnum.KUNDE)
                .eq(StammkundePool::getShopId, shopId)
                .orderByAsc(StammkundePool::getActivationTime)
                .last(" limit 1")
        );
    }

    private int initialNum(Long userId, Long shopId, Date expire) {
        final Date endInTime = DateUtil.getEndInTime(expire);
        return stammkundePoolService.count(Wrappers.<StammkundePool>lambdaQuery()
                .eq(StammkundePool::getAdviserId, userId)
                .eq(StammkundePool::getPoolStatus, StammkundeStatusEnum.KUNDE)
                .eq(StammkundePool::getShopId, shopId)
                .le(StammkundePool::getActivationTime, endInTime)
                .and(w1 -> w1.gt(StammkundePool::getRejectTime, endInTime).or().isNull(StammkundePool::getRejectTime))
        );
    }

    private int publicNum(Long userId, Long shopId, Date nowDate) {
        Date endDay = DateUtil.getEndInTime(nowDate);
        return stammkundePoolService.count(Wrappers.<StammkundePool>lambdaQuery()
                .eq(StammkundePool::getAdviserId, userId)
                .eq(StammkundePool::getSources, StammkundeSourcesEnum.PUBLIC_POOL)
                .eq(StammkundePool::getPoolStatus, StammkundeStatusEnum.KUNDE)
                .eq(StammkundePool::getShopId, shopId)
                .le(StammkundePool::getActivationTime, endDay)
        );
    }

    private int twiceNum(Long userId, Long shopId, Date preMonthEndDay, Date nowDate, FollowTypeEnum typeEnum) {
        Date endDay = DateUtil.getEndInTime(nowDate);
        return clueTaskService.count(Wrappers.<ClueTask>lambdaQuery()
                .eq(ClueTask::getState, TaskStateEnum.COMPLETE)
                .eq(ClueTask::getRedistribution, Boolean.TRUE)
                .eq(ClueTask::getType, typeEnum)
                .eq(ClueTask::getFollowShop, shopId)
                .eq(ClueTask::getFollowUser, userId)
                .gt(ClueTask::getCloseTime, preMonthEndDay)
                .le(ClueTask::getCloseTime, endDay)
        );
    }

    private int defeatNum(Long userId, Long shopId, DefeatReasonEnum reason, Date nowDate) {
        LocalDateTime yearAgo = DateUtil.date2LocalDate(nowDate).minusYears(1L).atStartOfDay();
        Date yearAgoTime = DateUtil.localDateTime2Date(yearAgo);
        Date endDay = DateUtil.getEndInTime(nowDate);
        return stammkundePoolService.count(Wrappers.<StammkundePool>lambdaQuery()
                .eq(StammkundePool::getAdviserId, userId)
                .eq(StammkundePool::getPoolStatus, StammkundeStatusEnum.KUNDE)
                .eq(StammkundePool::getShopId, shopId)
                .eq(StammkundePool::getAktiv, Boolean.FALSE)
                .eq(StammkundePool::getReason, reason)
                .gt(StammkundePool::getRejectTime, yearAgoTime)
                .le(StammkundePool::getRejectTime, endDay)

        );
    }

    class UserInfo {
        private Long userId;
        private String userName;

        public UserInfo(Long userId, String userName) {
            this.userId = userId;
            this.userName = userName;
        }

        public Long getUserId() {
            return userId;
        }

        public void setUserId(Long userId) {
            this.userId = userId;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            UserInfo userInfo = (UserInfo) o;
            return Objects.equals(userId, userInfo.userId) && Objects.equals(userName, userInfo.userName);
        }

        @Override
        public int hashCode() {
            return Objects.hash(userId, userName);
        }
    }

    class ShopInfo {
        private Long id;
        private String name;

        public ShopInfo(Long id, String name) {
            this.id = id;
            this.name = name;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            ShopInfo shopInfo = (ShopInfo) o;
            return Objects.equals(id, shopInfo.id) && Objects.equals(name, shopInfo.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, name);
        }
    }
}