package com.artfess.cqlt.manager.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.artfess.base.enums.AnalyseTypeEnum;
import com.artfess.base.enums.FaTargetTypeEnum;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.CommonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.cqlt.dao.QfFinancialStatisticalDao;
import com.artfess.cqlt.manager.QfEnterpriseInfoManager;
import com.artfess.cqlt.manager.QfEuroRatesDManager;
import com.artfess.cqlt.manager.QfFinanceLoanDManager;
import com.artfess.cqlt.manager.QfFinancePlSManager;
import com.artfess.cqlt.manager.QfFinancialStatisticalManager;
import com.artfess.cqlt.manager.QfHrPersonMManager;
import com.artfess.cqlt.manager.SysSubjectTargetManager;
import com.artfess.cqlt.model.QfEnterpriseInfo;
import com.artfess.cqlt.model.QfFinancialStatistical;
import com.artfess.cqlt.model.SysSubjectTarget;
import com.artfess.cqlt.utils.FinancialTimeUtils;
import com.artfess.cqlt.vo.BankLoanDetailRespVo;
import com.artfess.cqlt.vo.BridgeFigureVo;
import com.artfess.cqlt.vo.DataInfoVo;
import com.artfess.cqlt.vo.DateReqVo;
import com.artfess.cqlt.vo.EuroRatesRespVo;
import com.artfess.cqlt.vo.FaReportRespVo;
import com.artfess.cqlt.vo.FaTargetRespVo;
import com.artfess.cqlt.vo.ReportReqVo;
import com.artfess.cqlt.vo.ReportVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 财务主题大屏统计宽表 服务实现类
 *
 * @author min.wu
 * @company 阿特菲斯信息技术有限公司
 * @since 2023-03-30
 */
@Slf4j
@Service
public class QfFinancialStatisticalManagerImpl extends BaseManagerImpl<QfFinancialStatisticalDao, QfFinancialStatistical> implements QfFinancialStatisticalManager {

    private Map<String, QfEnterpriseInfo> enterpriseInfoMap = Maps.newHashMap();

    private FinancialTimeUtils financialTimeUtils = new FinancialTimeUtils();
    /**人资科目*/
    private final static String HR_030000S = "HR030000s";
    /**产品销售收入科目*/
    private final static String PRODUCT_SALES_REVENUE = "FE029";
    /**为了满足表达式引擎 由于部分指标是纯数字，会影响计算所以在指标前面加 U保证指标不是存数字，正确使用表达式引擎计算公式*/
    private final static String PL_3000 = "UPL3000";
    /**数据类型为预算数据*/
    private final static Integer BUDGET_TYPE = 2;
    /**数据类型为实际数据*/
    private final static Integer ACTUAL_TYPE = 1;
    /**大屏类型为集团大屏*/
    private final static Integer CIGR_TYPE = 2;
    /**大屏类型为子企业大屏*/
    private final static Integer COMPANY_TYPE = 1;
    @Autowired
    private SysSubjectTargetManager sysSubjectTargetManager;
    @Autowired
    private QfEnterpriseInfoManager enterpriseInfoManager;
    @Autowired
    private QfHrPersonMManager hrPersonmManager;
    @Autowired
    private QfFinancePlSManager plsManager;
    @Autowired
    private QfFinanceLoanDManager loandManager;
    @Autowired
    private QfEuroRatesDManager euroRatesdManager;

    /**
     * @param list       当前上报数据
     * @param dataInfoVo 上报时间信息
     * @param dataType   上报数据类型 1：实际值，2：预算值
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveData(List<ReportVo> list, DataInfoVo dataInfoVo, Integer dataType) {
        dataInfoVo.setDataType(dataType);
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        // 获取财务所有指标数据
        List<String> businessList = Lists.newArrayList();
        businessList.add("Finance");
        businessList.add("money");
        List<SysSubjectTarget> targetList = sysSubjectTargetManager.getTargetList(businessList);
        //资金指标
        if (CollectionUtils.isEmpty(targetList)) {
            return false;
        }
        if (!dataInfoVo.getFlag()) {
            List<ReportVo> hrReportVo = hrPersonmManager.getHrReportVo(dataInfoVo, HR_030000S);
            list.addAll(hrReportVo);
        }
        //获取境外企业
        Map<String, QfEnterpriseInfo> enterpriseInfoMap = enterpriseInfoManager.getEnterpriseInfoMap(null);

        List<QfFinancialStatistical> dataList = Lists.newArrayList();
        QueryWrapper<QfFinancialStatistical> query = new QueryWrapper<>();
        query.eq("year_", dataInfoVo.getYear());
        query.eq("quarter_", dataInfoVo.getQuarter());
        query.eq("month_", dataInfoVo.getMonth());
        List<QfFinancialStatistical> qfFinancialStatisticals = this.baseMapper.selectList(query);
        try {
            if (CollectionUtils.isEmpty(qfFinancialStatisticals)) {
                targetList.forEach(target -> {
                    saveFinancialStatistical(target, dataList, list, dataType, dataInfoVo, enterpriseInfoMap);
                });
            } else {
                Map<String, List<QfFinancialStatistical>> statisticalMap = qfFinancialStatisticals.stream().collect(Collectors.groupingBy(QfFinancialStatistical::getTargetId));
                targetList.forEach(target -> {
                    List<QfFinancialStatistical> statisticalList = Lists.newArrayList();
                    if (statisticalMap.containsKey(target.getId())) {
                        statisticalList = statisticalMap.get(target.getId());
                    }
                    updateFinancialStatistical(target, dataList, statisticalList, list, dataType, dataInfoVo, enterpriseInfoMap);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        //获取需要计算增长率的指标去年的数据
        List<QfFinancialStatistical> lastYearData = this.lastYearData(dataInfoVo);
        //处理 需要特殊公式计算的数据
        processSalesRevenue(dataList, targetList, dataInfoVo, lastYearData);
        try {
            partitionSave(dataList);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("财务大屏报表实际数据生成失败:{}", e.getMessage());
            return false;
        }
    }

    /**
     * 处理欧洲、美洲、亚洲区销售收入
     *
     * @param dataList
     * @param targetList
     * @param dataInfoVo
     */
    private void processSalesRevenue(List<QfFinancialStatistical> dataList,
                                     List<SysSubjectTarget> targetList,
                                     DataInfoVo dataInfoVo,
                                     List<QfFinancialStatistical> lastYearDate) {
        Map<String, SysSubjectTarget> subjectTargetMap = targetList.stream().collect(Collectors.toMap(item -> item.getCode(), item -> item));

        String salesRevenueTargetId = null;
        if (subjectTargetMap.containsKey(PRODUCT_SALES_REVENUE)) {
            salesRevenueTargetId = subjectTargetMap.get(PRODUCT_SALES_REVENUE).getId();
        }
        //获取所有企业销售收入以及公式为增长率的集合
        List<QfFinancialStatistical> list = Lists.newArrayList();
        String finalSalesRevenueTargetId = salesRevenueTargetId;
        dataList.forEach(detail -> {
            if (finalSalesRevenueTargetId.equals(detail.getTargetId()) && null != detail.getEnterpriseArea()) {
                detail.setAnalyseType(detail.getEnterpriseArea() + "");
                list.add(detail);
            }

            if (AnalyseTypeEnum.mergeType().contains(detail.getAnalyseType())) {
                list.add(detail);
            }
        });
        Map<String, List<QfFinancialStatistical>> statisticalMap = list.stream()
                .filter(b -> !StringUtils.isEmpty(b.getAnalyseType()))
                .collect(Collectors.groupingBy(QfFinancialStatistical::getAnalyseType));


        Map<String, List<SysSubjectTarget>> targetMap = targetList.stream()
                .filter(b -> !StringUtils.isEmpty(b.getAnalyseType()))
                .collect(Collectors.groupingBy(SysSubjectTarget::getAnalyseType));

        if (!CollectionUtils.isEmpty(lastYearDate)) {
            //计算年初余额
            calculatingBalance(dataInfoVo, lastYearDate, statisticalMap);
            //特殊公式-计算平均值
            calculatingAverage(dataInfoVo, lastYearDate, statisticalMap);
        }
        List<QfFinancialStatistical> areaData = this.getAreaData(dataInfoVo);
        Map<String, QfFinancialStatistical> areaTargetMap = areaData.stream()
                .collect(Collectors.toMap(item -> item.getTargetId(), item -> item));

        targetMap.forEach((analyseType, v) -> {
            List<QfFinancialStatistical> statisticals = statisticalMap.get(analyseType);
            if (CollectionUtils.isEmpty(statisticals)) {
                return;
            }
            //计算区域相关数据
            calculatingArea(dataList, dataInfoVo, areaTargetMap, analyseType, v, statisticals);
        });
    }

