package com.hzs.bonus.bonus.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.hzs.bonus.bonus.vo.BonusRecordDetailVO;
import com.hzs.common.core.constant.CountryConstants;
import com.hzs.common.core.constant.MagicNumberConstants;
import com.hzs.common.core.constant.SysConstants;
import com.hzs.common.core.constant.msg.BonusMsgConstants;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.domain.bonus.BdBonusDeduct;
import com.hzs.common.domain.bonus.risk.CuMemberRiskControl;
import com.hzs.common.domain.member.base.CuAwardsControl;
import com.hzs.common.domain.member.bonus.*;
import com.hzs.common.domain.member.detail.CuMemberAssess;
import com.hzs.common.domain.member.ext.CuBonusExpandExt;
import com.hzs.common.domain.member.ext.CuMemberSettleExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.common.domain.system.config.BdAwards;
import com.hzs.common.domain.system.config.BdGrade;
import com.hzs.system.config.dto.BonusConfigDTO;
import com.hzs.system.config.dto.BonusExpandDTO;
import com.hzs.system.config.dto.BonusRepurchasePushDTO;
import com.hzs.system.config.dto.RangeDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 计算复购的奖金处理类
 */
@Slf4j
@Component
public class BonusSettlePurchaseHandle extends BonusSettleHandle {

    @Autowired
    private BonusSettleFirstPurchaseHandle bonusSettleFirstPurchaseHandle;

    List<CuMemberBonusPush> calculateRepurchasePushBonusOne(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, BonusConfigDTO bonusConfigDTO,
                                                            Map<Long, CuMemberAssess> cuMemberAssessMap, Integer period, Map<Long, CuMemberBonus> cuMemberBonusMap,
                                                            SaOrderExt saOrderExt) {
        CuMemberSettleExt sourceSettleExt = cuMemberSettleExtMap.get(saOrderExt.getPkMember());
        List<CuMemberBonusPush> cuMemberBonusPushList = new ArrayList<>();
        if (sourceSettleExt == null) {
            return cuMemberBonusPushList;
        }
        BigDecimal orderAchieve = saOrderExt.getOrderAchieve();
        int i = MagicNumberConstants.BLOOD_GENERATION_START;
        Long pkParent = sourceSettleExt.getPkParent();
        while (i <= MagicNumberConstants.BLOOD_GENERATION_END) {
            CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(pkParent);
            if (targetMemberSettleExt == null) {
                break;
            }
            // 死点 停算 顾客 没有奖金
            if (ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                    || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                    || SysConstants.NOT_BONUS_GRADE.contains(targetMemberSettleExt.getGradeValue())) {
                // 会员不满足计算奖金条件，跳过
                pkParent = targetMemberSettleExt.getPkParent();
                continue;
            }
            if (validatePkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.HELP_EACH_INCOME.getValue())) {
                pkParent = targetMemberSettleExt.getPkParent();
                continue;
            }

            CuMemberBonus cuMemberBonus = getCuMemberBonus(period, cuMemberBonusMap, saOrderExt, targetMemberSettleExt);
            // 直推奖金明细
            int pkBonusItem = getPkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.HELP_EACH_INCOME.getValue());
            CuMemberBonusPush cuMemberBonusPush = bonusSettleFirstPurchaseHandle.getCuMemberBonusPush(saOrderExt, targetMemberSettleExt, cuMemberBonus, pkBonusItem);
            Map<Integer, BonusRepurchasePushDTO> repurchasePushMap = bonusConfigDTO.getBonusRepurchasePushMap().get(targetMemberSettleExt.getPkSettleCountry());
            if (!repurchasePushMap.containsKey(i)) {
                break;
            }
            // 复购直推需要修改
            BonusRepurchasePushDTO bonusRepurchasePushDTO = repurchasePushMap.get(i);
            cuMemberBonusPush.setCalType(bonusRepurchasePushDTO.getCalType());
            cuMemberBonusPush.setRound(0);
            cuMemberBonusPush.setSecond(0);
            // 比例
            if (ECalType.RATIO.getValue() == bonusRepurchasePushDTO.getCalType()) {
                cuMemberBonusPush.setCalValue(bonusRepurchasePushDTO.getPushValue());
                cuMemberBonusPush.setPretaxIncome(ComputeUtil.computeBonusMultiply(orderAchieve, bonusRepurchasePushDTO.getPushValue()));
            } else {
                cuMemberBonusPush.setCalValue(BigDecimal.ZERO);
                cuMemberBonusPush.setPretaxIncome(bonusRepurchasePushDTO.getPushValue());
            }
            BdBonusDeduct bdBonusDeduct = setBonusDetailDeduct(bonusConfigDTO, cuMemberBonusPush, saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
            if (EBonusIncomeStatus.NORMAL.getValue() == cuMemberBonusPush.getIncomeStatus()) {
                cuMemberBonus.setRepurPushIncome(ComputeUtil.computeAdd(cuMemberBonus.getRepurPushIncome(), cuMemberBonusPush.getPretaxIncome()));
                setPurchaseTotal(bdBonusDeduct, cuMemberBonus, cuMemberBonusPush);
            }
            repurchasePushRemark(saOrderExt, cuMemberBonusPush, sourceSettleExt, targetMemberSettleExt, BonusMsgConstants.REPURCHASE_PUSH);
            cuMemberBonusPushList.add(cuMemberBonusPush);
            pkParent = targetMemberSettleExt.getPkParent();
            i++;
        }
        return cuMemberBonusPushList;
    }

    /**
     * 计算复购拓展收益
     *
     * @param settleTableName   结算表
     * @param period            期间
     * @param bonusConfigDTO    参数
     * @param purchaseOrderList 首单
     * @param cuMemberBonusMap  所有计算出来的奖金汇总
     */
    List<CuMemberBonusExpand> calculateRepurchaseExpandBonus(Map<Long, CuMemberRiskControl> riskControlMap, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, String settleDateStr,
                                                             BonusConfigDTO bonusConfigDTO, Map<String, String> systemConfigMap, List<SaOrderExt> purchaseOrderList, Integer period,
                                                             Map<Long, CuMemberBonus> weekMemberBonusMap, Map<Long, CuMemberBonus> cuMemberBonusMap, Map<Long, CuBonusExpandExt> cuBonusExpandExtMap) {
        List<CuMemberBonusExpand> cuMemberBonusExpandList = new ArrayList<>();
        // 获取所有订单的上级，根据订单往上一步步计算
        // key：订单ID，value：订单向上找安置人列表（会查询出来延缓发放奖金数据）
        Map<Long, List<CuMemberSettleExt>> memberSettleMap = iCuMemberTreeService.batchQueryCuMemberSettlePlaceParent(settleTableName, period, purchaseOrderList);

        // 订单安置上找所有会员列表
        List<CuMemberSettleExt> memberSettleExtList = new ArrayList<>();
        for (List<CuMemberSettleExt> cuMemberSettleExt : memberSettleMap.values()) {
            memberSettleExtList.addAll(cuMemberSettleExt);
        }
        // 订单安置上所有会员List转成map
        getMemberSettle(cuMemberSettleExtMap, memberSettleExtList);

        for (SaOrderExt saOrderExt : purchaseOrderList) {
            // 所有需要计算的父节点，只计算新增（当前订单会员向上找的所有安置人）
            List<CuMemberSettleExt> cuMemberSettleExtList = memberSettleMap.get(saOrderExt.getPkId());
            if (CollectionUtil.isEmpty(cuMemberSettleExtList)) {
                // 会员上面没有人
                continue;
            }
            // 这三个参数是单独配置4-N的参数
            BigDecimal addTouch = BigDecimal.ZERO;
            BigDecimal expandRatio = BigDecimal.ZERO;
            int expandNumber = 0;
            for (int i = cuMemberSettleExtList.size() - 1; i >= 0; i--) {
                CuMemberSettleExt cuMemberSettleExt = cuMemberSettleExtList.get(i);
                if (cuBonusExpandExtMap.containsKey(cuMemberSettleExt.getPkMember())) {
                    addTouch = cuBonusExpandExtMap.get(cuMemberSettleExt.getPkMember()).getAddTouch();
                    expandRatio = cuBonusExpandExtMap.get(cuMemberSettleExt.getPkMember()).getExpandRatio();
                    expandNumber = cuBonusExpandExtMap.get(cuMemberSettleExt.getPkMember()).getExpandNumber();
                    break;
                }
            }
            // 计算量奖（拓展收益）
            List<CuMemberBonusExpand> expandList = calculateRepurchaseExpandBonusOne(riskControlMap, settleTableName, cuMemberSettleExtMap, bonusConfigDTO, systemConfigMap, period,
                    weekMemberBonusMap, cuMemberBonusMap, saOrderExt, cuMemberSettleExtList, addTouch, expandRatio, expandNumber);
            if (expandList.size() > 0) {
                cuMemberBonusExpandList.addAll(expandList);
            }
        }
        // 根据订单往上穿业绩，只计算新增
        return cuMemberBonusExpandList;
    }

