KpiAbsBaseCalculator.java 13.9 KB
package cn.fw.morax.service.biz.calculator.kpi;

import cn.fw.morax.domain.bo.kpi.KpiIndicatorBO;
import cn.fw.morax.domain.db.kpi.*;
import cn.fw.morax.domain.enums.IndicatorTypeEnum;
import cn.fw.morax.domain.enums.ScoreWayEnum;
import cn.fw.morax.domain.enums.TargetCalcTypeEnum;
import cn.fw.morax.domain.enums.TargetTypeEnum;
import cn.fw.morax.service.biz.calculator.Calculator;
import cn.fw.morax.service.data.kpi.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Consumer;

/**
 * @author : kurisu
 * @version : 1.0
 * @className : KpiBaseCalculator
 * @description : 绩效计算器
 * @date : 2022-04-18 11:28
 */
@Slf4j
public abstract class KpiAbsBaseCalculator implements Calculator<KpiGroupUser, KpiIndicatorBO, BigDecimal> {
    @Autowired
    protected KpiGroupIndicatorHitLogService kpiGroupIndicatorHitLogService;
    @Autowired
    protected IndicatorUserValueService indicatorUserValueService;
    @Autowired
    protected KpiGroupIndicatorParamService kpiGroupIndicatorParamService;
    @Autowired
    protected KpiGroupIndicatorPreconditionService kpiGroupIndicatorPreconditionService;
    @Autowired
    protected KpiGroupIndicatorPreconditionHitLogService preconditionHitLogService;
    @Autowired
    protected KpiGroupIndicatorPreconditionLaddersService preconditionLaddersService;
    @Autowired
    protected KpiGroupIndicatorTargetHitLogService kpiGroupIndicatorTargetHitLogService;

    public static void main(String[] args) {
        Set<Long> set = new HashSet<>();
        set.add(1L);
        set.add(2L);
        set.add(3L);
        String json = JSON.toJSONString(set);
        System.out.println(json);
        List<Long> set2 = JSON.parseArray(json, Long.class);
        System.out.println(set2.toString());
        System.out.println(Arrays.toString(set2.toArray()));
        String join = StringUtils.join(",", set);
        System.out.println(join);
    }

    /**
     * 获取设置类型
     *
     * @return
     */
    public abstract ScoreWayEnum getCalMethod();

    /**
     * 查询前置条件
     *
     * @param kpiGroupIndicatorId
     * @param kpiGroupId
     * @return
     */
    protected List<KpiGroupIndicatorPrecondition> queryPrecondition(Long kpiGroupIndicatorId, Long kpiGroupId) {
        List<KpiGroupIndicatorPrecondition> preList = kpiGroupIndicatorPreconditionService.list(Wrappers.<KpiGroupIndicatorPrecondition>lambdaQuery()
                .eq(KpiGroupIndicatorPrecondition::getKpiGroupIndicatorId, kpiGroupIndicatorId)
                .eq(KpiGroupIndicatorPrecondition::getKpiGroupId, kpiGroupId)
                .eq(KpiGroupIndicatorPrecondition::getYn, Boolean.TRUE)
                .orderByAsc(KpiGroupIndicatorPrecondition::getSort)
        );
        return Optional.ofNullable(preList).orElse(new ArrayList<>());
    }

    /**
     * 查询指标配置
     *
     * @param kpiGroupIndicatorId
     * @param kpiGroupId
     * @return
     */
    protected List<KpiGroupIndicatorParam> queryParam(Long kpiGroupIndicatorId, Long kpiGroupId) {
        List<KpiGroupIndicatorParam> list = kpiGroupIndicatorParamService.list(Wrappers.<KpiGroupIndicatorParam>lambdaQuery()
                .eq(KpiGroupIndicatorParam::getKpiGroupIndicatorId, kpiGroupIndicatorId)
                .eq(KpiGroupIndicatorParam::getKpiGroupId, kpiGroupId)
                .eq(KpiGroupIndicatorParam::getYn, Boolean.TRUE)
        );
        return Optional.ofNullable(list).orElse(new ArrayList<>());
    }

    /**
     * 查询指标值
     *
     * @param userId
     * @param groupId
     * @param dataDate
     * @param indicatorCode
     * @return
     */
    protected IndicatorUserValue queryValue(Long userId, Long groupId, LocalDate dataDate, String indicatorCode) {
        return indicatorUserValueService.getOne(Wrappers.<IndicatorUserValue>lambdaQuery()
                        .eq(IndicatorUserValue::getUserId, userId)
                        .eq(IndicatorUserValue::getIndicatorCode, indicatorCode)
                        .eq(IndicatorUserValue::getDataDate, dataDate)
                        .eq(IndicatorUserValue::getYn, Boolean.TRUE)
                        .eq(IndicatorUserValue::getGroupId, groupId)
                , Boolean.FALSE
        );
    }

