EvalRewardRankCalculator.java 6.27 KB
package cn.fw.morax.service.biz.calculator.eval.reward;

import cn.fw.morax.common.utils.PublicUtil;
import cn.fw.morax.domain.bo.eval.EvalGroupUserShop;
import cn.fw.morax.domain.db.eval.*;
import cn.fw.morax.domain.enums.*;
import cn.fw.morax.service.biz.CommonService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sun.org.apache.regexp.internal.RE;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author jiangchao
 * @des: 排名正负激励
 * @date 2023/2/1 11:03
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class EvalRewardRankCalculator extends EvalRewardBaseCalculator {

    private final CommonService commonService;

    @Override
    public EvalRewardCalMethodEnum getCalMethod() {
        return EvalRewardCalMethodEnum.RANK;
    }

    @Override
    public BigDecimal calculate(EvalGroupUserShop param, EvalGroupReward rewardBO) {
        return null;
    }

    @Override
    public void calculateGroup(List<EvalGroupUserShop> userShops, EvalGroupReward reward) {
        userShops = userShops.stream().filter(userShop -> Boolean.FALSE.equals(userShop.getIgnored())).collect(Collectors.toList());
        if (PublicUtil.isEmpty(userShops)) {
            return;
        }
        initReward(userShops);
        final Long evalGroupRewardId = reward.getId();
        RankTypeEnum rankType = reward.getRankType();
        List<EvalGroupRewardPrecondition> preconditions = queryPrecondition(evalGroupRewardId);
        List<EvalGroupRewardParam> params = queryProjectParam(evalGroupRewardId, ParamTypeEnum.LADDER);
        if (CollectionUtils.isEmpty(params)) {
            return;
        }

        //计算排名
        List<EvalGroupRewardRankLog> rankLogs = calculateRankParamValue(userShops, evalGroupRewardId, params);
        Collections.sort(rankLogs);
        commonService.calcRank(rankLogs);
        saveRankLogs(evalGroupRewardId, rankLogs, RankIndicatorTypeEnum.REWARD_COMMISSION);
        Map<Long, EvalGroupUserShop> poolUserShopMap = userShops.stream().collect(Collectors.toMap(EvalGroupUserShop::getPoolId,
                Function.identity(), (v1, v2) -> v1));

        //计算金额
        final BigDecimal personCount = BigDecimal.valueOf(userShops.size());
        List<EvalGroupRewardLadders> ladders = queryRewardLadders(evalGroupRewardId);
        for (EvalGroupRewardLadders ladder : ladders) {
            final BigDecimal money = ladder.getMoney();

            List<EvalGroupRewardRankLog> matchRankLogs = matchRank(rankType, personCount, ladder, rankLogs);
            updateHitRankLog(matchRankLogs);

            for (EvalGroupRewardRankLog rankLog : matchRankLogs) {
                EvalGroupUserShop userShop = poolUserShopMap.get(rankLog.getPoolId());
                boolean examined = examinePrecondition(userShop, preconditions);
                if (!examined) {
                    userShop.setEvalGroupRewardAmount(BigDecimal.ZERO);
                    continue;
                }
                userShop.setEvalGroupRewardAmount(money);
                BigDecimal hitCommissionValue = rankLog.getReachValue();
                clearProjectHitLog(evalGroupRewardId, userShop);
                saveProjectHitLog(evalGroupRewardId, userShop, log -> {
                    log.setRewardValue(money);
                    log.setEvalGroupRewardLaddersId(ladder.getId());
                    log.setHitLadderValue(hitCommissionValue);
                    log.setHitCommissionValue(hitCommissionValue);
                });
            }
        }

    }

    /**
     * 匹配排名
     *
     * @param rankType
     * @param personCount
     * @param ladder
     * @param rankLogs
     * @return
     */
    public List<EvalGroupRewardRankLog> matchRank(final RankTypeEnum rankType,
                                                      final BigDecimal personCount,
                                                      EvalGroupRewardLadders ladder,
                                                      List<EvalGroupRewardRankLog> rankLogs) {
        BigDecimal lower = ladder.getLower();
        BigDecimal upper = ladder.getUpper();
        RankOrderTypeEnum rankOrderType = ladder.getRankOrderType();
        Integer startIndex ;
        Integer endIndex ;

        //百分比
        if (RankTypeEnum.PERCENT.equals(rankType)) {
            if (RankOrderTypeEnum.NEGATIVE.equals(rankOrderType)) {
                lower = BigDecimal.ONE.subtract(ladder.getUpper());
                upper = BigDecimal.ONE.subtract(ladder.getLower());
            }
            startIndex = lower.multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue();
            endIndex = upper.multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue();

            if (startIndex > endIndex) {
                return new ArrayList<>();
            }

            Integer finalEndIndex = endIndex,finalStartIndex = startIndex;
            List<EvalGroupRewardRankLog> matchRankLogs = rankLogs.stream().filter(rankLog -> {
                return rankLog.getRank() > finalStartIndex && rankLog.getRank() <= finalEndIndex;
            }).collect(Collectors.toList());
            return matchRankLogs;
        }

        //名次
        if (RankOrderTypeEnum.NEGATIVE.equals(rankOrderType)) {
            startIndex = personCount.subtract(upper).intValue() + 1;
            endIndex = personCount.subtract(lower).intValue() + 1;
        } else {
            startIndex = ladder.getLower().intValue();
            endIndex = ladder.getUpper().intValue();
        }

        if (startIndex > endIndex) {
            return new ArrayList<>();
        }

        Integer finalEndIndex = endIndex,finalStartIndex = startIndex;
        List<EvalGroupRewardRankLog> matchRankLogs = rankLogs.stream().filter(rankLog -> {
            return rankLog.getRank() >= finalStartIndex && rankLog.getRank() <= finalEndIndex;
        }).collect(Collectors.toList());

        return matchRankLogs;
    }


}