    /**
     * 计算平均值
     * 特殊公式 参照客户提供的指标库
     *
     * @param dataInfoVo
     * @param lastYearDate
     * @param statisticalMap
     */
    private void calculatingAverage(DataInfoVo dataInfoVo, List<QfFinancialStatistical> lastYearDate,
                                    Map<String, List<QfFinancialStatistical>> statisticalMap) {
        if (CollectionUtils.isEmpty(statisticalMap)) {
            return;
        }
        List<QfFinancialStatistical> statisticals = Lists.newArrayList();
        if (statisticalMap.containsKey(AnalyseTypeEnum.JLR.getType())) {
            statisticals.addAll(statisticalMap.get(AnalyseTypeEnum.JLR.getType()));
        }
        if (statisticalMap.containsKey(AnalyseTypeEnum.XSSR.getType())) {
            statisticals.addAll(statisticalMap.get(AnalyseTypeEnum.XSSR.getType()));
        }
        if (statisticalMap.containsKey(AnalyseTypeEnum.XSCB.getType())) {
            statisticals.addAll(statisticalMap.get(AnalyseTypeEnum.XSCB.getType()));
        }
        if (statisticalMap.containsKey(AnalyseTypeEnum.PJZCZE.getType())) {
            statisticals.addAll(statisticalMap.get(AnalyseTypeEnum.PJZCZE.getType()));
        }

        if (CollectionUtils.isEmpty(statisticals)) {
            return;
        }
        statisticals.forEach(thisYearData -> {
            if (StringUtils.isEmpty(thisYearData.getTargetCalculation())) {
                return;
            }
            AnalyseTypeEnum analyse = AnalyseTypeEnum.getAnalyse(thisYearData.getAnalyseType());
            lastYearDate.forEach(lastYearData -> {
                if (StringUtils.isEmpty(thisYearData.getTargetCalculation()) || !lastYearData.getTargetId().equals(thisYearData.getTargetId()) || !lastYearData.getEnterpriseCode().equals(thisYearData.getEnterpriseCode())) {
                    return;
                }
                Map<Integer, Map<String, BigDecimal>> thisYearCalculationMap = JSONObject.parseObject(thisYearData.getTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> thisYearYtdCalculationMap = JSONObject.parseObject(thisYearData.getYtdTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> lastYearCalculationMap = JSONObject.parseObject(lastYearData.getTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> lastYearYtdCalculationMap = JSONObject.parseObject(lastYearData.getYtdTargetCalculation(), Map.class);
                Map<String, BigDecimal> thisYearDataMap = thisYearCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> thisYearYtdDataMap = thisYearYtdCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> lastYearDataMap = lastYearCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> lastYearYtdDataMap = lastYearYtdCalculationMap.get(dataInfoVo.getDataType());

                if (CollectionUtils.isEmpty(thisYearDataMap) || CollectionUtils.isEmpty(lastYearDataMap)) {
                    return;
                }
                //得到除数值
                String divisorCalculation = analyse.getFormula();
                List<String> divisorExpressionKey = CommonUtil.getExpressionKey(divisorCalculation);
                String thisYearDivisorCalculation = CommonUtil.replaceExpression(divisorExpressionKey, divisorCalculation);
                BigDecimal divisorValue = CommonUtil.convertToCode(thisYearDivisorCalculation, thisYearDataMap, 4);

                String targetCalculation = thisYearData.getTempCalculation().replaceAll(analyse.getFormula() + "/", "");
                List<String> expressionKey = CommonUtil.getExpressionKey(targetCalculation);
                String thisCalculation = CommonUtil.replaceExpression(expressionKey, targetCalculation);
                if (expressionKey.size() <= thisYearDataMap.size() && expressionKey.size() <= thisYearDataMap.size()) {
                    BigDecimal thisYearValue = CommonUtil.convertToCode(thisCalculation, thisYearDataMap, 4);
                    BigDecimal lastYearValue = CommonUtil.convertToCode(thisCalculation, lastYearDataMap, 4);
                    BigDecimal value = getAvgValue(thisYearData, lastYearData, divisorValue, thisYearValue, lastYearValue, 4);
                    if (dataInfoVo.getDataType() == 1) {
                        thisYearData.setActual(value);
                    } else if (BUDGET_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setBudget(value);
                    }
                }
                if (expressionKey.size() <= thisYearYtdDataMap.size() && expressionKey.size() <= thisYearYtdDataMap.size()) {
                    BigDecimal thisYearValue = CommonUtil.convertToCode(thisCalculation, thisYearYtdDataMap, 2);
                    BigDecimal lastYearValue = CommonUtil.convertToCode(thisCalculation, lastYearYtdDataMap, 2);
                    divisorValue = CommonUtil.convertToCode(thisYearDivisorCalculation, thisYearYtdDataMap, 4);
                    BigDecimal value = getAvgValue(thisYearData, lastYearData, divisorValue, thisYearValue, lastYearValue, 4);
                    if (ACTUAL_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setActualYtd(value);
                    } else if (BUDGET_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setBudgetYtd(value);
                    }
                }
                log.info("最终计算数据:thisYearData：{}", JSON.toJSONString(thisYearData));
            });
        });
    }

    private BigDecimal getAvgValue(QfFinancialStatistical thisYearData, QfFinancialStatistical lastYearData, BigDecimal divisorValue, BigDecimal thisYearValue, BigDecimal lastYearValue, int i) {
        BigDecimal value = null;
        if (null != lastYearData) {
            value = thisYearValue.add(lastYearValue).divide(new BigDecimal(2), 4, BigDecimal.ROUND_HALF_UP);
        } else {
            value = thisYearValue;
        }
        if (null == value || value.doubleValue() == 0) {
            value = BigDecimal.ZERO;
        } else {
            value = divisorValue.divide(value, 4, BigDecimal.ROUND_HALF_UP);
        }

        if ("天".equals(thisYearData.getTargetUnit()) && value.doubleValue() > 0) {
            value = new BigDecimal(30).multiply(new BigDecimal(thisYearData.getMonth())).divide(value, i, BigDecimal.ROUND_HALF_UP);
        }
        //权益乘数指标单独处理，不需要*100
        if ("次".equals(thisYearData.getTargetUnit()) && !AnalyseTypeEnum.PJZCZE.getType().equals(thisYearData.getAnalyseType())) {
            value = value.multiply(new BigDecimal(100));
        }
        if ("%".equals(thisYearData.getTargetUnit())) {
            value = value.multiply(new BigDecimal(100));
        }
        return value;
    }

    /**
     * 计算区域相关数据
     *
     * @param dataList
     * @param dataInfoVo
     * @param areaTargetMap
     * @param analyseType
     * @param v
     * @param statisticals
     */
    private void calculatingArea(List<QfFinancialStatistical> dataList, DataInfoVo dataInfoVo, Map<String, QfFinancialStatistical> areaTargetMap, String analyseType, List<SysSubjectTarget> v, List<QfFinancialStatistical> statisticals) {
        if (AnalyseTypeEnum.getAreaType().contains(analyseType)) {
            BigDecimal actual = BigDecimal.ZERO;
            BigDecimal budget = BigDecimal.ZERO;
            BigDecimal actualYtd = BigDecimal.ZERO;
            BigDecimal budgetYtd = BigDecimal.ZERO;
            for (QfFinancialStatistical qfFinancialStatistical : statisticals) {
                String targetCalculation = qfFinancialStatistical.getTargetCalculation();
                String ytdTargetCalculation = qfFinancialStatistical.getYtdTargetCalculation();
                Map<Integer, JSONObject> map = JSONObject.parseObject(targetCalculation, Map.class);
                Map<Integer, JSONObject> ytdMap = JSONObject.parseObject(ytdTargetCalculation, Map.class);
                JSONObject actualMap = map.get(ACTUAL_TYPE);
                JSONObject budgetMap = map.get(BUDGET_TYPE);
                JSONObject actualYtdMap = ytdMap.get(ACTUAL_TYPE);
                JSONObject budgetYtdMap = ytdMap.get(BUDGET_TYPE);
                if (!CollectionUtils.isEmpty(actualMap)) {
                    actual = actual.add(null == actualMap.getBigDecimal(PL_3000) ? BigDecimal.ZERO : actualMap.getBigDecimal(PL_3000));
                }
                if (!CollectionUtils.isEmpty(budgetMap)) {
                    budget = budget.add(null == budgetMap.getBigDecimal(PL_3000) ? BigDecimal.ZERO : budgetMap.getBigDecimal(PL_3000));
                }

                if (!CollectionUtils.isEmpty(actualYtdMap)) {
                    actualYtd = actualYtd.add(null == actualYtdMap.getBigDecimal(PL_3000) ? BigDecimal.ZERO : actualYtdMap.getBigDecimal(PL_3000));
                }

                if (!CollectionUtils.isEmpty(budgetYtdMap)) {
                    budgetYtd = budgetYtd.add(null == budgetYtdMap.getBigDecimal(PL_3000) ? BigDecimal.ZERO : budgetYtdMap.getBigDecimal(PL_3000));
                }
            }
            BigDecimal finalActual = actual;
            BigDecimal finalBudget = budget;
            BigDecimal finalBudgetYtd = budgetYtd;
            BigDecimal finalActualYtd = actualYtd;

            v.forEach(target -> {
                QfFinancialStatistical qfFinancialStatistical = null;
                if (areaTargetMap.containsKey(target.getId())) {
                    qfFinancialStatistical = areaTargetMap.get(target.getId());
                } else {
                    qfFinancialStatistical = new QfFinancialStatistical();
                    createInfo(target, dataInfoVo, qfFinancialStatistical);
                    qfFinancialStatistical.setEnterpriseCode("CIGR");
                }
                qfFinancialStatistical.setActual(finalActual);
                qfFinancialStatistical.setActualYtd(finalActualYtd);
                qfFinancialStatistical.setBudget(finalBudget);
                qfFinancialStatistical.setBudgetYtd(finalBudgetYtd);
                dataList.add(qfFinancialStatistical);
            });
        }
    }

    /**
     * 特殊公式计算- 年初余额计算
     *
     * @param dataInfoVo
     * @param lastYearDate
     * @param statisticalMap
     */
    private void calculatingBalance(DataInfoVo dataInfoVo, List<QfFinancialStatistical> lastYearDate, Map<String, List<QfFinancialStatistical>> statisticalMap) {
        List<QfFinancialStatistical> statisticals = statisticalMap.get(AnalyseTypeEnum.NCYE.getType());

        if (CollectionUtils.isEmpty(statisticals)) {
            return;
        }
        statisticals.forEach(thisYearData -> {
            if (StringUtils.isEmpty(thisYearData.getTargetCalculation())) {
                return;
            }
            lastYearDate.forEach(lastYearData -> {
                if (StringUtils.isEmpty(thisYearData.getTargetCalculation())) {
                    return;
                }
                if (!lastYearData.getTargetId().equals(thisYearData.getTargetId())) {
                    return;
                }
                if (!lastYearData.getEnterpriseCode().equals(thisYearData.getEnterpriseCode())) {
                    return;
                }
                Map<Integer, Map<String, BigDecimal>> lastYearCalculationMap = JSONObject.parseObject(lastYearData.getTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> thisYearCalculationMap = JSONObject.parseObject(thisYearData.getTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> lastYearYtdCalculationMap = JSONObject.parseObject(lastYearData.getYtdTargetCalculation(), Map.class);
                Map<Integer, Map<String, BigDecimal>> thisYearYtdCalculationMap = JSONObject.parseObject(thisYearData.getYtdTargetCalculation(), Map.class);
                Map<String, BigDecimal> thisYearDataMap = thisYearCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> lastYearDataMap = lastYearCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> thisYearYtdDataMap = thisYearYtdCalculationMap.get(dataInfoVo.getDataType());
                Map<String, BigDecimal> lastYearYtdDataMap = lastYearYtdCalculationMap.get(dataInfoVo.getDataType());
                if (CollectionUtils.isEmpty(thisYearDataMap) || CollectionUtils.isEmpty(lastYearDataMap)) {
                    return;
                }
                String targetCalculation = thisYearData.getTempCalculation();
                List<String> expressionKey = CommonUtil.getExpressionKey(targetCalculation);
                String thisCalculation = CommonUtil.replaceExpression(expressionKey, targetCalculation);
                if (expressionKey.size() == thisYearDataMap.size() && expressionKey.size() == thisYearDataMap.size()) {
                    BigDecimal thisYearValue = CommonUtil.convertToCode(thisCalculation, thisYearDataMap, 2);
                    BigDecimal lastYearValue = CommonUtil.convertToCode(thisCalculation, lastYearDataMap, 2);
                    BigDecimal value = BigDecimal.ZERO;
                    if (null != lastYearValue && lastYearValue.doubleValue() != 0) {
                        value = thisYearValue.divide(lastYearValue, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    }
                    if (ACTUAL_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setActual(value);
                    } else if (BUDGET_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setBudget(value);
                    }
                }
                if (expressionKey.size() == thisYearYtdDataMap.size() && expressionKey.size() == thisYearYtdDataMap.size()) {
                    BigDecimal thisYearValue = CommonUtil.convertToCode(thisCalculation, thisYearYtdDataMap, 2);
                    BigDecimal lastYearValue = CommonUtil.convertToCode(thisCalculation, lastYearYtdDataMap, 2);
                    BigDecimal value = BigDecimal.ZERO;
                    if (null != lastYearValue && lastYearValue.doubleValue() != 0) {
                        value = thisYearValue.divide(lastYearValue, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    }
                    if (ACTUAL_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setActualYtd(value);
                    } else if (BUDGET_TYPE.equals(dataInfoVo.getDataType())) {
                        thisYearData.setBudgetYtd(value);
                    }
                }
            });
        });
    }

    /**
     * 获取区域指标数据
     *
     * @param dataInfoVo
     * @return
     */
    private List<QfFinancialStatistical> getAreaData(DataInfoVo dataInfoVo) {
        QueryWrapper<QfFinancialStatistical> query = new QueryWrapper<>();
        query.eq("year_", dataInfoVo.getYear());
        query.eq("month_", dataInfoVo.getMonth());
        query.eq("target_level_", 4);
        query.in("analyse_type_", AnalyseTypeEnum.getAreaType());
        List<QfFinancialStatistical> qfFinancialStatisticals = this.baseMapper.selectList(query);
        return qfFinancialStatisticals;
    }

    /**
     * 获取去年12月份需要特殊计算的数据
     *
     * @param dataInfoVo
     * @return
     */
    private List<QfFinancialStatistical> lastYearData(DataInfoVo dataInfoVo) {
        QueryWrapper<QfFinancialStatistical> query = new QueryWrapper<>();
        query.eq("year_", dataInfoVo.getYear() - 1);
        query.eq("month_", 12);
        query.in("analyse_type_", AnalyseTypeEnum.mergeType());
        List<QfFinancialStatistical> qfFinancialStatisticals = this.baseMapper.selectList(query);
        return qfFinancialStatisticals;
    }

    @Override
    public List<FaTargetRespVo> data(ReportReqVo t) {
        if (StringUtils.isEmpty(t.getTargetId())) {
            t.setTargetLevel("1");
        }
        //获取当前指标的年季月趋势数据
        if (null == t.getYear() || t.getYear() <= 0) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }

        if (null == t.getStartYear() || null == t.getEndYear()) {
            t.setEndYear(t.getYear());
            t.setStartYear(t.getYear() - 5);
        }

        QfEnterpriseInfo group = enterpriseInfoManager.getGroup();
        if (StringUtil.isEmpty(t.getEnterpriseCode()) || group.getCode().equals(t.getEnterpriseCode())) {
            t.setEnterpriseCode(group.getCode());
            t.setType(2);
        } else {
            t.setType(1);
        }

        List<SysSubjectTarget> targetList = this.baseMapper.getGroupData(t);
        List<FaTargetRespVo> resultList = Lists.newArrayList();
        targetList.forEach(target -> {
            String[] type = new String[]{"5"};
            List<String> newTypeList = Arrays.asList(type);
            t.setTargetId(target.getId());
            List<FaTargetRespVo> faTargetRespVos = currentTargetAnalysis(target, newTypeList, t, null, true);
            resultList.addAll(faTargetRespVos);
            FaTargetRespVo resultFa = new FaTargetRespVo();
            resultFa.setTargetId(target.getId());
            resultFa.setTargetName(target.getName());
            resultFa.setTargetNameEn(target.getTargetNameEn());
            resultFa.setTargetUnit(target.getUnit());
            if ("1".equals(target.getConversionUnit())) {
                resultFa.setTargetUnit("10K€");
            }

            if ("2".equals(target.getConversionUnit())) {
                resultFa.setTargetUnit("亿欧");
            }
            if ("万欧/人".equals(target.getUnit())) {
                resultFa.setTargetUnit("10K€/person");
            }
            if ("人".equals(target.getUnit())) {
                resultFa.setTargetUnit("person");
            }
            resultFa.setStaLat("3");
            resultFa.setType("13");
            resultFa.setSn(target.getSn());

            //首页显示数值
            if (!CollectionUtils.isEmpty(faTargetRespVos)) {
                List<FaReportRespVo> resultData = faTargetRespVos.get(0).getResultData();
                if (!CollectionUtils.isEmpty(resultData)) {
                    FaReportRespVo faReportRespVo = resultData.get(resultData.size() - 1);
                    resultFa.setShowValue(faReportRespVo.getActual());
                    resultFa.setAsDate(faReportRespVo.getYear() + "-" + faReportRespVo.getMonth());
                }
            }
            resultList.add(resultFa);
        });

        return resultList;
    }

    @Override
    public List<FaTargetRespVo> dataAnalysis(ReportReqVo t) {
        Assert.hasText(t.getTargetId(), "请选择要统计的指标id");
        SysSubjectTarget target = sysSubjectTargetManager.get(t.getTargetId());
        Assert.notNull(target, "当前指标不存在");
        if (StringUtils.isEmpty(target.getType())) {
            return Lists.newArrayList();
        }
        QfEnterpriseInfo group = enterpriseInfoManager.getGroup();
        if (StringUtil.isEmpty(t.getEnterpriseCode()) || group.getCode().equals(t.getEnterpriseCode())) {
            t.setEnterpriseCode(group.getCode());
            t.setType(2);
        } else {
            t.setType(1);
        }
        List<String> typeList = Arrays.asList(target.getType().split(","));
        //展示第三个以后数据统计图
        List<String> newTypeList = Lists.newArrayList();
        for (int i = 0; i < typeList.size(); i++) {
            if (i > 2) {
                newTypeList.add(typeList.get(i));
            }
        }
        List<SysSubjectTarget> lowerLevelTargetList = Lists.newArrayList();
        //占比分析统计 需要获取当前指标的下级指标 用做占比计算（下级与当前级的占比计算）
        if (target.getType().contains("11")) {
            lowerLevelTargetList = sysSubjectTargetManager.lowerLevelTargetList(target.getSubjectId());
        }
        List<FaTargetRespVo> list = currentTargetAnalysis(target, newTypeList, t, lowerLevelTargetList, false);
        return list;
    }

    @Override
    public BigDecimal getLastYearSales(int lastYear, String salesCode, String code) {
        return this.baseMapper.findByTargetCodeAndCompanyCode(lastYear, salesCode, code);
    }

    @Override
    public BigDecimal getlastYearProfitsSales(int lastYear, String profitsSalesCode, String code) {
        return this.baseMapper.findByTargetCodeAndCompanyCode(lastYear, profitsSalesCode, code);
    }

    /**
     * 资金1级指标
     *
     * @param t
     * @return
     */
    @Override
    public List<FaTargetRespVo> moneyData(ReportReqVo t) {
        if (StringUtils.isEmpty(t.getTargetId())) {
            t.setTargetLevel("1");
        }
        //获取当前指标的年季月趋势数据
        if (null == t.getYear() || t.getYear() <= 0) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }

        if (null == t.getStartYear() || null == t.getEndYear()) {
            t.setEndYear(t.getYear());
            t.setStartYear(t.getYear() - 5);
        }

        QfEnterpriseInfo group = enterpriseInfoManager.getGroup();
        if (StringUtil.isEmpty(t.getEnterpriseCode()) || group.getCode().equals(t.getEnterpriseCode())) {
            t.setEnterpriseCode(group.getCode());
            t.setType(2);
        } else {
            t.setType(1);
        }
        QueryWrapper<SysSubjectTarget> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("target_level_", "1");
        queryWrapper.eq("business_", "money");
        List<SysSubjectTarget> targetList = sysSubjectTargetManager.list(queryWrapper);
        List<FaTargetRespVo> resultList = Lists.newArrayList();
        targetList.forEach(target -> {
            String[] type = new String[]{"5"};
            List<String> newTypeList = Arrays.asList(type);
            t.setTargetId(target.getId());
            List<FaTargetRespVo> faTargetRespVos = currentTargetAnalysis(target, newTypeList, t, null, true);
            resultList.addAll(faTargetRespVos);
        });
        return resultList;
    }

    /**
     * 桥图分析
     *
     * @param t
     * @return
     */
    @Override
    public List<FaTargetRespVo> bridgeFigureAnalysis(ReportReqVo t) {
        SysSubjectTarget target = sysSubjectTargetManager.get(t.getTargetId());
        if (null == target) {
            return null;
        }
        //桥图路径 利润总额路径
        String[] targetCodes = null;
        if ("FE001".equals(target.getCode())) {
            targetCodes = new String[]{"FE013", "FE912", "FE012", "FE011", "FE034", "FE033", "FE032", "FE031", "FE030", "FE029", "FE001"};
        } else if ("FE040".equals(target.getCode())) {
            targetCodes = new String[]{"FE011", "FE034", "FE033", "FE032", "FE031", "FE030", "FE029", "FE040"};
        }
        List<FaTargetRespVo> respVoList = Lists.newArrayList();
        monthBridge(t, target, targetCodes, respVoList);
        ytdBridge(t, target, targetCodes, respVoList);
        return respVoList;
    }

    private void monthBridge(ReportReqVo t, SysSubjectTarget target, String[] targetCodes, List<FaTargetRespVo> respVoList) {
        FaTargetRespVo faTargetRespVo = new FaTargetRespVo();
        faTargetRespVo.setTargetName(target.getName() + "当月桥图分析(万欧)");
        if (!StringUtils.isEmpty(target.getTargetNameEn())) {
            faTargetRespVo.setTargetNameEn(target.getTargetNameEn() + "bridge(10K€)");
        }

        List<FaReportRespVo> list = baseMapper.bridgeFigureAnalysis(t, Arrays.asList(targetCodes));
        List<BridgeFigureVo> bridgeFigureVoList = getBridgeFigureVos(list, target);
        if (CollectionUtils.isEmpty(bridgeFigureVoList)) {
            return;
        }
        faTargetRespVo.setBridgeFigureList(bridgeFigureVoList);
        respVoList.add(faTargetRespVo);
    }

    private void ytdBridge(ReportReqVo t, SysSubjectTarget target, String[] targetCodes, List<FaTargetRespVo> respVoList) {

        List<FaReportRespVo> list = baseMapper.ytdBridgeFigureAnalysis(t, Arrays.asList(targetCodes));
        List<BridgeFigureVo> bridgeFigureVoList = getBridgeFigureVos(list, target);
        if (CollectionUtils.isEmpty(bridgeFigureVoList)) {
            return;
        }
        FaTargetRespVo faTargetRespVo = new FaTargetRespVo();
        faTargetRespVo.setTargetName(target.getName() + "当月累计桥图分析(万欧)");
        if (!StringUtils.isEmpty(target.getTargetNameEn())) {
            faTargetRespVo.setTargetNameEn(target.getTargetNameEn() + "bridge(10K€)");
        }
        faTargetRespVo.setBridgeFigureList(bridgeFigureVoList);
        respVoList.add(faTargetRespVo);
    }

    private List<BridgeFigureVo> getBridgeFigureVos(List<FaReportRespVo> list, SysSubjectTarget target) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<BridgeFigureVo> bridgeFigureVoList = Lists.newArrayList();
        list.forEach(resp -> {
            if (!resp.getTargetName().equals(target.getName())) {
                return;
            }
            //桥图指标
            BridgeFigureVo bridgeFigureVo = new BridgeFigureVo();
            bridgeFigureVo.setTargetName(resp.getTargetName() + "预算");
            bridgeFigureVo.setTargetNameEn(resp.getTargetNameEn());
            bridgeFigureVo.setValue(resp.getBudget());
            bridgeFigureVoList.add(bridgeFigureVo);
        });

        BigDecimal actual = BigDecimal.ZERO;
        BigDecimal budget = BigDecimal.ZERO;
        for (FaReportRespVo reportRespVo : list) {
            if ("产品销售收入".equals(reportRespVo.getTargetName())) {
                actual = reportRespVo.getActual();
                budget = reportRespVo.getBudget();
            }
        }
        BigDecimal finalActual = actual;
        BigDecimal finalBudget = budget;
        list.forEach(faReportRespVo -> {
            BridgeFigureVo resp = new BridgeFigureVo();
            if (faReportRespVo.getTargetName().equals(target.getName())) {
                return;
            }
            if (faReportRespVo.getTargetName().contains("率")) {
                resp.setTargetName(faReportRespVo.getTargetName().substring(0, faReportRespVo.getTargetName().length() - 1));
                resp.setTargetNameEn(faReportRespVo.getTargetNameEn());
                resp.setValue(faReportRespVo.getActual().divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).multiply(finalActual)
                        .subtract(faReportRespVo.getBudget().divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).multiply(finalBudget)));
            } else {
                resp.setTargetName(faReportRespVo.getTargetName());
                resp.setTargetNameEn(faReportRespVo.getTargetNameEn());
                resp.setValue(faReportRespVo.getActual().subtract(faReportRespVo.getBudget()));
            }
            if("产品销售收入".equals(faReportRespVo.getTargetName())
                    || "工装模具销售收入".equals(faReportRespVo.getTargetName())){
                resp.setValue(resp.getValue());
            }else{
                resp.setValue(resp.getValue().multiply(new BigDecimal("-1")));
            }

            bridgeFigureVoList.add(resp);
        });
        //桥图指标
        BridgeFigureVo bridgeFigureVo = new BridgeFigureVo();
        list.forEach(resp -> {
            if (!resp.getTargetName().equals(target.getName())) {
                return;
            }
            bridgeFigureVo.setTargetName(resp.getTargetName() + "实际");
            bridgeFigureVo.setTargetNameEn(resp.getTargetNameEn());
            bridgeFigureVo.setValue(resp.getActual());
        });

        BridgeFigureVo other = new BridgeFigureVo();
        other.setTargetName("其他");
        other.setTargetNameEn("other");
        BigDecimal allValue = bridgeFigureVoList.stream()
                .map(BridgeFigureVo::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
        other.setValue(bridgeFigureVo.getValue().subtract(allValue));
        bridgeFigureVoList.add(other);

        bridgeFigureVoList.add(bridgeFigureVo);
        bridgeFigureVoList.forEach(resp -> {
            resp.setValue(resp.getValue().divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP));
        });
        return bridgeFigureVoList;
    }

    private void partitionSave(List<QfFinancialStatistical> detailList) throws InterruptedException {
        List<List<QfFinancialStatistical>> partition = BeanUtils.partition(detailList, detailList.size() / 10);
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(partition.size());
        // 声明线程计数器 记录单个任务的执行次数
        CountDownLatch countDownLatch = new CountDownLatch(partition.size());
        // 遍历处理拆分的list数据
        for (int i = 0; i < partition.size(); i++) {
            int finalI = i;
            executorService.execute(() -> {
                // 业务处理部分
                List<QfFinancialStatistical> importParamDTOList = partition.get(finalI);
                this.saveOrUpdateBatch(importParamDTOList);
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        //关闭线程池
        executorService.shutdown();
    }

    /**
     * 保存财务
     *
     * @param target
     * @param dataList
     * @param list
     * @param dataType
     * @param dataInfoVo
     * @param enterpriseInfoMap
     */
    private void saveFinancialStatistical(SysSubjectTarget target,
                                          List<QfFinancialStatistical> dataList,
                                          List<ReportVo> list,
                                          Integer dataType,
                                          DataInfoVo dataInfoVo,
                                          Map<String, QfEnterpriseInfo> enterpriseInfoMap) {

        Map<String, List<ReportVo>> enterpriseMap = list.stream().collect(Collectors.groupingBy(ReportVo::getEnterpriseCode));
        String targetCalculation = target.getTargetCalculation();
        List<String> expressionKey = CommonUtil.getExpressionKey(targetCalculation);
        enterpriseMap.forEach((enterpriseCode, financialVoList) -> {
            if (!enterpriseInfoMap.containsKey(enterpriseCode)) {
                return;
            }
            QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(enterpriseCode);
            QfFinancialStatistical qfFinancialStatistical = new QfFinancialStatistical();
            qfFinancialStatistical.setTempCalculation(targetCalculation);
            qfFinancialStatistical.setEnterpriseCode(enterpriseCode);
            createInfo(target, dataInfoVo, qfFinancialStatistical);
            calculateData(dataType, targetCalculation, expressionKey, financialVoList, qfFinancialStatistical);

            if (!StringUtil.isNotEmpty(target.getAnalyseType()) || !AnalyseTypeEnum.getAreaType().contains(target.getAnalyseType())) {
                if (!StringUtil.isEmpty(qfEnterpriseInfo.getContinent())) {
                    qfFinancialStatistical.setEnterpriseArea(Integer.parseInt(qfEnterpriseInfo.getContinent()));
                }
                qfFinancialStatistical.setEnterpriseType(qfEnterpriseInfo.getBusinessType());
                dataList.add(qfFinancialStatistical);
            }
        });
    }

    /**
     * 修改财务统计数据
     *
     * @param target
     * @param dataList
     * @param statisticalList
     * @param list
     * @param dataType
     * @param dataInfoVo
     * @param enterpriseInfoMap
     */
    private void updateFinancialStatistical(SysSubjectTarget target,
                                            List<QfFinancialStatistical> dataList,
                                            List<QfFinancialStatistical> statisticalList,
                                            List<ReportVo> list,
                                            Integer dataType,
                                            DataInfoVo dataInfoVo,
                                            Map<String, QfEnterpriseInfo> enterpriseInfoMap) {

        if (CollectionUtils.isEmpty(statisticalList)) {
            return;
        }

        Map<String, List<ReportVo>> enterpriseReportMap = list.stream().collect(Collectors.groupingBy(ReportVo::getEnterpriseCode));
        //将已经产生的大屏统计数据根据企业编号分组
        Map<String, List<QfFinancialStatistical>> statisticalMap = statisticalList.stream().collect(Collectors.groupingBy(QfFinancialStatistical::getEnterpriseCode));
        String targetCalculation = target.getTargetCalculation();
        List<String> expressionKey = CommonUtil.getExpressionKey(targetCalculation);
        enterpriseReportMap.forEach((enterpriseCode, financialVoList) -> {
            if (!enterpriseInfoMap.containsKey(enterpriseCode)) {
                return;
            }
            //获取对应企业信息
            QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(enterpriseCode);
            //获取当前企业相关的大屏统计数据
            List<ReportVo> reportVos = enterpriseReportMap.get(enterpriseCode);
            if (statisticalMap.containsKey(enterpriseCode)) {
                List<QfFinancialStatistical> statisticals = statisticalMap.get(enterpriseCode);
                //将已产生的企业大屏数据根据指标进行map转换，获取对应企业当前指标的统计数据
                Map<String, QfFinancialStatistical> faMap = statisticals.stream().collect(Collectors.toMap(item -> item.getTargetId(), item -> item));
                QfFinancialStatistical qfFinancialStatistical = null;
                //判断当前指标是否已经产生数据，没有则新增，有则进行修改
                if (faMap.containsKey(target.getId())) {
                    qfFinancialStatistical = faMap.get(target.getId());
                    //公式发生改变需要清空 计算值
                    processFormulaChange(targetCalculation, qfFinancialStatistical);
                    qfFinancialStatistical.setTempCalculation(targetCalculation);
                } else {
                    qfFinancialStatistical = new QfFinancialStatistical();
                    qfFinancialStatistical.setTempCalculation(targetCalculation);
                    qfFinancialStatistical.setEnterpriseCode(enterpriseCode);
                    qfFinancialStatistical.setLastTime(LocalDateTime.now());
                    createInfo(target, dataInfoVo, qfFinancialStatistical);
                }
                calculateData(dataType, targetCalculation, expressionKey, reportVos, qfFinancialStatistical);
                if (!StringUtil.isNotEmpty(target.getAnalyseType()) || !AnalyseTypeEnum.getAreaType().contains(target.getAnalyseType())) {
                    if (!StringUtil.isEmpty(qfEnterpriseInfo.getContinent())) {
                        qfFinancialStatistical.setEnterpriseArea(Integer.parseInt(qfEnterpriseInfo.getContinent()));
                    }
                    qfFinancialStatistical.setEnterpriseType(qfEnterpriseInfo.getBusinessType());
                    qfFinancialStatistical.setLastTime(LocalDateTime.now());
                    dataList.add(qfFinancialStatistical);
                }
            }
        });
    }

    /**
     * 指标公式方式改变时 再次导入时更新指标计算公式并按照新指标公式进行计算
     *
     * @param targetCalculation
     * @param qfFinancialStatistical
     */
    private void processFormulaChange(String targetCalculation, QfFinancialStatistical qfFinancialStatistical) {
        if (null == qfFinancialStatistical) {
            return;
        }
        if (StringUtil.isEmpty(targetCalculation)) {
            return;
        }
        if (StringUtils.isEmpty(qfFinancialStatistical.getTempCalculation())) {
            return;
        }
        if (qfFinancialStatistical.getTempCalculation().equals(targetCalculation)) {
            return;
        }
        qfFinancialStatistical.setYtdTargetCalculation(null);
        qfFinancialStatistical.setTargetCalculation(null);
        qfFinancialStatistical.setActualYtd(null);
        qfFinancialStatistical.setBudgetYtd(null);
        qfFinancialStatistical.setActual(null);
        qfFinancialStatistical.setBudget(null);
    }

    /**
     * 根据公式计算大屏企业指标数据
     *
     * @param dataType
     * @param targetCalculation
     * @param expressionKey
     * @param financialVoList
     * @param qfFinancialStatistical
     */
    private void calculateData(Integer dataType,
                               String targetCalculation,
                               List<String> expressionKey,
                               List<ReportVo> financialVoList,
                               QfFinancialStatistical qfFinancialStatistical) {
        theMonthValue(dataType, targetCalculation, expressionKey, financialVoList, qfFinancialStatistical);
        ytdValue(dataType, targetCalculation, expressionKey, financialVoList, qfFinancialStatistical);
    }

    /**
     * 当月值计算
     *
     * @param dataType
     * @param targetCalculation
     * @param expressionKey
     * @param financialVoList
     * @param statistical
     */
    private void theMonthValue(Integer dataType, String targetCalculation, List<String> expressionKey, List<ReportVo> financialVoList, QfFinancialStatistical statistical) {
        String targetCalculationJson = statistical.getTargetCalculation();
        Map<Integer, Map<String, BigDecimal>> map = JSONObject.parseObject(targetCalculationJson, Map.class);
        Map<String, BigDecimal> targetCalculationMap = Maps.newHashMap();
        if (CollectionUtils.isEmpty(map)) {
            map = Maps.newHashMap();
        } else {
            if (map.containsKey(dataType) && null != map.get(dataType)) {
                targetCalculationMap = map.get(dataType);
            }
        }
        Map<String, List<ReportVo>> containsSubjectMap = buildContainsSubjectMap(expressionKey, financialVoList);
        for (String key : expressionKey) {
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            if (!containsSubjectMap.containsKey(key)) {
                continue;
            }
            List<ReportVo> list = containsSubjectMap.get(key);
            key = "U" + key;
            for (ReportVo financialVo : list) {

                if (StringUtils.isEmpty(financialVo.getSubjectCode()) || !financialVo.getSubjectCode().equals(key.substring(1))) {
                    continue;
                }
                if (ACTUAL_TYPE.equals(dataType) && null == financialVo.getActual()) {
                    financialVo.setActual(BigDecimal.ZERO);
                }

                if (BUDGET_TYPE.equals(dataType) && null == financialVo.getBudget()) {
                    financialVo.setBudget(BigDecimal.ZERO);
                }

                if(financialVo.getEnterpriseCode().equals("CIGR") && financialVo.getSubjectCode().equals("PL3300S")){
                    System.out.println(1);
                }

                if (CollectionUtils.isEmpty(map)) {
                    targetCalculationMap.put(key, ACTUAL_TYPE .equals(dataType) ? financialVo.getActual() : financialVo.getBudget());
                    map.put(dataType, targetCalculationMap);
                } else {
                    Map<String, BigDecimal> stringBigDecimalMap = map.get(dataType);
                    if (!CollectionUtils.isEmpty(stringBigDecimalMap)) {
                        //将之前已经计算的用新数据替换
                        for (Map.Entry<String, BigDecimal> entry : stringBigDecimalMap.entrySet()) {
                            if (!key.equals(entry.getKey())) {
                                continue;
                            }
                            targetCalculationMap.put(entry.getKey(), ACTUAL_TYPE .equals(dataType) ? financialVo.getActual() : financialVo.getBudget());
                            break;
                        }
                        //在替换掉之前已计算公式后，如果当前数据之前未加入计算公式，则继续新增
                        if (!targetCalculationMap.containsKey(key)) {
                            targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActual() : financialVo.getBudget());
                        } else {
                            targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActual() : financialVo.getBudget());
                        }
                        map.put(dataType, targetCalculationMap);
                    } else {
                        targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActual() : financialVo.getBudget());
                    }
                }
            }
        }
        //补0操作
        if (CollectionUtils.isEmpty(containsSubjectMap)) {
            for (String key : expressionKey) {
                key = "U" + key;
                if (!targetCalculationMap.containsKey(key)) {
                    targetCalculationMap.put(key, BigDecimal.ZERO);
                }
            }
        }
        targetCalculation = CommonUtil.replaceExpression(expressionKey, targetCalculation);
        map.put(dataType, targetCalculationMap);
        statistical.setTargetCalculation(JSON.toJSONString(map));
        if (!StringUtil.isNotEmpty(targetCalculation)) {
            return;
        }
        //1.需要单独公式计算的不在此次计算范围内 2.计算公式数量=匹配上的科目数量
        if ((!StringUtil.isNotEmpty(statistical.getAnalyseType()) || AnalyseTypeEnum.getAreaType().contains(statistical.getAnalyseType()))) {
            BigDecimal bigDecimal = CommonUtil.convertToCode(targetCalculation, targetCalculationMap, 4);
            bigDecimal = findByUnitCalculate(statistical, bigDecimal);
            if (ACTUAL_TYPE.equals(dataType)) {
                statistical.setActual(bigDecimal);
            } else if (BUDGET_TYPE.equals(dataType)) {
                statistical.setBudget(bigDecimal);
            }
        }
    }

    /**
     * 累计值计算
     *
     * @param dataType
     * @param targetCalculation
     * @param expressionKey
     * @param financialVoList
     * @param statistical
     */
    private void ytdValue(Integer dataType, String targetCalculation, List<String> expressionKey, List<ReportVo> financialVoList, QfFinancialStatistical statistical) {
        String targetCalculationJson = statistical.getYtdTargetCalculation();
        Map<Integer, Map<String, BigDecimal>> map = JSONObject.parseObject(targetCalculationJson, Map.class);
        Map<String, BigDecimal> targetCalculationMap = Maps.newHashMap();
        if (CollectionUtils.isEmpty(map)) {
            map = Maps.newHashMap();
        } else {
            if (map.containsKey(dataType) && null != map.get(dataType)) {
                targetCalculationMap = map.get(dataType);
            }
        }
        Map<String, List<ReportVo>> containsSubjectMap = buildContainsSubjectMap(expressionKey, financialVoList);

        for (String key : expressionKey) {
            if (StringUtils.isEmpty(key) || !containsSubjectMap.containsKey(key)) {
                continue;
            }
            List<ReportVo> list = containsSubjectMap.get(key);
            key = "U" + key;
            for (ReportVo financialVo : list) {

                if (StringUtils.isEmpty(financialVo.getSubjectCode()) || !financialVo.getSubjectCode().equals(key.substring(1))) {
                    continue;
                }
                if (ACTUAL_TYPE.equals(dataType) && null == financialVo.getActualYtd()) {
                    financialVo.setActualYtd(BigDecimal.ZERO);
                }
                if (BUDGET_TYPE.equals(dataType) && null == financialVo.getBudgetYtd()) {
                    financialVo.setBudgetYtd(BigDecimal.ZERO);
                }

                if (CollectionUtils.isEmpty(map)) {
                    targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActualYtd() : financialVo.getBudgetYtd());
                    map.put(dataType, targetCalculationMap);
                } else {
                    Map<String, BigDecimal> stringBigDecimalMap = map.get(dataType);
                    if (!CollectionUtils.isEmpty(stringBigDecimalMap)) {
                        //将之前已经计算的用新数据替换
                        for (Map.Entry<String, BigDecimal> entry : stringBigDecimalMap.entrySet()) {
                            if (!key.equals(entry.getKey())) {
                                continue;
                            }
                            targetCalculationMap.put(entry.getKey(), ACTUAL_TYPE.equals(dataType) ? financialVo.getActualYtd() : financialVo.getBudgetYtd());
                            break;
                        }
                        //在替换掉之前已计算公式后，如果当前数据之前未加入计算公式，则继续新增
                        if (!targetCalculationMap.containsKey(key)) {
                            targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActualYtd() : financialVo.getBudgetYtd());
                        } else {
                            targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActualYtd() : financialVo.getBudgetYtd());
                        }
                        map.put(dataType, targetCalculationMap);
                    } else {
                        targetCalculationMap.put(key, ACTUAL_TYPE.equals(dataType) ? financialVo.getActualYtd() : financialVo.getBudgetYtd());
                    }
                }
            }
        }
        //补0操作
        if (CollectionUtils.isEmpty(containsSubjectMap)) {
            for (String key : expressionKey) {
                key = "U" + key;
                if (!targetCalculationMap.containsKey(key)) {
                    targetCalculationMap.put(key, BigDecimal.ZERO);
                }
            }
        }