    /**
     * 查询具体指标值
     *
     * @param indicatorCode
     * @param originalValue
     * @return
     */
    protected BigDecimal queryIndicatorValue(String indicatorCode, String originalValue) {
        BigDecimal value = BigDecimal.ZERO;
        try {
            JSONObject jsonObject = JSONObject.parseObject(originalValue);
            value = Optional.ofNullable(jsonObject.getBigDecimal(indicatorCode)).orElse(BigDecimal.ZERO);
        } catch (Exception e) {
            log.error("[{}]指标值转化失败", indicatorCode, e);
        }
        return value;
    }

    /**
     * 通过前置条件计算绩效得分系数
     *
     * @param list
     * @return
     */
    protected BigDecimal calcCoefficient(KpiGroupUser user, List<KpiGroupIndicatorPrecondition> list) {
        BigDecimal coefficient = BigDecimal.ONE;
        if (CollectionUtils.isEmpty(list)) {
            return coefficient;
        }
        final Long userId = user.getUserId();
        for (int i = 0; i < list.size(); i++) {
            KpiGroupIndicatorPrecondition precondition = list.get(i);
            TargetTypeEnum targetType = precondition.getTargetType();
            IndicatorUserValue userValue = queryValue(userId, user.getGroupId(), user.getDataDate(), precondition.getIndicatorCode());
            if (Objects.isNull(userValue)) {
                return BigDecimal.ZERO;
            }
            final BigDecimal originValue = queryIndicatorValue(userValue.getIndicatorCode(), userValue.getIndicatorValue());
            BigDecimal indicatorValue = originValue;
            if (!TargetTypeEnum.NO.equals(targetType)) {
                BigDecimal targetValue = precondition.getTargetValue();
                TargetCalcTypeEnum targetCalcType = precondition.getTargetCalcType();
                if (TargetCalcTypeEnum.TARGET_VALUE.equals(targetCalcType)) {
                    indicatorValue = indicatorValue.divide(targetValue, 4, RoundingMode.HALF_UP);
                } else {
                    BigDecimal difference = BigDecimal.ONE.subtract(targetValue);
                    if (BigDecimal.ZERO.compareTo(difference) == 0) {
                        difference = BigDecimal.ONE;
                    }
                    BigDecimal userDiffValue = indicatorValue.subtract(targetValue);
                    if (userDiffValue.compareTo(BigDecimal.ZERO) <= 0) {
                        indicatorValue = BigDecimal.ZERO;
                    } else {
                        indicatorValue = userDiffValue.divide(difference, 4, RoundingMode.HALF_UP);
                    }
                }

                saveTargetHitLog(user, precondition.getId(), IndicatorTypeEnum.PRE, originValue, indicatorValue);
            }
            coefficient = coefficient.multiply(coefficient(user, precondition.getId(), indicatorValue))
                    .divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
        }
        return coefficient;
    }

    protected BigDecimal coefficient(KpiGroupUser user, Long preconditionId, BigDecimal value) {
        KpiGroupIndicatorPreconditionLadders ladder = preconditionLaddersService.getOne(Wrappers.<KpiGroupIndicatorPreconditionLadders>lambdaQuery()
                        .eq(KpiGroupIndicatorPreconditionLadders::getPreconditionId, preconditionId)
                        .gt(KpiGroupIndicatorPreconditionLadders::getUpper, value)
                        .le(KpiGroupIndicatorPreconditionLadders::getLower, value)
                        .eq(KpiGroupIndicatorPreconditionLadders::getYn, Boolean.TRUE),
                Boolean.FALSE
        );
        if (Objects.isNull(ladder)) {
            savePreconditionHitLog(user, preconditionId, hitLog -> {
                hitLog.setPreconditionLaddersId(-1L);
                hitLog.setValue(value);
            });
            return BigDecimal.ZERO;
        }

        savePreconditionHitLog(user, preconditionId, hitLog -> {
            hitLog.setPreconditionLaddersId(ladder.getId());
            hitLog.setValue(value);
        });
        return ladder.getScorePercent();
    }

