# HotelKpiExplainConfigServiceImpl.java

    package cloud.wconnect.workperformance.service.hotelkpi.impl;

    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.cons.hotelkpi.HotelKpiCons;
    import cloud.wconnect.workperformance.cons.hotelkpi.HotelKpiExplainFormulaCons;
    import cloud.wconnect.workperformance.cons.hotelkpi.comparison.HotelKpiJudgmentCons;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiExplainConfig;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiMetricsConfig;
    import cloud.wconnect.workperformance.mapper.hotelkpi.HotelKpiExplainConfigMapper;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.explain.HotelKpiExplainDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.kpi.HotelKpiCalculationFactorDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.kpi.HotelKpiComparisonRuleDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.kpi.HotelKpiValueDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.kpiv2.HotelKpiV2ComparisonRuleDTO;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiExplainConfigService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Service;

    import java.math.BigDecimal;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     * Hotel KPI Explain Config 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-06-26
     */
    @Service
    @DS("work_performance")
    public class HotelKpiExplainConfigServiceImpl extends ServiceImpl<HotelKpiExplainConfigMapper, HotelKpiExplainConfig> implements IHotelKpiExplainConfigService {

        @Resource
        private ObjectMapper objectMapper;

        /**
         * 根据指标类型获取 Explain 配置
         *
         * @param propertyId 资产 id
         * @return HotelKpiExplainConfig
         * @author zc
         * @date 2024/6/28
         */
        @Override
        public HotelKpiExplainConfig getByMetricsType(int propertyId) {
            return getOne(new LambdaQueryWrapper<HotelKpiExplainConfig>()
                    .eq(HotelKpiExplainConfig::getPropertyId, propertyId));
        }

        /**
         * 判断 Explain 是否显示
         *
         * @param explainConfig  Explain 配置
         * @param explainMonthly Explain 数据
         * @param metricsType    指标类型
         * @return Boolean true: 通过, false: 不通过, null: 不可比较
         * @author zc
         * @date 2024/6/28
         */
        @Override
        public Boolean getExplainIsShow(HotelKpiExplainConfig explainConfig, HotelKpiExplainDTO explainMonthly, int metricsType) {
            if (Objects.isNull(explainConfig) || Objects.isNull(explainMonthly)) {
                return null;
            }
            List<Integer> effectiveMetricsTypeList = JsonUtils.convertStringToList(objectMapper,
                    explainConfig.getMetrics(), Integer.class);
            if (!effectiveMetricsTypeList.contains(metricsType)) {
                return null;
            }
            if (!HotelKpiExplainFormulaCons.SURVEY_COUNT.equals(explainConfig.getFormula())) {
                return null;
            }
            BigDecimal actual = explainMonthly.getValue();
            BigDecimal configValue = explainConfig.getValue();
            if (Objects.isNull(actual) || Objects.isNull(configValue)) {
                return null;
            }
            return actual.compareTo(configValue) < 0;
        }

        /**
         * 获取 KPI 是否达标
         *
         * @param metricsConfig 指标配置
         * @param actual        实际值
         * @param target        目标值
         * @return Boolean true: 达标, false: 未达标, null: 不可比较
         * @author zc
         * @date 2024/6/28
         */
        @Override
        public Boolean getKpiComparison(HotelKpiMetricsConfig metricsConfig, HotelKpiValueDTO actualKpiValueDTO, BigDecimal actual, BigDecimal target) {
            String actualGreaterTarget;
            if (Objects.equals(metricsConfig.getVersion(), HotelKpiCons.V1)) {
                HotelKpiComparisonRuleDTO comparisonRuleDTO = JsonUtils.convertStringToObject(objectMapper,
                        metricsConfig.getComparisonRule(), HotelKpiComparisonRuleDTO.class);
                // 若比较规则关闭，则返回 null
                if (!comparisonRuleDTO.getOn()) {
                    return null;
                }
                if (Objects.isNull(target)) {
                    return null;
                }
                if (Objects.isNull(actual)) {
                    HotelKpiCalculationFactorDTO calculationFactorDTO = actualKpiValueDTO.getCalculationFactor().stream()
                            .filter(item -> item.getIndex() == 2).findFirst().orElse(null);
                    if (Objects.nonNull(calculationFactorDTO) && Objects.nonNull(calculationFactorDTO.getCrawl())) {
                        if (calculationFactorDTO.getCrawl().compareTo(BigDecimal.ZERO) == 0) {
                            return true;
                        }
                    }
                    return null;
                }
                actualGreaterTarget = comparisonRuleDTO.getActualGreaterTarget();
            } else {
                HotelKpiV2ComparisonRuleDTO comparisonRuleDTO = JsonUtils.convertStringToObject(objectMapper,
                        metricsConfig.getComparisonRule(), HotelKpiV2ComparisonRuleDTO.class);
                // 若比较规则关闭，则返回 null
                if (!comparisonRuleDTO.getOn()) {
                    return null;
                }
                if (Objects.isNull(target) || Objects.isNull(actual)) {
                    return null;
                }
                actualGreaterTarget = comparisonRuleDTO.getBudgetChg().getGreaterJudgment();
            }
            if (HotelKpiJudgmentCons.GOOD.equals(actualGreaterTarget)) {
                return actual.compareTo(target) >= 0;
            } else if (HotelKpiJudgmentCons.BAD.equals(actualGreaterTarget)) {
                return actual.compareTo(target) <= 0;
            } else {
                return null;
            }
        }

    }