//    /**
//     * 秒接复购量奖
//     *
//     * @return: List<CuMemberBonusExpand>
//     */
//    protected List<CuMemberBonusExpand> calculateRepurchaseExpandSecondBonus(Map<Long, CuMemberRiskControl> riskControlMap, String settleTableName, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, BonusConfigDTO bonusConfigDTO,
//                                                                             Map<String, String> systemConfigMap, Integer period, Map<Long, CuMemberBonus> weekMemberBonusMap,
//                                                                             Map<Long, CuMemberBonus> cuMemberBonusMap, SaOrderExt saOrderExt,
//                                                                             List<CuMemberSettleExt> cuMemberSettleExtList, String settleDateStr, BigDecimal addTouch, BigDecimal expandRatio, Integer expandNumber) {
//        // 复购订单，计算复购级差，复购拓展
//        return calculateRepurchaseExpandBonusOne(riskControlMap, settleTableName, cuMemberSettleExtMap, bonusConfigDTO, systemConfigMap, period, weekMemberBonusMap, cuMemberBonusMap,
//                saOrderExt, cuMemberSettleExtList, addTouch, expandRatio, expandNumber);
//    }
//
//    /**
//     * 秒接复购量奖
//     *
//     * @return: List<CuMemberBonusExpand>
//     */
//    protected List<CuMemberBonusPush> calculateRepurchasePushSecondBonus(String settleTableName, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, BonusConfigDTO bonusConfigDTO, Integer period,
//                                                                         Map<Long, CuMemberBonus> cuMemberBonusMap, SaOrderExt saOrderExt,
//                                                                         List<CuMemberSettleExt> cuMemberSettleExtList, String settleDateStr) {
//        // 根据订单获取轮次，要回写
//        return calculateRepurchasePushBonusOne(cuMemberSettleExtMap, bonusConfigDTO, null, period, cuMemberBonusMap, saOrderExt);
//    }

    /**
     * 计算复购量奖（拓展收益）
     *
     * @return
     */
    private List<CuMemberBonusExpand> calculateRepurchaseExpandBonusOne(Map<Long, CuMemberRiskControl> riskControlMap, String settleName, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, BonusConfigDTO bonusConfigDTO,
                                                                        Map<String, String> systemConfigMap, Integer period, Map<Long, CuMemberBonus> weekMemberBonusMap, Map<Long, CuMemberBonus> cuMemberBonusMap,
                                                                        SaOrderExt saOrderExt, List<CuMemberSettleExt> cuMemberSettleExtList,
                                                                        BigDecimal addTouch, BigDecimal expandRatio, Integer expandNumber) {
        List<CuMemberBonusExpand> cuMemberBonusExpandList = new ArrayList<>();
        CuMemberSettleExt settleExt = cuMemberSettleExtMap.get(saOrderExt.getPkMember());
        if (settleExt == null) {
            return cuMemberBonusExpandList;
        }
        settleExt.setRepurchaseAmount(ComputeUtil.computeAdd(settleExt.getRepurchaseAmount(), saOrderExt.getOrderAmount()));
        settleExt.setRepurchasePv(ComputeUtil.computeAdd(settleExt.getRepurchasePv(), saOrderExt.getOrderAchieve()));
        settleExt.setRepurchaseNewAmount(ComputeUtil.computeAdd(settleExt.getRepurchaseNewAmount(), saOrderExt.getOrderAmount()));
        settleExt.setRepurchaseNewPv(ComputeUtil.computeAdd(settleExt.getRepurchaseNewPv(), saOrderExt.getOrderAchieve()));

        // 先计算新增，根据新增计算碰次
        // 先进行初始化所有的安置人，存储需要修改的值,cuMemberSettleExtMap最终修改的
//        getMemberSettle(cuMemberSettleExtMap, cuMemberSettleExtList);

        Map<Integer, BonusExpandDTO> bdBonusExpandMap = bonusConfigDTO.getBonusExpandMap();
        // 先准备值，准备好值后，开始计算，计算碰次
        int touchNum = calculateTouchNum(riskControlMap, cuMemberSettleExtMap, saOrderExt, cuMemberSettleExtList, bonusConfigDTO);
        // 有碰次，计算拓展奖
        if (touchNum > 0) {
            // 判断是否>3 是否需要启动4-N，4-N的参数按照伞上各安置人结算国家进行获取
            // 先计算前3碰
            int startTouch = touchNum;
            // 后面碰次
            int endTouch = 0;
            // 拓展次数（一般配置的为3，前3碰保持原来的处理逻辑，3次以后判断是否启动4-N，进行分摊收益）
            BonusExpandDTO bdBonusExpand = bdBonusExpandMap.get(saOrderExt.getPkCountry());
            int realExpandNumber = expandNumber > 0 ? expandNumber : bdBonusExpand.getExpandNumber();
            if (touchNum > realExpandNumber) {
                startTouch = realExpandNumber;
                endTouch = touchNum - startTouch;
            }

            // 正常的拓展奖计算
            // 计算拓展奖
            for (int i = 1; i <= startTouch; i++) {
                for (CuMemberSettleExt sourceMemberSettleExt : cuMemberSettleExtList) {
                    CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(sourceMemberSettleExt.getPkPlaceParent());
                    if (null == targetMemberSettleExt
                            || ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                            || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                            || SysConstants.NOT_BONUS_GRADE.contains(targetMemberSettleExt.getGradeValue())) {
                        // 会员不满足计算奖金条件，跳过
                        continue;
                    }
                    // 验证是否有当前奖金项
                    if (validatePkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.CONSUMPTION_EXPANSION_INCOME.getValue())) {
                        continue;
                    }
                    // 判断左右区是否有值，找到有值的就是有碰次，碰完左区或右区肯定有变为0的
                    if ((ComputeUtil.compareValue(targetMemberSettleExt.getABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getBBalance()))
                            || (ComputeUtil.compareValue(targetMemberSettleExt.getRepABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getRepBBalance()))) {
                        // 根据会员等级获取对应的配置
                        BdGrade bdGrade = getGradeExpand(bonusConfigDTO, targetMemberSettleExt);
                        BigDecimal countryExpandRatio = bdGrade.getRepurchaseRatio();
                        // 计算量碰
                        calculateRepurchaseExpandBonusByAchieve(period, weekMemberBonusMap, cuMemberBonusMap, bonusConfigDTO, systemConfigMap, cuMemberBonusExpandList,
                                saOrderExt, touchNum, i, sourceMemberSettleExt, targetMemberSettleExt, bdGrade, countryExpandRatio);
                        break;
                    }
                }
            }
            // 4-N计算
            if (endTouch > 0) {
                // 获得每一碰的比例, 找到剩下的碰次的国家
                for (int i = 1; i <= endTouch; i++) {
                    for (CuMemberSettleExt sourceMemberSettleExt : cuMemberSettleExtList) {
                        CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(sourceMemberSettleExt.getPkPlaceParent());
                        if (null == targetMemberSettleExt
                                || ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                                || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                                || SysConstants.NOT_BONUS_GRADE.contains(targetMemberSettleExt.getGradeValue())) {
                            // 会员不满足计算奖金条件，跳过
                            continue;
                        }
                        // 验证是否有当前奖金项
                        if (validatePkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.CONSUMPTION_EXPANSION_INCOME.getValue())) {
                            continue;
                        }
                        // 判断左右区是否有值，找到有值的就是有碰次，碰完左区或右区肯定有变为0的
                        if ((ComputeUtil.compareValue(targetMemberSettleExt.getABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getBBalance()))
                                || (ComputeUtil.compareValue(targetMemberSettleExt.getRepABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getRepBBalance()))) {
                            // 根据会员等级获取对应的配置
                            BdGrade bdGrade = getGradeExpand(bonusConfigDTO, targetMemberSettleExt);
                            // 获取国家4-n的配置
                            BigDecimal countryExpandRatio = getCountryRepurchaseExpand(bonusConfigDTO, targetMemberSettleExt, endTouch, bdGrade, addTouch, expandRatio);
                            // 计算量碰
                            calculateRepurchaseExpandBonusByAchieve(period, weekMemberBonusMap, cuMemberBonusMap, bonusConfigDTO, systemConfigMap, cuMemberBonusExpandList,
                                    saOrderExt, touchNum, i + startTouch, sourceMemberSettleExt, targetMemberSettleExt, bdGrade, countryExpandRatio);
                            break;
                        }
                    }
                }
            }
        }
        return cuMemberBonusExpandList;
    }

    private int calculateTouchNum(Map<Long, CuMemberRiskControl> riskControlMap, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap,
                                  SaOrderExt saOrderExt, List<CuMemberSettleExt> cuMemberSettleExtList, BonusConfigDTO bonusConfigDTO) {
        int touchNum = 0;
        for (CuMemberSettleExt cuMemberSettleExt : cuMemberSettleExtList) {
            // 数据已经准备好了，肯定有值，map中是实际的值，先计算新增，然后根据新增结算计算碰次，list是为了存储碰次的顺序
            CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(cuMemberSettleExt.getPkPlaceParent());
            if (null == targetMemberSettleExt
                    || ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                    || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                    || SysConstants.NOT_BONUS_GRADE.contains(targetMemberSettleExt.getGradeValue())) {
                // 会员不满足计算奖金条件，跳过
                continue;
            }
            // 验证是否计算奖金
            BdGrade bdGrade = getGradeExpand(bonusConfigDTO, targetMemberSettleExt);
            if (bdGrade.getRepurchaseCalculate() != null && EYesNo.NO.getIntValue() == bdGrade.getRepurchaseCalculate()) {
                continue;
            }
            if (EPlaceDept.LEFT_DEPT.getValue() == cuMemberSettleExt.getPlaceDept()) {
                // 左区
                // K值设置
                if (riskControlMap.containsKey(targetMemberSettleExt.getPkMember())) {
                    CuMemberRiskControl cuMemberRiskControl = riskControlMap.get(targetMemberSettleExt.getPkMember());
                    targetMemberSettleExt.setANewAmount(ComputeUtil.computeAdd(targetMemberSettleExt.getANewAmount(), ComputeUtil.computeBonusMultiply(convertLocalCurrency(saOrderExt, bonusConfigDTO), cuMemberRiskControl.getAchieveRatio())));
                    targetMemberSettleExt.setANewPv(ComputeUtil.computeAdd(targetMemberSettleExt.getANewPv(), ComputeUtil.computeBonusMultiply(saOrderExt.getUploadAchieve(), cuMemberRiskControl.getAchieveRatio())));
                    targetMemberSettleExt.setABalance(ComputeUtil.computeAdd(targetMemberSettleExt.getABalance(), ComputeUtil.computeBonusMultiply(saOrderExt.getUploadAchieve(), cuMemberRiskControl.getAchieveRatio())));
                } else {
                    targetMemberSettleExt.setANewAmount(ComputeUtil.computeAdd(targetMemberSettleExt.getANewAmount(), convertLocalCurrency(saOrderExt, bonusConfigDTO)));
                    targetMemberSettleExt.setANewPv(ComputeUtil.computeAdd(targetMemberSettleExt.getANewPv(), saOrderExt.getUploadAchieve()));
                    targetMemberSettleExt.setABalance(ComputeUtil.computeAdd(targetMemberSettleExt.getABalance(), saOrderExt.getUploadAchieve()));
                }
                targetMemberSettleExt.setRABalance(ComputeUtil.computeAdd(targetMemberSettleExt.getRABalance(), saOrderExt.getUploadAchieve()));
            } else {
                // 右区
                if (riskControlMap.containsKey(targetMemberSettleExt.getPkMember())) {
                    CuMemberRiskControl cuMemberRiskControl = riskControlMap.get(targetMemberSettleExt.getPkMember());
                    targetMemberSettleExt.setBNewAmount(ComputeUtil.computeAdd(targetMemberSettleExt.getBNewAmount(), ComputeUtil.computeBonusMultiply(convertLocalCurrency(saOrderExt, bonusConfigDTO), cuMemberRiskControl.getAchieveRatio())));
                    targetMemberSettleExt.setBNewPv(ComputeUtil.computeAdd(targetMemberSettleExt.getBNewPv(), ComputeUtil.computeBonusMultiply(saOrderExt.getUploadAchieve(), cuMemberRiskControl.getAchieveRatio())));
                    targetMemberSettleExt.setBBalance(ComputeUtil.computeAdd(targetMemberSettleExt.getBBalance(), ComputeUtil.computeBonusMultiply(saOrderExt.getUploadAchieve(), cuMemberRiskControl.getAchieveRatio())));
                } else {
                    targetMemberSettleExt.setBNewAmount(ComputeUtil.computeAdd(targetMemberSettleExt.getBNewAmount(), convertLocalCurrency(saOrderExt, bonusConfigDTO)));
                    targetMemberSettleExt.setBNewPv(ComputeUtil.computeAdd(targetMemberSettleExt.getBNewPv(), saOrderExt.getUploadAchieve()));
                    targetMemberSettleExt.setBBalance(ComputeUtil.computeAdd(targetMemberSettleExt.getBBalance(), saOrderExt.getUploadAchieve()));
                }
                targetMemberSettleExt.setRBBalance(ComputeUtil.computeAdd(targetMemberSettleExt.getRBBalance(), saOrderExt.getUploadAchieve()));
            }

            // 判断左右区是否有值，左右区有值有碰次
            if (ComputeUtil.compareValue(targetMemberSettleExt.getABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getBBalance())) {
                // 国内量奖修改为考核不通过的不占用4-N，不算奖金
                // 验证是否验证考核
                touchNum++;
            }
            // 判断左右区是否有值，左右区有值有碰次
            if (ComputeUtil.compareValue(targetMemberSettleExt.getRABalance()) && ComputeUtil.compareValue(targetMemberSettleExt.getRBBalance())) {
                BigDecimal minAchieve = ComputeUtil.obtainMinAchieve(targetMemberSettleExt.getRABalance(), targetMemberSettleExt.getRBBalance());
                targetMemberSettleExt.setRABalance(ComputeUtil.computeSubtractAbs(targetMemberSettleExt.getRABalance(), minAchieve));
                targetMemberSettleExt.setRBBalance(ComputeUtil.computeSubtractAbs(targetMemberSettleExt.getRBBalance(), minAchieve));
            }
        }
        return touchNum;
    }

    private Map<Long, CuMemberAssess> getCuMemberAssessMap(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleDateStr, List<CuMemberSettleExt> memberSettleExtList) {
        List<CuMemberSettleExt> queryMemberList = getQueryMemberSettleExtList(cuMemberSettleExtMap, memberSettleExtList);
        return getLongCuMemberAssessMap(settleDateStr, queryMemberList);
    }

    /**
     * 计算复购级差
     *
     * @param period            期间
     * @param bonusConfigDTO    参数
     * @param purchaseOrderList 复购订单
     * @param cuMemberBonusMap  所有计算出来的奖金汇总
     */
    List<CuMemberBonusRange> calculateRepurchaseRangeBonus(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, String settleDate, Map<String, RangeDTO> rangeDtoMap, Map<String, BdAwards> awardsMap,
                                                           BonusConfigDTO bonusConfigDTO, List<SaOrderExt> purchaseOrderList, Integer period,
                                                           Map<Long, CuMemberBonus> cuMemberBonusMap, Map<Long, CuAwardsControl> cuAwardsControlMap) {
        List<CuMemberBonusRange> cuMemberBonusRangeList = new ArrayList<>();
        // 处理血缘上网体信息
        getMemberParentBySaOrder(cuMemberSettleExtMap, settleTableName, purchaseOrderList);
        // 考核相关
//        List<CuMemberSettleExt> cuMemberSettleExtList = getMemberParentBySaOrder(cuMemberSettleExtMap, settleTableName, purchaseOrderList);
//        Map<Long, CuMemberAssess> cuMemberAssessMap = getCuMemberAssessMap(cuMemberSettleExtMap, settleDate, cuMemberSettleExtList);
//        if (chinaRangeOrderList.size() > 0) {
//            Map<String, List<SaOrderRangeDto>> saOrderRangeDtoMap = saOrderServiceApi.queryOrderRangeVO(chinaRangeOrderList).getData();
//            Map<String, RangeDTO> rangePkDtoMap = new HashMap<>(ComputeUtil.mapInitCapacity(rangeDtoMap.size()));
//            rangeDtoMap.forEach((key, rangeDto) ->
//                    rangePkDtoMap.put(rangeDto.getPkCountry().toString() + rangeDto.getPkRange(), rangeDto));
//            chinaRangeOrderList.forEach(saOrderExt -> {
//                List<SaOrderRangeDto> orderRangeVOList = saOrderRangeDtoMap.get(saOrderExt.getOrderCode());
//                if (orderRangeVOList == null || orderRangeVOList.size() == 0) {
//                    return;
//                }
//                if (!validateSecondOrderExistBonus(saOrderExt, EBonusItems.REPURCHASE_RANGE_INCOME.getValue())) {
//                    return;
//                }
//                Map<Long, List<SaOrderRangeDto>> orderRangeDtoMap = getRangeDtoMap(orderRangeVOList);
//                for(Long pkItem :orderRangeDtoMap.keySet()){
//                    List<SaOrderRangeDto> saOrderRangeDtoList = orderRangeDtoMap.get(pkItem);
//                    // 一定要发完，从推荐人开始发
//                    executeChinaOrderRange(cuMemberSettleExtMap, rangeDtoMap, awardsMap, bonusConfigDTO, period, cuMemberBonusMap,
//                            cuAwardsControlMap, cuMemberBonusRangeList, cuMemberAssessMap, rangePkDtoMap, saOrderExt, saOrderRangeDtoList);
//                }
//            });
//            List<SaOrderExt> saOrderExtList = new ArrayList<>();
//            for (SaOrderExt saOrderExt : chinaRangeOrderList) {
//                if(ComputeUtil.compareValue(saOrderExt.getOrderAmount(), BigDecimal.valueOf(170000))){
//                    for (SaOrderItemsExt saOrderItemsExt : saOrderExt.getOrderItemsExtList()) {
//                        if(Objects.equals(13825, saOrderItemsExt.getPkWares())){
//                            saOrderExt.setOrderAchieve(saOrderItemsExt.getAchievement());
//                            saOrderExtList.add(saOrderExt);
//                        }
//                    }
//                }
//            }
//            if(saOrderExtList.size() >0) {
//                for (SaOrderExt saOrderExt : saOrderExtList) {
//                    CuMemberSettleExt sourceMemberTree = cuMemberSettleExtMap.get(saOrderExt.getPkMember());
//                    while (true) {
//                        if (sourceMemberTree == null) {
//                            break;
//                        }
//                        CuMemberSettleExt parentMemberTree = cuMemberSettleExtMap.get(sourceMemberTree.getPkParent());
//                        parentMemberTree = getRangeCuMemberTree(cuMemberSettleExtMap, rangeDtoMap, awardsMap, bonusConfigDTO, sourceMemberTree, parentMemberTree, cuAwardsControlMap, cuMemberAssessMap);
//                        if (parentMemberTree == null) {
//                            break;
//                        }
//                        RangeDTO parentRangeDto = getRangeDto(rangeDtoMap, awardsMap, parentMemberTree, cuAwardsControlMap);
//                        RangeDTO sourceRangeDto = getRangeDto(rangeDtoMap, awardsMap, sourceMemberTree, cuAwardsControlMap);
//                        BigDecimal achieveRatio = ComputeUtil.computeSubtract(parentRangeDto.getAchieveRatio(), sourceRangeDto.getAchieveRatio());
//                        // 发放奖金
//                        CuMemberBonus cuMemberBonus = getCuMemberBonus(period, cuMemberBonusMap, saOrderExt, parentMemberTree);
//                        CuMemberBonusRange cuMemberBonusRange = getCuMemberBonusRange(bonusConfigDTO, saOrderExt, parentMemberTree, cuMemberBonus);
//                        cuMemberBonusRange.setCalAchieve(saOrderExt.getOrderAchieve());
////                        BigDecimal repurchaseRangeBonus = ComputeUtil.computeMultiply(ComputeUtil.computeSubtract(orderAchieve, saOrderRangeDto.getRangeAchieve()), saOrderRangeDto.getQuantity());
//                        if (ComputeUtil.compareValue(BigDecimal.ZERO, achieveRatio)) {
//                            sourceMemberTree = cuMemberSettleExtMap.get(parentMemberTree.getPkMember());
//                            continue;
//                        }
//                        cuMemberBonusRange.setCalValue(BigDecimal.ZERO);
//                        BigDecimal repurchaseRangeBonus = ComputeUtil.computeBonusMultiply(saOrderExt.getOrderAchieve(), achieveRatio);
//                        cuMemberBonusRange.setPretaxIncome(repurchaseRangeBonus);
//                        cuMemberBonusRange.setPkRange(parentRangeDto.getPkRange());
//                        cuMemberBonusRange.setPkBeforeRange(sourceRangeDto.getPkRange());
//                        cuMemberBonusRange.setPkOrderItems(0L);
//                        rangeRemark(saOrderExt, cuMemberBonusRange, sourceMemberTree, parentMemberTree, parentRangeDto, sourceRangeDto);
//                        packageRepurchaseRange(bonusConfigDTO, cuMemberBonusRangeList, saOrderExt, cuMemberBonus, cuMemberBonusRange, repurchaseRangeBonus);
//                        if (ERangeType.AWARDS.getValue() == parentRangeDto.getRangeType() && EAwards.GLOBAL_CHAIRMAN.getValue() == parentRangeDto.getRangeValue()) {
//                            break;
//                        }
//                        sourceMemberTree = cuMemberSettleExtMap.get(parentMemberTree.getPkMember());
//                    }
//                }
//            }
//        }
        return cuMemberBonusRangeList;
    }

    /**
     * 封装复购级差
     *
     * @param bonusConfigDTO
     * @param cuMemberBonusRangeList
     * @param saOrderExt
     * @param cuMemberBonus
     * @param cuMemberBonusRange
     * @param repurchaseRangeBonus
     */
    private void packageRepurchaseRange(BonusConfigDTO bonusConfigDTO, List<CuMemberBonusRange> cuMemberBonusRangeList, SaOrderExt saOrderExt, CuMemberBonus cuMemberBonus, CuMemberBonusRange cuMemberBonusRange, BigDecimal repurchaseRangeBonus) {
        // 奖金扣项
        BdBonusDeduct bdBonusDeduct = setBonusDetailDeduct(bonusConfigDTO, cuMemberBonusRange, saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
        if (EBonusIncomeStatus.NORMAL.getValue() == cuMemberBonusRange.getIncomeStatus()) {
            // 收益状态正常，扣除
            cuMemberBonus.setRepurRangeIncome(ComputeUtil.computeAdd(cuMemberBonus.getRepurRangeIncome(), repurchaseRangeBonus));
            setPurchaseTotal(bdBonusDeduct, cuMemberBonus, cuMemberBonusRange);
        }
        cuMemberBonusRangeList.add(cuMemberBonusRange);
    }

    /**
     * 计算复购量碰
     *
     * @param period                  期间
     * @param cuMemberBonusMap        奖金汇总
     * @param cuMemberBonusExpandList 拓展奖奖金明细
     * @param saOrderExt              订单
     * @param touchNum                碰次
     * @param i                       当前碰次
     * @param sourceMemberSettleExt   提供奖金的人
     * @param targetMemberSettleExt   获得奖金的人
     * @param bdGrade                 等级对应的参数
     * @param countryExpandRatio      4-n时计算国家对应的参数
     */
    private void calculateRepurchaseExpandBonusByAchieve(Integer period, Map<Long, CuMemberBonus> weekMemberBonusMap, Map<Long, CuMemberBonus> cuMemberBonusMap,
                                                         BonusConfigDTO bonusConfigDTO, Map<String, String> systemConfigMap, List<CuMemberBonusExpand> cuMemberBonusExpandList,
                                                         SaOrderExt saOrderExt, int touchNum, int i, CuMemberSettleExt sourceMemberSettleExt, CuMemberSettleExt targetMemberSettleExt,
                                                         BdGrade bdGrade, BigDecimal countryExpandRatio) {
        // 获取拓展收益奖项ID
        Integer pkBonusItems = getPkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.CONSUMPTION_EXPANSION_INCOME.getValue());

        // 验证封顶方式 1=日 2=周，若是周的话需要获取 周奖金（首购已经去掉周封顶逻辑，此处周封顶默认0，后续代码可以不需要修改）
        BigDecimal weekRepExpandIncome = BigDecimal.ZERO;
//        if (systemConfigMap.containsKey(targetMemberSettleExt.getPkSettleCountry() + ESystemConfig.EXPAND_CAP_METHOD.getKey())) {
//            String expandCapMethod = systemConfigMap.get(targetMemberSettleExt.getPkSettleCountry() + ESystemConfig.EXPAND_CAP_METHOD.getKey());
//            if (Objects.equals(expandCapMethod, EExpandCapMethod.WEEK_SETTLE.toString()) &&
//                    weekMemberBonusMap.containsKey(targetMemberSettleExt.getPkMember())) {
//                weekRepExpandIncome = weekMemberBonusMap.get(targetMemberSettleExt.getPkMember()).getRepurExpandIncome();
//            }
//        }

        // 国内使用首购比例封顶
        BigDecimal gradeExpandRatio = bdGrade.getRepurchaseRatio();

        if (targetMemberSettleExt.getPkSettleCountry().equals(CountryConstants.CHINA_COUNTRY)) {
            // 中国复购使用首购封顶
            gradeExpandRatio = bdGrade.getExpandRatio();
        }

        // 获取等级封顶值
        CuMemberBonus cuMemberBonus = getCuMemberBonus(period, cuMemberBonusMap, saOrderExt, targetMemberSettleExt);
        // 左右区获取最小的
        BigDecimal calAchieve;
        if (targetMemberSettleExt.getPkSettleCountry().equals(CountryConstants.CHINA_COUNTRY)) {
            calAchieve = ComputeUtil.obtainMinAchieve(targetMemberSettleExt.getABalance(), targetMemberSettleExt.getBBalance());
        } else {
            calAchieve = ComputeUtil.obtainMinAchieve(targetMemberSettleExt.getRepABalance(), targetMemberSettleExt.getRepBBalance());
        }

        CuMemberBonusExpand cuMemberBonusExpand = getCuMemberBonusExpand(saOrderExt, touchNum, i, targetMemberSettleExt, countryExpandRatio, cuMemberBonus, calAchieve, pkBonusItems, BigDecimal.ZERO, bdGrade);
        if (targetMemberSettleExt.getPkSettleCountry().equals(CountryConstants.CHINA_COUNTRY)) {
            targetMemberSettleExt.setABalance(ComputeUtil.computeSubtract(targetMemberSettleExt.getABalance(), calAchieve));
            targetMemberSettleExt.setBBalance(ComputeUtil.computeSubtract(targetMemberSettleExt.getBBalance(), calAchieve));
        } else {
            // 扣减a、b区结余
            targetMemberSettleExt.setRepABalance(ComputeUtil.computeSubtractAbs(targetMemberSettleExt.getRepABalance(), calAchieve));
            targetMemberSettleExt.setRepBBalance(ComputeUtil.computeSubtractAbs(targetMemberSettleExt.getRepBBalance(), calAchieve));
        }

        // 计算收益 先计算出会员最大的收益
        // maxIncome = 业绩 * 等级扩展比例
        BigDecimal maxIncome = ComputeUtil.computeBonusMultiply(cuMemberBonusExpand.getCalAchieve(), gradeExpandRatio);
        // actualIncome = 业绩 * 等级扩展比例
        BigDecimal actualIncome = ComputeUtil.computeBonusMultiply(cuMemberBonusExpand.getCalAchieve(), countryExpandRatio);

        // 获取等级对应的封顶值（累计复购扩展 + 当前等级对应订单的最大收益）
        BigDecimal expandIncome = ComputeUtil.computeAdd(ComputeUtil.computeAdd(cuMemberBonus.getRepurExpandIncome(), actualIncome), weekRepExpandIncome);

        if (targetMemberSettleExt.getPkSettleCountry().equals(CountryConstants.CHINA_COUNTRY)) {
            // 获取等级对应的封顶值（中国重新赋值封顶值）（累计扩展 + 累计复购扩展 + 当前等级对应订单的最大收益）
            expandIncome = ComputeUtil.computeAdd(ComputeUtil.computeAdd(cuMemberBonus.getExpandIncome(), expandIncome), weekRepExpandIncome);
            // 判断收益 是否超过封顶值，超过的话变为封顶值
            // 判断是否烧伤，判断原奖金是否>=封顶值,奖金到了就是烧伤
            // 验证会员状态 封停状态跟冻结都正常计算奖金，封停的账号发放的时候奖金发放为0，冻结的账号正常发放，不能登录
            packageCuMemberBonusExpand(cuMemberBonusExpand, cuMemberBonus, bdGrade.getExpandCapping(), maxIncome, actualIncome);

            if (ComputeUtil.compareValue(ComputeUtil.computeAdd(cuMemberBonus.getExpandIncome(), cuMemberBonus.getRepurExpandIncome()), bdGrade.getExpandCapping())) {
                // 拓展收益 累加 复购收益 >= 等级封顶值
                if (EBonusIncomeStatus.NORMAL.getValue() == cuMemberBonusExpand.getIncomeStatus()) {
                    // 状态为烧伤
                    // TODO new V3 V4 没有烧伤，改为延缓发放
                    if (EGrade.VIP.getValue() == bdGrade.getGradeValue()
                            || EGrade.S_VIP.getValue() == bdGrade.getGradeValue()) {
                        cuMemberBonusExpand.setIncomeStatus(EBonusIncomeStatus.DELAY_GRANT.getValue());
                    } else {
                        cuMemberBonusExpand.setIncomeStatus(EBonusIncomeStatus.FIRE_BURN.getValue());
                    }
                }
                expandIncome = ComputeUtil.computeSubtract(bdGrade.getExpandCapping(), ComputeUtil.computeAdd(cuMemberBonus.getExpandIncome(), cuMemberBonus.getRepurExpandIncome()));
            } else if (ComputeUtil.compareGreaterThan(expandIncome, bdGrade.getExpandCapping())) {
                BigDecimal realIncome = ComputeUtil.computeSubtract(ComputeUtil.computeSubtract(bdGrade.getExpandCapping(), weekRepExpandIncome), ComputeUtil.computeAdd(cuMemberBonus.getExpandIncome(), cuMemberBonus.getRepurExpandIncome()));
                // 存在一半烧伤一半正常的值，拆2条
                // 拓展明细表 进行修改
                packageCuMemberBonusExpand(cuMemberBonusExpand, cuMemberBonus, bdGrade.getExpandCapping(), realIncome, realIncome);

                CuMemberBonusExpand fireCuMemberBonusExpand = BeanUtil.copyProperties(cuMemberBonusExpand, CuMemberBonusExpand.class);
                BigDecimal fireIncome = ComputeUtil.computeSubtract(maxIncome, realIncome);
                if (EBonusIncomeStatus.NORMAL.getValue() == fireCuMemberBonusExpand.getIncomeStatus()) {
                    // TODO new V3 V4 没有烧伤，改为延缓发放
                    if (EGrade.VIP.getValue() == bdGrade.getGradeValue()
                            || EGrade.S_VIP.getValue() == bdGrade.getGradeValue()) {
                        fireCuMemberBonusExpand.setIncomeStatus(EBonusIncomeStatus.DELAY_GRANT.getValue());
                    } else {
                        fireCuMemberBonusExpand.setIncomeStatus(EBonusIncomeStatus.FIRE_BURN.getValue());
                    }
                }
                packageCuMemberBonusExpand(fireCuMemberBonusExpand, cuMemberBonus, bdGrade.getExpandCapping(), fireIncome, fireIncome);
                // 收益占比
                setBonusDetailDeduct(bonusConfigDTO, fireCuMemberBonusExpand, saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
                expandRemark(saOrderExt, fireCuMemberBonusExpand, sourceMemberSettleExt, targetMemberSettleExt);
                cuMemberBonusExpandList.add(fireCuMemberBonusExpand);
                // 拓展收益取封顶最大值
                expandIncome = ComputeUtil.computeSubtract(bdGrade.getExpandCapping(), weekRepExpandIncome);
            }
        }

        // 收益占比
        BdBonusDeduct bdBonusDeduct = setBonusDetailDeduct(bonusConfigDTO, cuMemberBonusExpand, saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
        repurchaseExpandRemark(saOrderExt, cuMemberBonusExpand, sourceMemberSettleExt, targetMemberSettleExt);

        if (EBonusIncomeStatus.NORMAL.getValue() == cuMemberBonusExpand.getIncomeStatus()) {
            cuMemberBonus.setRepurExpandIncome(ComputeUtil.computeSubtract(expandIncome, cuMemberBonus.getExpandIncome()));
            setPurchaseTotal(bdBonusDeduct, cuMemberBonus, cuMemberBonusExpand);
        }
        cuMemberBonusExpandList.add(cuMemberBonusExpand);
    }


    private CuMemberBonusRange getCuMemberRange(BonusConfigDTO bonusConfigDTO, SaOrderExt saOrderExt, CuMemberSettleExt cuMemberSettleExt, CuMemberBonus cuMemberBonus,
                                                EBonusItems eBonusItems) {
        CuMemberBonusRange cuMemberBonusRange = CuMemberBonusRange.builder()
                .pkOrder(saOrderExt.getPkId())
                .pkOrderItems(0L)
                .pkBonus(cuMemberBonus.getPkId())
                .pkBonusItems(getPkBonusItems(bonusConfigDTO, cuMemberSettleExt.getPkSettleCountry(), eBonusItems.getValue()))
                // 正常还是烧伤
                .incomeStatus(cuMemberSettleExt.getIncomeStatus())
                .calType(ECalType.RATIO.getValue())
                .calAchieve(saOrderExt.getOrderAchieve())
                .calValue(BigDecimal.ZERO)
                .incomeRatio(BigDecimal.ZERO)
                .incomeDialRatio(BigDecimal.ZERO)
                .orderDialRatio(BigDecimal.ZERO)
                .build();
        cuMemberBonusRange.setPkCountry(cuMemberSettleExt.getPkSettleCountry());
        cuMemberBonusRange.setPkCreator(MagicNumberConstants.PK_ADMIN);
        return cuMemberBonusRange;
    }

    /**
     * 处理复购延缓
     */
    public void handleRepExpandDelay(List<CuMemberBonusExpand> cuMemberBonusExpandList, Integer period, BonusRecordDetailVO bonusRecordDetailVO) {
        // key：会员ID，value：会员延缓发放明细
        Map<Long, CuMemberBonusDelayDetail> bonusDelayDetailMap;
        if (null == bonusRecordDetailVO.getBonusDelayDetailAddMap()) {
            bonusDelayDetailMap = new HashMap<>();
            bonusRecordDetailVO.setBonusDelayDetailAddMap(bonusDelayDetailMap);
        } else {
            bonusDelayDetailMap = bonusRecordDetailVO.getBonusDelayDetailAddMap();
        }

        cuMemberBonusExpandList.forEach(bonusExpand -> {
            if (EBonusIncomeStatus.DELAY_GRANT.getValue() == bonusExpand.getIncomeStatus()) {
                // 延缓发放的才处理
                CuMemberBonusDelayDetail bonusDelayDetail = bonusDelayDetailMap.get(bonusExpand.getPkMember());
                if (null == bonusDelayDetail) {
                    // 延缓发放不存在，创建新的计算比例等都是一样的
                    bonusDelayDetail = CuMemberBonusDelayDetail.builder()
                            .pkMember(bonusExpand.getPkMember())
                            .period(period)
                            .repCalType(bonusExpand.getCalType())
                            .repCalValue(bonusExpand.getCalValue())
                            .repCalAchieve(BigDecimal.ZERO)
                            .repPretaxIncome(BigDecimal.ZERO)
                            .firCalAchieve(BigDecimal.ZERO)
                            .firPretaxIncome(BigDecimal.ZERO)
                            .beforePretaxIncome(bonusExpand.getUnGrantIncome())
                            .type(EInfusingWaterType.ADD.getValue())
                            .pkBonus(bonusExpand.getPkMember())
                            .expandCapping(bonusExpand.getDelayExpandCapping())
                            .build();
                    bonusDelayDetail.setPkCountry(bonusExpand.getPkCountry());
                    bonusDelayDetail.setPkCreator(bonusExpand.getPkCreator());
                    bonusDelayDetailMap.put(bonusExpand.getPkMember(), bonusDelayDetail);
                }
                // 累加计算业绩、税前收益
                bonusDelayDetail.setRepCalAchieve(bonusDelayDetail.getRepCalAchieve().add(bonusExpand.getCalAchieve()));
                bonusDelayDetail.setRepPretaxIncome(bonusDelayDetail.getRepPretaxIncome().add(bonusExpand.getPretaxIncome()));
            }
        });
    }

    /**
     * 处理首购延缓
     */
    public void handleFirExpandDelay(List<CuMemberBonusExpand> cuMemberBonusExpandList, Integer period, BonusRecordDetailVO bonusRecordDetailVO) {
        // key：会员ID，value：会员延缓发放明细
        Map<Long, CuMemberBonusDelayDetail> bonusDelayDetailMap;
        if (null == bonusRecordDetailVO.getBonusDelayDetailAddMap()) {
            bonusDelayDetailMap = new HashMap<>();
            bonusRecordDetailVO.setBonusDelayDetailAddMap(bonusDelayDetailMap);
        } else {
            bonusDelayDetailMap = bonusRecordDetailVO.getBonusDelayDetailAddMap();
        }

        cuMemberBonusExpandList.forEach(bonusExpand -> {
            if (EBonusIncomeStatus.DELAY_GRANT.getValue() == bonusExpand.getIncomeStatus()) {
                // 延缓发放的才处理
                CuMemberBonusDelayDetail bonusDelayDetail = bonusDelayDetailMap.get(bonusExpand.getPkMember());
                if (null == bonusDelayDetail) {
                    // 延缓发放不存在，创建新的计算比例等都是一样的
                    bonusDelayDetail = CuMemberBonusDelayDetail.builder()
                            .pkMember(bonusExpand.getPkMember())
                            .period(period)
                            .firCalType(bonusExpand.getCalType())
                            .firCalValue(bonusExpand.getCalValue())
                            .firCalAchieve(BigDecimal.ZERO)
                            .firPretaxIncome(BigDecimal.ZERO)
                            .repCalAchieve(BigDecimal.ZERO)
                            .repPretaxIncome(BigDecimal.ZERO)
                            .beforePretaxIncome(bonusExpand.getUnGrantIncome())
                            .type(EInfusingWaterType.ADD.getValue())
                            .pkBonus(bonusExpand.getPkMember())
                            .expandCapping(bonusExpand.getDelayExpandCapping())
                            .build();
                    bonusDelayDetail.setPkCountry(bonusExpand.getPkCountry());
                    bonusDelayDetail.setPkCreator(bonusExpand.getPkCreator());
                    bonusDelayDetailMap.put(bonusExpand.getPkMember(), bonusDelayDetail);
                } else {
                    if (null == bonusDelayDetail.getFirCalType()) {
                        bonusDelayDetail.setFirCalType(bonusExpand.getCalType());
                        bonusDelayDetail.setFirCalValue(bonusExpand.getCalValue());
                    }
                }
                // 累加计算业绩、税前收益
                bonusDelayDetail.setFirCalAchieve(bonusDelayDetail.getFirCalAchieve().add(bonusExpand.getCalAchieve()));
                bonusDelayDetail.setFirPretaxIncome(bonusDelayDetail.getFirPretaxIncome().add(bonusExpand.getPretaxIncome()));
            }
        });
    }

    /**
     * 计算见点收益
     */
    List<CuMemberBonusCoach> calculateRepurchasePointBonus(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, Integer period,
                                                           BonusConfigDTO bonusConfigDTO, List<SaOrderExt> purchaseOrderList, Map<Long, CuMemberBonus> cuMemberBonusMap,
                                                           Map<Integer, BdGrade> gradeMap) {
        List<CuMemberBonusCoach> cuMemberBonusCoachList = new ArrayList<>();

        if (purchaseOrderList.size() > 0) {
            // 处理血缘上网体信息
            getMemberParentBySaOrder(cuMemberSettleExtMap, settleTableName, purchaseOrderList);

            for (SaOrderExt saOrderExt : purchaseOrderList) {
                // 来源会员
                CuMemberSettleExt sourceMemberSettleExt = cuMemberSettleExtMap.get(saOrderExt.getPkMember());
                // 处理会员复购业绩
                sourceMemberSettleExt.setRepurchaseAmount(ComputeUtil.computeAdd(sourceMemberSettleExt.getRepurchaseAmount(), saOrderExt.getOrderAmount()));
                sourceMemberSettleExt.setRepurchasePv(ComputeUtil.computeAdd(sourceMemberSettleExt.getRepurchasePv(), saOrderExt.getOrderAchieve()));
                sourceMemberSettleExt.setRepurchaseNewAmount(ComputeUtil.computeAdd(sourceMemberSettleExt.getRepurchaseNewAmount(), saOrderExt.getOrderAmount()));
                sourceMemberSettleExt.setRepurchaseNewPv(ComputeUtil.computeAdd(sourceMemberSettleExt.getRepurchaseNewPv(), saOrderExt.getOrderAchieve()));
                // 订单产生的见点收益
                List<CuMemberBonusCoach> orderBonusCoachList = new ArrayList<>();

                // 推荐人
                Long pkParent = cuMemberSettleExtMap.get(saOrderExt.getPkMember()).getPkParent();

                // 一共拿多少代（最多20代）
                int pointAlgebra = MagicNumberConstants.POINT_ALGEBRA_START;
                // 最多20代
                while (pointAlgebra <= MagicNumberConstants.POINT_ALGEBRA_END) {
                    // 当前需要拿奖金的会员
                    CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(pkParent);
                    if (null == targetMemberSettleExt) {
                        break;
                    }
                    pkParent = targetMemberSettleExt.getPkParent();

                    if (ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                            || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                            || EYesNo.NO.getIntValue() == targetMemberSettleExt.getIsMakerSpace()) {
                        // 会员状态不正常 或者 停算收益 或者 考核不通过
                        continue;
                    }
                    if (validatePkBonusItems(bonusConfigDTO, targetMemberSettleExt.getPkSettleCountry(), EBonusItems.REPURCHASE_POINT_INCOME.getValue())) {
                        // 校验当前国家是否有该奖项（见点收益）
                        continue;
                    }

                    // 前10代，默认拿10%
                    BigDecimal pointRatio = MagicNumberConstants.BONUS_POINT_10;
                    if (pointAlgebra > 10) {
                        // 后10代，拿5%
                        pointRatio = MagicNumberConstants.BONUS_POINT_20;
                    }

                    // 根据等级获取可以拿的代数
                    BdGrade targetGrade = gradeMap.get(targetMemberSettleExt.getPkGrade());
                    if (targetGrade.getAlgebra() >= pointAlgebra) {
                        // 税前收益 = 订单业绩 * 收益比例
                        BigDecimal pretaxIncome = saOrderExt.getOrderAchieve().multiply(pointRatio);

                        // 获取会员奖金数据
                        CuMemberBonus cuMemberBonus = getCuMemberBonus(period, cuMemberBonusMap, saOrderExt, targetMemberSettleExt);
                        // 会员见点收益奖金
                        CuMemberBonusCoach cuMemberBonusCoach = this.getCuMemberPointBonus(bonusConfigDTO, saOrderExt, targetMemberSettleExt, cuMemberBonus);
                        cuMemberBonusCoach.setCalAchieve(saOrderExt.getOrderAchieve());
                        cuMemberBonusCoach.setCalValue(pointRatio);
                        cuMemberBonusCoach.setPretaxIncome(pretaxIncome);
                        cuMemberBonusCoach.setCurrentGeneration(pointAlgebra);
                        repurchasePointRemark(saOrderExt, cuMemberBonusCoach, sourceMemberSettleExt, targetMemberSettleExt, pointAlgebra);
                        // 奖金扣项
                        BdBonusDeduct bdBonusDeduct = setBonusDetailDeduct(bonusConfigDTO, cuMemberBonusCoach,
                                saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
                        if (EBonusIncomeStatus.NORMAL.getValue() == cuMemberBonusCoach.getIncomeStatus()) {
                            // 累计奖金数据
                            cuMemberBonus.setGlobalPoints(cuMemberBonus.getGlobalPoints().add(cuMemberBonusCoach.getPretaxIncome()));
                            // 复购小计、总计
                            setPurchaseTotal(bdBonusDeduct, cuMemberBonus, cuMemberBonusCoach);
                        }

                        orderBonusCoachList.add(cuMemberBonusCoach);

                        pointAlgebra++;
                    }
                }
                // 补全代数信息
                handlePointRemark(orderBonusCoachList, --pointAlgebra);
                cuMemberBonusCoachList.addAll(orderBonusCoachList);
            }
        }
        return cuMemberBonusCoachList;
    }

    /**
     * 生成见点收益备注
     */
    private CuMemberBonusCoach getCuMemberPointBonus(BonusConfigDTO bonusConfigDTO, SaOrderExt saOrderExt, CuMemberSettleExt cuMemberSettleExt, CuMemberBonus cuMemberBonus) {
        CuMemberBonusCoach cuMemberBonusCoach = CuMemberBonusCoach.builder()
                .pkOrder(saOrderExt.getPkId())
                .pkBonus(cuMemberBonus.getPkId())
                .pkBonusItems(getPkBonusItems(bonusConfigDTO, cuMemberSettleExt.getPkSettleCountry(), EBonusItems.REPURCHASE_POINT_INCOME.getValue()))
                // 正常还是烧伤
                .incomeStatus(cuMemberSettleExt.getIncomeStatus())
                .calType(ECalType.RATIO.getValue())
                .calAchieve(BigDecimal.ZERO)
                .calValue(BigDecimal.ZERO)
                .incomeRatio(BigDecimal.ZERO)
                .incomeDialRatio(BigDecimal.ZERO)
                .orderDialRatio(BigDecimal.ZERO)
                .coachNoCapping(BigDecimal.ZERO)
                .coachCapping(BigDecimal.ZERO)
                .coachNormalHalf(BigDecimal.ZERO)
                .coachNormalReal(BigDecimal.ZERO)
                .build();
        cuMemberBonusCoach.setPkCountry(cuMemberSettleExt.getPkSettleCountry());
        cuMemberBonusCoach.setPkCreator(MagicNumberConstants.PK_ADMIN);
        return cuMemberBonusCoach;
    }

    /**
     * 补全见点收益备注
     */
    private void handlePointRemark(List<CuMemberBonusCoach> memberBonusCoachList, int i) {
        for (CuMemberBonusCoach cuMemberBonusCoach : memberBonusCoachList) {
            cuMemberBonusCoach.setCoachGeneration(i);
            cuMemberBonusCoach.setRemark(cuMemberBonusCoach.getRemark().replace("#", cuMemberBonusCoach.getCoachGeneration().toString()));
        }
    }

    /**
     * 计算区域收益
     */
    List<CuMemberBonusRange> calculateRepurchaseAreaBonus(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, Integer period,
                                                          BonusConfigDTO bonusConfigDTO, List<SaOrderExt> purchaseOrderList, Map<Long, CuMemberBonus> cuMemberBonusMap,
                                                          Map<String, Long> memberRegionMap) {
        List<CuMemberBonusRange> cuMemberBonusRangeList = new ArrayList<>();

        if (purchaseOrderList.size() > 0 && memberRegionMap.size() > 0) {
            // 有订单数据 并且 有选择的区域，处理区域收益
            // 获取区域会员数据
            Set<Long> memberIdSet = new HashSet<>(memberRegionMap.values());
            memberIdSet.addAll(purchaseOrderList.stream().map(SaOrderExt::getPkMember).collect(Collectors.toSet()));
            this.getMemberByIdSet(cuMemberSettleExtMap, settleTableName, memberIdSet);

            // 区域配置（省=15%，市=10%，区=5%）
            Map<Integer, BigDecimal> regionAreaConfigMap = bonusConfigDTO.getRegionAreaConfigMap();

            for (SaOrderExt saOrderExt : purchaseOrderList) {
                if (validatePkBonusItems(bonusConfigDTO, saOrderExt.getPkCountry(), EBonusItems.REPURCHASE_AREA_INCOME.getValue())) {
                    // 校验当前国家是否有该奖项（区域收益）
                    continue;
                }
                // 订单会员
                CuMemberSettleExt sourceMemberSettleExt = cuMemberSettleExtMap.get(saOrderExt.getPkMember());

                Integer recProvince = saOrderExt.getRecProvince();
                Integer recCity = saOrderExt.getRecCity();
                Integer recCounty = saOrderExt.getRecCounty();

                // 前面拿的奖金比例
                BigDecimal beforeBonusCal = BigDecimal.ZERO;
                // 区
                String countyKey = recProvince + "-" + recCity + "-" + recCounty;
                if (memberRegionMap.containsKey(countyKey)) {
                    // 奖金目标会员
                    CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(memberRegionMap.get(countyKey));
                    if (null != targetMemberSettleExt) {
                        // 处理区域收益
                        BigDecimal tmpCal = this.handleAreaBonus(saOrderExt, sourceMemberSettleExt, targetMemberSettleExt, period, bonusConfigDTO, regionAreaConfigMap,
                                cuMemberBonusMap, cuMemberBonusRangeList, EAreaType.COUNTY, beforeBonusCal);
                        if (null != tmpCal) {
                            beforeBonusCal = tmpCal;
                        }
                    }
                }
                // 市
                String cityKey = recProvince + "-" + recCity + "-0";
                if (memberRegionMap.containsKey(cityKey)) {
                    CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(memberRegionMap.get(cityKey));
                    if (null != targetMemberSettleExt) {
                        // 处理区域收益
                        BigDecimal tmpCal = this.handleAreaBonus(saOrderExt, sourceMemberSettleExt, targetMemberSettleExt, period, bonusConfigDTO, regionAreaConfigMap,
                                cuMemberBonusMap, cuMemberBonusRangeList, EAreaType.CITY, beforeBonusCal);
                        if (null != tmpCal) {
                            beforeBonusCal = beforeBonusCal.add(tmpCal);
                        }
                    }
                }
                // 省
                String provinceKey = recProvince + "-0-0";
                if (memberRegionMap.containsKey(provinceKey)) {
                    CuMemberSettleExt targetMemberSettleExt = cuMemberSettleExtMap.get(memberRegionMap.get(provinceKey));
                    if (null != targetMemberSettleExt) {
                        // 处理区域收益
                        this.handleAreaBonus(saOrderExt, sourceMemberSettleExt, targetMemberSettleExt, period, bonusConfigDTO, regionAreaConfigMap,
                                cuMemberBonusMap, cuMemberBonusRangeList, EAreaType.PROVINCE, beforeBonusCal);
                    }
                }
            }
        }
        return cuMemberBonusRangeList;
    }


    /**
     * 处理区域收益
     */
    private BigDecimal handleAreaBonus(SaOrderExt saOrderExt, CuMemberSettleExt sourceMemberSettleExt, CuMemberSettleExt targetMemberSettleExt,
                                       Integer period, BonusConfigDTO bonusConfigDTO, Map<Integer, BigDecimal> regionAreaConfigMap,
                                       Map<Long, CuMemberBonus> cuMemberBonusMap, List<CuMemberBonusRange> cuMemberBonusRangeList, EAreaType eAreaType,
                                       BigDecimal beforeBonusCal) {
        if (ECategory.NORMAL.getValue() != targetMemberSettleExt.getCategory()
                || EAccountStatus.STOP_INCOME.getValue() == targetMemberSettleExt.getAccountStatus()
                || SysConstants.NOT_BONUS_GRADE.contains(targetMemberSettleExt.getGradeValue())) {
            // 死点 停算 顾客 没有奖金，跳过
            return null;
        } else {
            // 区域比例（当前等级比例 - 前一级奖金比例）
            BigDecimal calValue = regionAreaConfigMap.get(eAreaType.getValue()).subtract(beforeBonusCal);
            // 税前收益
            BigDecimal pretaxIncome = saOrderExt.getOrderAchieve().multiply(calValue);

            // 会员奖金数据
            CuMemberBonus cuMemberBonus = getCuMemberBonus(period, cuMemberBonusMap, saOrderExt, targetMemberSettleExt);
            // 级差奖金数据（区域收益）
            CuMemberBonusRange cmMemberAreaBonusRange = this.getCuMemberRange(bonusConfigDTO, saOrderExt, targetMemberSettleExt, cuMemberBonus, EBonusItems.REPURCHASE_AREA_INCOME);
            cmMemberAreaBonusRange.setCalValue(calValue);
            cmMemberAreaBonusRange.setPretaxIncome(pretaxIncome);
            cmMemberAreaBonusRange.setPkRange(eAreaType.getValue());
            cmMemberAreaBonusRange.setPkBeforeRange(0);
            // 备注
            areaRangeRemark(saOrderExt, cmMemberAreaBonusRange, sourceMemberSettleExt, targetMemberSettleExt, eAreaType);
            // 奖金扣项
            BdBonusDeduct bdBonusDeduct = setBonusDetailDeduct(bonusConfigDTO, cmMemberAreaBonusRange, saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate(), true);
            if (EBonusIncomeStatus.NORMAL.getValue() == cmMemberAreaBonusRange.getIncomeStatus()) {
                // 收益状态正常，扣除
                cuMemberBonus.setStoreIncome(ComputeUtil.computeAdd(cuMemberBonus.getStoreIncome(), cmMemberAreaBonusRange.getPretaxIncome()));
                setPurchaseTotal(bdBonusDeduct, cuMemberBonus, cmMemberAreaBonusRange);
            }
            cuMemberBonusRangeList.add(cmMemberAreaBonusRange);

            return calValue;
        }
    }

}