        targetCalculation = CommonUtil.replaceExpression(expressionKey, targetCalculation);
        map.put(dataType, targetCalculationMap);
        statistical.setYtdTargetCalculation(JSON.toJSONString(map));
        if (!StringUtil.isNotEmpty(targetCalculation)) {
            return;
        }
        //1.需要单独公式计算的不在此次计算范围内 2.计算公式数量=匹配上的科目数量
        if ((!StringUtil.isNotEmpty(statistical.getAnalyseType()) || AnalyseTypeEnum.getAreaType().contains(statistical.getAnalyseType()))) {
            BigDecimal bigDecimal = CommonUtil.convertToCode(targetCalculation, targetCalculationMap, 4);
            bigDecimal = findByUnitCalculate(statistical, bigDecimal);
            if (ACTUAL_TYPE.equals(dataType)) {
                statistical.setActualYtd(bigDecimal);
            } else if (BUDGET_TYPE.equals(dataType)) {
                statistical.setBudgetYtd(bigDecimal);
            }
        }
    }

    private BigDecimal findByUnitCalculate(QfFinancialStatistical statistical, BigDecimal bigDecimal) {
        if (StringUtil.isNotEmpty(statistical.getTargetCalculation()) && "%".equals(statistical.getTargetUnit())) {
            //如果不是增长率且单位是%的 需要*100
            bigDecimal = bigDecimal.multiply(new BigDecimal(100));
        }
        if ("天".equals(statistical.getTargetUnit())) {
            if (null != bigDecimal && bigDecimal.doubleValue() != 0) {
                bigDecimal = new BigDecimal(60).multiply(new BigDecimal(statistical.getMonth())).divide(bigDecimal, 2, BigDecimal.ROUND_HALF_UP);
            }
        }
        if ("次".equals(statistical.getTargetUnit())) {
            bigDecimal = bigDecimal.multiply(new BigDecimal(100));
        }
        return bigDecimal;
    }

    /**
     * 从导入的数据中 获取当前指标包含的所有科目数据
     *
     * @param expressionKey
     * @param financialVoList
     * @return
     */
    private Map<String, List<ReportVo>> buildContainsSubjectMap(List<String> expressionKey, List<ReportVo> financialVoList) {
        Map<String, List<ReportVo>> subjectMap = financialVoList.stream().collect(Collectors.groupingBy(ReportVo::getSubjectCode));
        Map<String, List<ReportVo>> containsSubjectMap = Maps.newHashMap();
        for (String key : expressionKey) {
            if (!subjectMap.containsKey(key)) {
                continue;
            }
            containsSubjectMap.put(key, subjectMap.get(key));
        }
        return containsSubjectMap;
    }

    private void createInfo(SysSubjectTarget target, DataInfoVo dataInfoVo, QfFinancialStatistical qfFinancialStatistical) {
        qfFinancialStatistical.setTargetId(target.getId());
        qfFinancialStatistical.setTargetLevel(target.getTargetLevel());
        qfFinancialStatistical.setTargetName(target.getName());
        qfFinancialStatistical.setTargetNameEn(target.getTargetNameEn());
        qfFinancialStatistical.setTargetUnit(target.getUnit());
        qfFinancialStatistical.setType(target.getType());
        qfFinancialStatistical.setStaLat(target.getStaLat());
        qfFinancialStatistical.setAnalyseType(target.getAnalyseType());
        qfFinancialStatistical.setLargerType(target.getLargerType());
        qfFinancialStatistical.setParentTargetId(target.getParentId());
        qfFinancialStatistical.setYear(dataInfoVo.getYear());
        qfFinancialStatistical.setQuarter(dataInfoVo.getQuarter());
        qfFinancialStatistical.setMonth(dataInfoVo.getMonth());
    }

    /**
     * 下级指标
     *
     * @param t
     * @return
     */
    @Override
    public List<FaTargetRespVo> fromUnderData(ReportReqVo t) {
        Assert.hasText(t.getTargetId(), "请选择要统计的指标id");
        SysSubjectTarget target = sysSubjectTargetManager.get(t.getTargetId());
        Assert.notNull(target, "当前指标不存在");
        if (StringUtils.isEmpty(target.getType())) {
            return Lists.newArrayList();
        }
        enterpriseInfoMap = enterpriseInfoManager.getEnterpriseInfoMap(null);
        QfEnterpriseInfo group = enterpriseInfoManager.getGroup();
        if (StringUtil.isEmpty(t.getEnterpriseCode()) || group.getCode().equals(t.getEnterpriseCode())) {
            t.setEnterpriseCode(group.getCode());
            t.setType(2);
        } else {
            t.setType(1);
        }
        List<String> typeList = Arrays.asList(target.getType().split(","));
        //获取下级指标 区域特殊处理
        List<SysSubjectTarget> lowerLevelTargetList = sysSubjectTargetManager.lowerLevelTargetList(target.getSubjectId());
        if (!StringUtil.isEmpty(target.getRelatedCode())) {
            QueryWrapper<SysSubjectTarget> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code_", target.getRelatedCode());
            SysSubjectTarget relatedTarget = sysSubjectTargetManager.getOne(queryWrapper);
            if (null != relatedTarget) {
                relatedTarget.setSn(99);
                lowerLevelTargetList.add(relatedTarget);
            }
        }

        if (target.getCode().equals(PRODUCT_SALES_REVENUE) && 1 == t.getType()) {
            lowerLevelTargetList = Lists.newArrayList();
        }
        if (!CollectionUtils.isEmpty(lowerLevelTargetList)) {
            List<String> newTypeList = Lists.newArrayList();
            for (int i = 0; i < typeList.size(); i++) {
                if (i <= 2) {
                    newTypeList.add(typeList.get(i));
                }
            }
            typeList = Lists.newArrayList(newTypeList);
        }

        List<FaTargetRespVo> list = currentTargetAnalysis(target, typeList, t, lowerLevelTargetList, false);

        lowerLevelTargetList.forEach(lowerLevelTarget -> {
            List<String> newTypeList = Lists.newArrayList();
            if ("Finance".equals(lowerLevelTarget.getBusiness())) {
                String[] type = new String[]{"5"};
                newTypeList = Arrays.asList(type);
            } else if ("money".equals(lowerLevelTarget.getBusiness())) {
                String[] type = new String[]{lowerLevelTarget.getType().split(",")[0]};
                newTypeList = Arrays.asList(type);
            }
            t.setTargetId(lowerLevelTarget.getId());
            list.addAll(currentTargetAnalysis(lowerLevelTarget, newTypeList, t, null, true));
        });
        if (!CollectionUtils.isEmpty(list)) {
            FaTargetRespVo faTargetRespVo = list.get(0);
            if (CollectionUtils.isEmpty(lowerLevelTargetList)) {
                faTargetRespVo.setLowerStatus("0");
                faTargetRespVo.setIsData("0");
            } else {
                faTargetRespVo.setLowerStatus("1");
                if (Arrays.asList(target.getType().split(",")).size() <= 3) {
                    faTargetRespVo.setIsData("0");
                } else {
                    faTargetRespVo.setIsData("1");
                }
            }

        }
        list.forEach(resp -> {
            if (resp.getContainType().contains(FaTargetTypeEnum.qt.getType().toString())) {
                resp.setBridgeFigure("1");
            } else {
                resp.setBridgeFigure("0");
            }
        });
        return list;
    }

    /**
     * 当前指标分析
     *
     * @param target
     * @param typeList
     * @param current  是否是下级指标 true：是 false:否
     */
    private List<FaTargetRespVo> currentTargetAnalysis(SysSubjectTarget target, List<String> typeList,
                                                       ReportReqVo t, List<SysSubjectTarget> lowerLevelTargetList, boolean current) {
        List<FaTargetRespVo> resultList = Lists.newArrayList();
        typeList.forEach(type -> {

            FaTargetTypeEnum targetTypeEnum = FaTargetTypeEnum.getTarget(type);
            if (null == targetTypeEnum) {
                return;
            }
            switch (targetTypeEnum) {
                case dysj:
                    monthAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case ljsj:
                    monthYtdAnalysis(target, t, resultList, targetTypeEnum, current);
                    break;
                case tbfx:
                    comparedAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case hbfx:
                    sequentialAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case ndsj:
                    yearAnalysis(target, t, resultList, targetTypeEnum, current);
                    break;
                case scqysj:
                    productionEnterpriseAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case fscqysj:
                    nonProductionEnterpriseAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case zzlfx:
                    growthRateAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case jtwclfx:
                    groupCompletion(target, t, resultList, targetTypeEnum);
                    break;
                case zqywclfx:
                    enterpriseCompletion(target, t, resultList, targetTypeEnum);
                    break;
                case zbfx:
                    ratioAnalysis(target, t, resultList, targetTypeEnum, lowerLevelTargetList);
                    break;
                case zqydysj:
                    meanRankAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case ndsy:
                    yearAnalysis(target, t, resultList, targetTypeEnum, current);
                    break;
                case jdlj:
                    realTimeBalance(target, t, resultList, targetTypeEnum, current);
                    break;
                case zqylj:
                    companyAnalysis(target, t, resultList, targetTypeEnum, current);
                    break;
                case yhdk:
                    bankAnalysis(target, t, resultList, targetTypeEnum);
                    break;
                case yhyk:
                    bankAnnualFigure(target, t, resultList, targetTypeEnum);
                    break;
                case oyll:
                    euroRatesAnalysis(target, t, resultList, targetTypeEnum);
                    break;

                default:
                    break;
            }
        });
        return resultList;
    }

    private void euroRatesAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        if(null == t.getYear()) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }
        List<EuroRatesRespVo> euroRespList = this.euroRatesdManager.euroRatesAnalysis(t);
        Map<Integer, List<EuroRatesRespVo>> map = euroRespList.stream().collect(Collectors.groupingBy(EuroRatesRespVo::getMonth));
        List<EuroRatesRespVo> data = Lists.newArrayList();
        map.forEach((month, v) -> {
            EuroRatesRespVo ratesRespVo = new EuroRatesRespVo();
            ratesRespVo.setMonth(month);
            v.forEach(euroRatesRespVo -> {
                if (StringUtils.isEmpty(euroRatesRespVo.getType())) {
                    return;
                }

                if ("1M".equals(euroRatesRespVo.getType())) {
                    ratesRespVo.setOneActual(euroRatesRespVo.getFillData());
                }
                if ("3M".equals(euroRatesRespVo.getType())) {
                    ratesRespVo.setThreeActual(euroRatesRespVo.getFillData());
                }
                if ("6M".equals(euroRatesRespVo.getType())) {
                    ratesRespVo.setSixActual(euroRatesRespVo.getFillData());
                }
            });
            data.add(ratesRespVo);
        });

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, null);
        resultFa.setEuroRatesList(data);
        resultList.add(resultFa);
    }

    private void bankAnnualFigure(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(null);
        String dataType = null;
        if ("M003".equals(target.getCode())) {
            dataType = "1";
        }
        List<FaReportRespVo> bankLoanList = this.loandManager.bankAnnualFigure(t, dataType);
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, null);
        resultFa.setResultData(bankLoanList);
        resultList.add(resultFa);
    }

    private void bankAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        if (!t.getType().equals(CIGR_TYPE)) {
            return;
        }
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(null);
        String dataType = null;
        if ("M003".equals(target.getCode())) {
            dataType = "1";
        } else if ("M006".equals(target.getCode())) {
            dataType = "2";
        }
        List<BankLoanDetailRespVo> bankLoanList = this.loandManager.bankDetail(t, dataType);
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, null);
        resultFa.setBankLoanList(bankLoanList);
        resultList.add(resultFa);

    }

    private void companyAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum, boolean current) {
        if (t.getType().equals(1)) {
            return;
        }
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(null);
        List<FaReportRespVo> reportRespVos = Lists.newArrayList();
        String dataType = null;
        if ("M003".equals(target.getCode())) {
            reportRespVos = this.loandManager.dbzeQuarterCompanyAnalysis(t);
        } else if ("M006".equals(target.getCode())) {
            dataType = "2";
            reportRespVos = this.loandManager.dkyeQuarterCompanyAnalysis(t, dataType);
        }
        BigDecimal totalMoney = BigDecimal.ZERO;
        for (FaReportRespVo report : reportRespVos) {
            report.setTargetId(target.getId());
            report.setYear(t.getYear());
            report.setBudget(null);
            QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(report.getEnterpriseCode());
            if (null != qfEnterpriseInfo) {
                report.setEnterpriseName(qfEnterpriseInfo.getShortName());
            }
            totalMoney = totalMoney.add(report.getActual());
        }
        FaTargetRespVo resultFa = null;
        if (current) {
            resultFa = financialTimeUtils.getFaTargetRespVo(target, type, reportRespVos);
            resultFa.setStaLat(target.getStaLat().trim());
        } else {
            resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        }
        resultFa.setTotalMoney(totalMoney);
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 年度实时余额分析 15
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void realTimeBalance(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum, boolean current) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(null);
        if (t.getType().equals(CIGR_TYPE)) {
            t.setEnterpriseCode(null);
        }
        boolean flag = false;
        List<FaReportRespVo> reportRespVos = Lists.newArrayList();
        if ("M003".equals(target.getCode())) {
            reportRespVos = this.loandManager.nbwdYearAnalysis(t);
            flag = true;
        } else if ("M006".equals(target.getCode())) {
            reportRespVos = this.loandManager.zzrzYearAnalysis(t);
        }
        FaTargetRespVo resultFa = null;
        if (current) {
            resultFa = financialTimeUtils.getFaTargetRespVo(target, type, reportRespVos);
            resultFa.setStaLat(target.getStaLat().trim());
        } else {
            resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        }
        reportRespVos.forEach(report -> {
            report.setTargetId(target.getId());
            report.setDifferenceRate(null);
            report.setDifferenceValue(null);
        });
        resultFa.setResultData(reportRespVos);
        if (flag) {
            resultFa.setControlMoney(new BigDecimal("13000"));
            BigDecimal earlyGuaranteeMoney = this.loandManager.getEarlyGuaranteeMoney(t.getYear());
            resultFa.setEarlyGuaranteeMoney(earlyGuaranteeMoney);
        }

        resultList.add(resultFa);
    }

    /**
     * 子企业当月实际VS集团均值分析（排名）
     * //均值取每年预算第一个月的 均值科目
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum 12
     */
    private void meanRankAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        if (t.getType().equals(1)) {
            return;
        }
        t.setTargetId(target.getId());
        BigDecimal meanRank = plsManager.getMeanRank(t, target);
        List<FaReportRespVo> reportRespVos = this.baseMapper.meanRankAnalysis(t);
        if (!CollectionUtils.isEmpty(reportRespVos)) {
            reportRespVos.forEach(report -> {
                report.setBudget(meanRank);
                if (null == report.getActual()) {
                    report.setActual(BigDecimal.ZERO);
                }
                QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(report.getEnterpriseCode());
                if (null != qfEnterpriseInfo) {
                    report.setEnterpriseName(qfEnterpriseInfo.getShortName());
                }
            });
            reportRespVos.sort(Comparator.comparing(FaReportRespVo::getActual));
        }

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setTargetUnit("%");
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 占比分析
     * 当月 实际 预算
     *
     * @param t
     * @param resultList
     * @param targetTypeEnum 11
     */
    private void ratioAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum, List<SysSubjectTarget> lowerLevelTargetList) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        if (t.getType().equals(COMPANY_TYPE) && PRODUCT_SALES_REVENUE.equals(target.getCode())) {
            return;
        }
        if (t.getType().equals(CIGR_TYPE) && PRODUCT_SALES_REVENUE.equals(target.getCode())) {
            t.setEnterpriseCode(null);
        }
        if (CollectionUtils.isEmpty(lowerLevelTargetList)) {
            return;
        }

        List<String> targetIds = lowerLevelTargetList.stream().map(SysSubjectTarget::getId).collect(Collectors.toList());
        List<FaReportRespVo> targetData = this.baseMapper.targetData(t, targetIds);
        List<FaReportRespVo> targetAllData = this.baseMapper.targetAllData(t);

        Map<Integer, List<FaReportRespVo>> monthMap = targetData.stream().collect(Collectors.groupingBy(FaReportRespVo::getMonth));
        List<FaReportRespVo> reportRespVos = Lists.newArrayList();
        //获取当前指标实际和预算值
        Map<Integer, BigDecimal> currentTargetActualMap = Maps.newHashMap();
        Map<Integer, BigDecimal> currentTargetBudgetMap = Maps.newHashMap();
        targetAllData.forEach(qfFinancialStatistical -> {
            BigDecimal actual = BigDecimal.ZERO;
            BigDecimal budget = BigDecimal.ZERO;
            if (null != qfFinancialStatistical.getActual()) {
                actual = qfFinancialStatistical.getActual();
            }
            if (null != qfFinancialStatistical.getBudget()) {
                budget = qfFinancialStatistical.getBudget();
            }
            currentTargetActualMap.put(qfFinancialStatistical.getMonth(), actual);
            currentTargetBudgetMap.put(qfFinancialStatistical.getMonth(), budget);
        });

        Map<Integer, BigDecimal> targetActualMap = Maps.newHashMap();
        Map<Integer, BigDecimal> targetBudgetMap = Maps.newHashMap();
        monthMap.forEach((month, v) -> {
            targetActualMap.put(month, v.stream().map(FaReportRespVo::getActual).reduce(BigDecimal.ZERO, BigDecimal::add));
            targetBudgetMap.put(month, v.stream().map(FaReportRespVo::getBudget).reduce(BigDecimal.ZERO, BigDecimal::add));
        });
        Map<String, List<FaReportRespVo>> targetMap = targetData.stream().collect(Collectors.groupingBy(FaReportRespVo::getTargetId));
        targetMap.forEach((targetId, v) -> {
            Map<Integer, FaReportRespVo> collect = v.stream().collect(Collectors.toMap(item -> item.getMonth(), item -> item));
            collect.forEach((k, qfFinancialStatistical) -> {
                FaReportRespVo faReportRespVo = new FaReportRespVo();
                if (null == qfFinancialStatistical.getBudget()) {
                    qfFinancialStatistical.setBudget(BigDecimal.ZERO);
                }
                if (null == qfFinancialStatistical.getActual()) {
                    qfFinancialStatistical.setActual(BigDecimal.ZERO);
                }
                faReportRespVo.setTargetId(qfFinancialStatistical.getTargetId());
                faReportRespVo.setTargetName(qfFinancialStatistical.getTargetName());
                faReportRespVo.setTargetNameEn(qfFinancialStatistical.getTargetNameEn());
                BigDecimal actual = BigDecimal.ZERO;
                BigDecimal budget = BigDecimal.ZERO;
                if (null != currentTargetActualMap.get(k) && 0 != currentTargetActualMap.get(k).doubleValue()) {
                    actual = qfFinancialStatistical.getActual().divide(currentTargetActualMap.get(k), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                }

                if (null != currentTargetBudgetMap.get(k) && 0 != currentTargetBudgetMap.get(k).doubleValue()) {
                    budget = qfFinancialStatistical.getBudget().divide(currentTargetBudgetMap.get(k), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                }
                faReportRespVo.setActual(actual);
                faReportRespVo.setBudget(budget);
                faReportRespVo.setMonth(k);
                faReportRespVo.setYear(qfFinancialStatistical.getYear());
                reportRespVos.add(faReportRespVo);
            });
        });

        if (!target.getCode().equals(PRODUCT_SALES_REVENUE)) {
            monthMap.forEach((k, v) -> {
                FaReportRespVo faReportRespVo = new FaReportRespVo();
                faReportRespVo.setTargetName("其他");
                faReportRespVo.setTargetNameEn("other");
                BigDecimal otherActual = BigDecimal.ZERO;
                BigDecimal otherbudget = BigDecimal.ZERO;
                if (null != currentTargetActualMap.get(k) && null != currentTargetBudgetMap.get(k) && 0 != currentTargetActualMap.get(k).doubleValue() && 0 != currentTargetBudgetMap.get(k).doubleValue()) {
                    otherActual = currentTargetActualMap.get(k).subtract(targetActualMap.get(k));
                    otherbudget = currentTargetBudgetMap.get(k).subtract(targetBudgetMap.get(k));
                    otherActual = otherActual.divide(currentTargetActualMap.get(k), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    otherbudget = otherbudget.divide(currentTargetBudgetMap.get(k), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                }
                faReportRespVo.setActual(otherActual);
                faReportRespVo.setBudget(otherbudget);
                faReportRespVo.setMonth(k);
                faReportRespVo.setYear(t.getYear());
                reportRespVos.add(faReportRespVo);
            });
        }
        target.setUnit("%");
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 子企业完成率
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void enterpriseCompletion(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        if (t.getType().equals(1)) {
            return;
        }
        t.setTargetId(target.getId());
        target.setUnit("%");
        List<FaReportRespVo> reportRespVos = this.baseMapper.enterpriseCompletion(t);
        if (!CollectionUtils.isEmpty(reportRespVos)) {
            reportRespVos.forEach(report -> {
                if (null == report.getBudget()) {
                    report.setBudget(BigDecimal.ZERO);
                }
                if (report.getBudget().doubleValue() == 0) {
                    report.setActual(BigDecimal.ZERO);
                } else {
                    report.setActual(report.getActual().divide(report.getBudget(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
                }
                report.setBudget(null);
                QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(report.getEnterpriseCode());
                if (null != qfEnterpriseInfo) {
                    report.setEnterpriseName(qfEnterpriseInfo.getShortName());
                }
            });
            reportRespVos.sort(Comparator.comparing(FaReportRespVo::getActual));
        }

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 集团层面完成率
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void groupCompletion(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        if (t.getType().equals(1)) {
            return;
        }
        t.setTargetId(target.getId());
        List<FaReportRespVo> reportRespVos = this.baseMapper.groupCompletion(t);

        if (!CollectionUtils.isEmpty(reportRespVos)) {
            reportRespVos.forEach(report -> {
                if (null == report.getBudget()) {
                    report.setBudget(BigDecimal.ZERO);
                }
                if (report.getBudget().doubleValue() == 0) {
                    report.setActual(BigDecimal.ZERO);
                } else {
                    report.setActual(report.getActual().divide(report.getBudget(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
                }
                report.setBudget(null);
            });
        }

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setTargetUnit("%");
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 增长率分析
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void growthRateAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        target.setUnit("%");
        List<FaReportRespVo> monthData = this.baseMapper.growthRateAnalysis(t);
        List<FaReportRespVo> reportRespVos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(monthData)) {
            Map<Integer, FaReportRespVo> respVoMap = monthData.stream().collect(Collectors.toMap(item -> item.getYear(), item -> item));
            for (int i = t.getStartYear(); i <= t.getEndYear(); i++) {
                if (i == t.getStartYear()) {
                    continue;
                }
                FaReportRespVo faReportRespVo = new FaReportRespVo();
                BigDecimal currentMonthActual = BigDecimal.ZERO;
                BigDecimal lastMonthActual = BigDecimal.ZERO;
                if (respVoMap.containsKey(i) && null != respVoMap.get(i).getActual()) {
                    currentMonthActual = respVoMap.get(i).getActual();
                }
                if (respVoMap.containsKey(i - 1) && null != respVoMap.get(i - 1).getActual()) {
                    lastMonthActual = respVoMap.get(i - 1).getActual();
                }
                faReportRespVo.setMonth(t.getMonth());
                faReportRespVo.setYear(i);
                faReportRespVo.setTargetId(t.getTargetId());
                if (null == lastMonthActual || lastMonthActual.doubleValue() == 0) {
                    faReportRespVo.setActual(BigDecimal.ZERO);
                } else {
                    faReportRespVo.setActual(currentMonthActual.subtract(lastMonthActual).divide(lastMonthActual, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
                }

                faReportRespVo.setBudget(null);
                reportRespVos.add(faReportRespVo);
            }
        }

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setTargetUnit("%");
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 非生产企业实际VS预算分析:展示当前指标子企业实际预算累计值,查询条件：1、年份 2、月份范围（默认去年1-12月）
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void nonProductionEnterpriseAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        if (t.getType().equals(1)) {
            return;
        }
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(null);
        List<FaReportRespVo> reportRespVos = this.baseMapper.enterpriseAnalysis(t);
        reportRespVos.forEach(resp -> {
            QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(resp.getEnterpriseCode());
            if (null != qfEnterpriseInfo) {
                resp.setEnterpriseName(qfEnterpriseInfo.getShortName());
            }
        });
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        reportRespVos.sort(Comparator.nullsLast(Comparator.comparing(FaReportRespVo::getDifferenceValue)));
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 生产企业实际VS预算分析:展示当前指标子企业实际预算累计值,查询条件：1、年份 2、月份范围（默认去年1-12月）
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void productionEnterpriseAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        if (t.getType().equals(1)) {
            return;
        }
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        t.setEnterpriseType(1);
        List<FaReportRespVo> reportRespVos = this.baseMapper.enterpriseAnalysis(t);
        reportRespVos.forEach(resp -> {
            QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(resp.getEnterpriseCode());
            if (null != qfEnterpriseInfo) {
                resp.setEnterpriseName(qfEnterpriseInfo.getShortName());
            }
        });
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        reportRespVos.sort(Comparator.nullsLast(Comparator.comparing(FaReportRespVo::getDifferenceValue)));
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 年度实际VS预算分析:展示当前指标该年度实际预算累计值,查询条件：1、企业，2、年份范围，默认5年
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void yearAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum, boolean current) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        List<FaReportRespVo> reportRespVos = this.baseMapper.yearAnalysis(t);
        FaTargetRespVo resultFa = null;
        if (current) {
            resultFa = financialTimeUtils.getFaTargetRespVo(target, type, reportRespVos);
            resultFa.setStaLat("3,4");
            FaTargetRespVo finalResultFa = resultFa;
            reportRespVos.forEach(reportRespVo -> {
                if (null != reportRespVo.getBudget() && null != reportRespVo.getActual()) {
                    BigDecimal differenceValue = reportRespVo.getActual().subtract(reportRespVo.getBudget());
                    reportRespVo.setDifferenceValue(differenceValue);
                    String differenceRate = null;
                    if (0 != reportRespVo.getBudget().doubleValue()) {
                        differenceRate = differenceValue.divide(reportRespVo.getBudget(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")) + "%";
                    }
                    if(!"%".equals(finalResultFa.getTargetUnit())){
                        reportRespVo.setDifferenceRate(differenceRate);
                    }
                }
            });

        } else {
            resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        }
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 环比分析
     * 展示当前指标该月与上月实际值增减情况 查询条件：1、企业，2：年度 3、截止月份 ，默认今年上一月
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void sequentialAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());

        List<FaReportRespVo> monthData = this.baseMapper.sequentialAnalysis(t);
        List<FaReportRespVo> reportRespVos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(monthData)) {

            Map<Integer, FaReportRespVo> respVoMap = monthData.stream().collect(Collectors.toMap(item -> item.getMonth(), item -> item));
            for (int i = 1; i < t.getEndMonth(); i++) {
                if (i == 1) {
                    continue;
                }
                FaReportRespVo faReportRespVo = new FaReportRespVo();
                BigDecimal currentMonthActual = BigDecimal.ZERO;
                BigDecimal lastMonthActual = BigDecimal.ZERO;
                if (respVoMap.containsKey(i) && null != respVoMap.get(i).getActual()) {
                    currentMonthActual = respVoMap.get(i).getActual();
                }
                if (respVoMap.containsKey(i - 1) && null != respVoMap.get(i - 1).getActual()) {
                    lastMonthActual = respVoMap.get(i - 1).getActual();
                }
                faReportRespVo.setMonth(i);
                faReportRespVo.setYear(t.getYear());
                faReportRespVo.setTargetId(t.getTargetId());
                faReportRespVo.setActual(currentMonthActual.subtract(lastMonthActual));
                if (lastMonthActual.doubleValue() != 0) {
                    BigDecimal growthRate = currentMonthActual.subtract(lastMonthActual).divide(lastMonthActual, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                    faReportRespVo.setGrowthRate(growthRate);
                } else {
                    faReportRespVo.setGrowthRate(BigDecimal.ZERO);
                }
                reportRespVos.add(faReportRespVo);
            }
        }
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        reportRespVos.forEach(resp -> {
            resp.setDifferenceRate(null);
        });
        resultFa.setResultData(reportRespVos);
        resultFa.setStaLat("14");
        resultList.add(resultFa);
    }

    /**
     * 同比分析
     * 展示当前指标该月年度累计实际对比上一年同期增减数据 查询条件：1、企业，2、年份范围（去年-今年） 3、月份默认 ，1-12
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void comparedAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());

        List<FaReportRespVo> reportRespVos = this.baseMapper.comparedAnalysis(t);

        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        List<FaReportRespVo> list = Lists.newArrayList();
        Map<Integer, List<FaReportRespVo>> monthMap = reportRespVos.stream().collect(Collectors.groupingBy(FaReportRespVo::getMonth));
        monthMap.forEach((month, v) -> {
            if (v.size() <= 1) {
                return;
            }
            BigDecimal thisYearActual = v.get(v.size() - 1).getActual();
            BigDecimal lastYearActual = v.get(0).getActual();
            BigDecimal growthRate = null;
            if (null == lastYearActual || lastYearActual.doubleValue() == 0) {
                growthRate = BigDecimal.ZERO;
            } else {
                growthRate = thisYearActual.subtract(lastYearActual).divide(lastYearActual, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            }
            for (FaReportRespVo resp : v) {
                resp.setGrowthRate(growthRate);
                resp.setDifferenceRate(null);
                list.add(resp);
            }
        });
        list.sort(Comparator.comparing(FaReportRespVo::getMonth));
        resultFa.setResultData(list);
        resultList.add(resultFa);
    }

    /**
     * 累计实际VS预算分析
     * 展示当前指标该月年度累计实际预算值 查询条件 ：1、企业，2、年份 3、月份范围(起始月-结束月)， 默认上一年 月份：1-12
     *
     * @param target
     * @param t
     * @param resultList
     * @param targetTypeEnum
     */
    private void monthYtdAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum, boolean current) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, type);
        financialTimeUtils.processDateQuery(t, dateReqVo);
        t.setTargetId(target.getId());
        List<FaReportRespVo> reportRespVos = this.baseMapper.monthYtdData(t);
        FaTargetRespVo resultFa = null;
        if (current) {
            resultFa = financialTimeUtils.getFaTargetRespVo(target, type, reportRespVos);
            resultFa.setStaLat("3,4");
        } else {
            resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        }
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

    /**
     * 当月实际VS预算分析 ,查询条件 ：1、企业，2、年份 3、月份范围(起始月-结束月)，默认上一年 ，默认月份：1-12
     *
     * @param target     当前指标
     * @param t          查询条件
     * @param resultList
     */
    private void monthAnalysis(SysSubjectTarget target, ReportReqVo t, List<FaTargetRespVo> resultList, FaTargetTypeEnum targetTypeEnum) {
        String type = targetTypeEnum.getType().toString();
        DateReqVo dateReqVo = financialTimeUtils.processDateReqVo(t, targetTypeEnum.getType().toString());
        financialTimeUtils.processDateQuery(t, dateReqVo);

        t.setTargetId(target.getId());
        List<FaReportRespVo> reportRespVos = this.baseMapper.monthData(t);
        FaTargetRespVo resultFa = financialTimeUtils.getCurrentFaTargetRespVo(targetTypeEnum, target, type, reportRespVos);
        resultFa.setResultData(reportRespVos);
        resultList.add(resultFa);
    }

}