    /**
     * 计算最终的指标值
     *
     * @param paramList
     * @param user
     * @param kpiGroupIndicatorId
     * @return
     */
    protected BigDecimal calculateFinalIndValue(List<KpiGroupIndicatorParam> paramList, KpiGroupUser user, Long kpiGroupIndicatorId) {
        BigDecimal rate = BigDecimal.ZERO;
        if (CollectionUtils.isEmpty(paramList)) {
            log.info("指标[{}]配置不存在", kpiGroupIndicatorId);
            return rate;
        }
        for (KpiGroupIndicatorParam param : paramList) {
            IndicatorUserValue userValue = queryValue(user.getUserId(), user.getGroupId(), user.getDataDate(), param.getIndicatorCode());
            if (Objects.isNull(userValue)) {
                log.info("用户[{}]指标[{}]值不存在", user.getUserId(), kpiGroupIndicatorId);
                continue;
            }
            TargetTypeEnum targetType = param.getTargetType();
            final BigDecimal originValue = queryIndicatorValue(userValue.getIndicatorCode(), userValue.getIndicatorValue());
            BigDecimal indicatorValue = originValue;
            if (!TargetTypeEnum.NO.equals(targetType)) {
                BigDecimal targetValue = param.getTargetValue();
                TargetCalcTypeEnum targetCalcType = param.getTargetCalcType();
                if (TargetCalcTypeEnum.TARGET_VALUE.equals(targetCalcType)) {
                    indicatorValue = indicatorValue.divide(targetValue, 4, RoundingMode.HALF_UP);
                } else {
                    BigDecimal difference = BigDecimal.ONE.subtract(targetValue);
                    if (BigDecimal.ZERO.compareTo(difference) == 0) {
                        difference = BigDecimal.ONE;
                    }
                    BigDecimal userDiffValue = indicatorValue.subtract(targetValue);
                    if (userDiffValue.compareTo(BigDecimal.ZERO) <= 0) {
                        indicatorValue = BigDecimal.ZERO;
                    } else {
                        indicatorValue = userDiffValue.divide(difference, 4, RoundingMode.HALF_UP);
                    }
                }

                saveTargetHitLog(user, param.getId(), IndicatorTypeEnum.EXAMINE, originValue, indicatorValue);
            }
            boolean isCap = Boolean.TRUE.equals(param.getCap());
            BigDecimal proportion = param.getProportion();
            if (isCap) {
                indicatorValue = BigDecimal.ONE.compareTo(indicatorValue) > 0 ? indicatorValue : BigDecimal.ONE;
            }
            rate = rate.add(proportion.multiply(indicatorValue));
        }
        return rate;
    }

    protected void savePreconditionHitLog(KpiGroupUser user, Long preconditionId, Consumer<KpiGroupIndicatorPreconditionHitLog> consumer) {
        preconditionHitLogService.remove(Wrappers.<KpiGroupIndicatorPreconditionHitLog>lambdaQuery()
                .eq(KpiGroupIndicatorPreconditionHitLog::getUserId, user.getUserId())
                .eq(KpiGroupIndicatorPreconditionHitLog::getPreconditionId, preconditionId)
                .eq(KpiGroupIndicatorPreconditionHitLog::getDataDate, user.getDataDate())
                .eq(KpiGroupIndicatorPreconditionHitLog::getGroupId, user.getGroupId())
        );
        KpiGroupIndicatorPreconditionHitLog hitLog = new KpiGroupIndicatorPreconditionHitLog();
        hitLog.setPreconditionId(preconditionId);
        hitLog.setUserId(user.getUserId());
        hitLog.setDataDate(user.getDataDate());
        hitLog.setGroupId(user.getGroupId());
        if (consumer != null) {
            consumer.accept(hitLog);
        }
        preconditionHitLogService.save(hitLog);
    }

    protected void saveTargetHitLog(KpiGroupUser user, Long referId, IndicatorTypeEnum targetType, BigDecimal value, BigDecimal reachValue) {
        kpiGroupIndicatorTargetHitLogService.remove(Wrappers.<KpiGroupIndicatorTargetHitLog>lambdaQuery()
                .eq(KpiGroupIndicatorTargetHitLog::getUserId, user.getUserId())
                .eq(KpiGroupIndicatorTargetHitLog::getTargetType, targetType)
                .eq(KpiGroupIndicatorTargetHitLog::getDataDate, user.getDataDate())
                .eq(KpiGroupIndicatorTargetHitLog::getReferId, referId)
        );
        KpiGroupIndicatorTargetHitLog log = new KpiGroupIndicatorTargetHitLog();
        log.setReferId(referId);
        log.setTargetType(targetType);
        log.setUserId(user.getUserId());
        log.setValue(value);
        log.setReachValue(reachValue);
        log.setDataDate(user.getDataDate());
        log.setGroupId(user.getGroupId());
        log.setYn(Boolean.TRUE);
        kpiGroupIndicatorTargetHitLogService.save(log);
    }

    /**
     * 储存命中记录
     *
     * @param kpiGroupIndicatorId
     * @param kpiGroupIndicatorLaddersId
     * @param kpiValue
     * @param user
     */
    protected void saveParamHitLog(Long kpiGroupIndicatorId, Long kpiGroupIndicatorLaddersId, BigDecimal kpiValue, KpiGroupUser user) {
        KpiGroupIndicatorHitLog hitLog = new KpiGroupIndicatorHitLog();
        hitLog.setKpiGroupIndicatorId(kpiGroupIndicatorId);
        hitLog.setKpiGroupIndicatorLaddersId(kpiGroupIndicatorLaddersId);
        hitLog.setUserId(user.getUserId());
        hitLog.setKpiValue(kpiValue);
        hitLog.setDataDate(user.getDataDate());
        hitLog.setGroupId(user.getGroupId());
        hitLog.setYn(Boolean.TRUE);
        kpiGroupIndicatorHitLogService.saveUnique(hitLog);
    }
}