package com.hzs.member.base.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.hzs.activity.pick.IAcPickServiceApi;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.constant.SystemFieldConstants;
import com.hzs.common.core.constant.msg.MemberMsgConstants;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.exception.ServiceException;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.StringUtils;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberTrade;
import com.hzs.common.domain.member.account.CuMemberTradeBonus;
import com.hzs.common.domain.member.account.CuMemberTradeDetail;
import com.hzs.common.domain.member.achieve.CuMemberAchieve;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriod;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.base.CuMemberRegister;
import com.hzs.common.domain.member.detail.CuMemberAwards;
import com.hzs.common.domain.member.detail.CuMemberChangeLog;
import com.hzs.common.domain.member.detail.CuMemberLevel;
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.common.domain.sale.order.SaOrder;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.common.domain.system.config.BdAwards;
import com.hzs.member.account.dto.BusinessCommissionDTO;
import com.hzs.member.account.dto.CuMemberBankParam;
import com.hzs.member.account.service.*;
import com.hzs.member.achieve.service.ICuMemberAchieveService;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.member.base.service.*;
import com.hzs.member.detail.service.ICuMemberAwardsService;
import com.hzs.member.detail.service.ICuMemberChangeLogService;
import com.hzs.member.detail.service.ICuMemberLevelService;
import com.hzs.member.pub.tool.MemberToolsHandler;
import com.hzs.sale.order.ISaOrderServiceApi;
import com.hzs.system.base.ICurrencyServiceApi;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAccountServiceApi;
import com.hzs.system.config.IAreaCurrencyServiceApi;
import com.hzs.system.config.IAwardsServiceApi;
import com.hzs.system.config.dto.AreaCurrencyDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 会员服务需要保存不同的表, 用于处理服务内的事务
 */
@Slf4j
@Service
public class CuMemberBusinessServiceImpl implements ICuMemberBusinessService {

    @DubboReference
    IAreaCurrencyServiceApi areaCurrencyServiceApi;
    @DubboReference
    IAccountServiceApi accountServiceApi;
    @DubboReference
    IAwardsServiceApi awardsServiceApi;
    @DubboReference
    ICurrencyServiceApi currencyServiceApi;
    @DubboReference
    IAcPickServiceApi acPickServiceApi;
    @DubboReference
    ISaOrderServiceApi iSaOrderServiceApi;

    @Autowired
    private MemberToolsHandler memberToolsHandler;
    @Autowired
    private ICuMemberAchieveService cuMemberAchieveService;
    @Autowired
    private ICuMemberBankService cuMemberBankService;

    private RedisService redisService;

    private ICuMemberService cuMemberService;

    private ICuMemberRegisterService cuMemberRegisterService;

    private ICuMemberAccountService cuMemberAccountService;

    private ICuMemberTradeService cuMemberTradeService;

    private ICuMemberLevelService cuMemberLevelService;

    private ICuMemberAwardsService cuMemberAwardsService;

    private ICuMemberChangeLogService cuMemberChangeLogService;

    private ICuMemberTradeDetailService cuMemberTradeDetailService;

    private ICuMemberTradeBonusService cuMemberTradeBonusService;

    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;

    private ICuMemberUpgradeService cuMemberUpgradeService;

    @Autowired
    public void setCuMemberUpgradeService(ICuMemberUpgradeService cuMemberUpgradeService) {
        this.cuMemberUpgradeService = cuMemberUpgradeService;
    }

    @Autowired
    public void setCuMemberSettlePeriodService(ICuMemberSettlePeriodService cuMemberSettlePeriodService) {
        this.cuMemberSettlePeriodService = cuMemberSettlePeriodService;
    }

    @Autowired
    public void setCuMemberTradeBonusService(ICuMemberTradeBonusService cuMemberTradeBonusService) {
        this.cuMemberTradeBonusService = cuMemberTradeBonusService;
    }

    @Autowired
    public void setCuMemberTradeDetailService(ICuMemberTradeDetailService cuMemberTradeDetailService) {
        this.cuMemberTradeDetailService = cuMemberTradeDetailService;
    }

    @Autowired
    public void setCuMemberAwardsService(ICuMemberAwardsService cuMemberAwardsService) {
        this.cuMemberAwardsService = cuMemberAwardsService;
    }

    @Autowired
    public void setCuMemberLevelService(ICuMemberLevelService cuMemberLevelService) {
        this.cuMemberLevelService = cuMemberLevelService;
    }

    @Autowired
    public void setCuMemberTradeService(ICuMemberTradeService cuMemberTradeService) {
        this.cuMemberTradeService = cuMemberTradeService;
    }

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Autowired
    public void setCuMemberAccountService(ICuMemberAccountService cuMemberAccountService) {
        this.cuMemberAccountService = cuMemberAccountService;
    }

    @Autowired
    public void setCuMemberService(ICuMemberService cuMemberService) {
        this.cuMemberService = cuMemberService;
    }

    @Autowired
    public void setCuMemberRegisterService(ICuMemberRegisterService cuMemberRegisterService) {
        this.cuMemberRegisterService = cuMemberRegisterService;
    }

    @Autowired
    public void setCuMemberChangeLogService(ICuMemberChangeLogService cuMemberChangeLogService) {
        this.cuMemberChangeLogService = cuMemberChangeLogService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCuMember(CuMember cuMember) {
        redisService.lockKeyMany(CacheConstants.UPD_MEMBER + cuMember.getMemberCode());
        try {
            cuMemberService.updateById(cuMember);
        } catch (Exception e) {
            log.error("updateCuMember error: ", e);
            throw e;
        } finally {
            redisService.unlock(CacheConstants.UPD_MEMBER + cuMember.getMemberCode());
        }
    }

    /**
     * 修改会员信息，确认订单信息，流水（升级订单、复购订单）
     *
     * @param cuMember           会员信息
     * @param saOrder            订单信息
     * @param cuMemberAccountExt 会员账户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMember(CuMember cuMember, SaOrderExt saOrder, CuMemberAccountExt cuMemberAccountExt) {
        try {
            if (EOrderType.RENEWAL_ORDER.getValue() == saOrder.getOrderType()) {
                // 判断是否需要更新年包时间
                if (saOrder.getExpireDateFlag()) {
                    // 更新年包时间
                    cuMemberService.updateExpireDate(saOrder);
                }
            } else {
                // 当cuMember为空时，代表为复购订单，不更新会员表
                if (cuMember != null) {
                    // 验证等级是否发生了变化，海外存在累计升级的国家
                    CuMember member = cuMemberService.getMember(cuMember.getPkId());
                    if (!cuMember.getPkSettleGrade().equals(member.getPkSettleGrade())) {
                        saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, member.getPkSettleGrade());
                    }
                    if (!cuMember.getPkAwards().equals(member.getPkAwards())) {
                        saveAwardsUpgrade(cuMember, EUpgradeType.PURCHASE_GIFT.getValue(), saOrder, member.getPkAwards());
                    }
                    updateCuMember(cuMember);
                }
            }

            // 代表在线支付，在线支付先插入一条充值信息
            if (cuMemberAccountExt == null) {
                // 报单订单 生成一条充值记录，更新会员账户信息
                cuMemberAccountExt = insertMemberRecharge(saOrder);
                if (cuMemberAccountExt == null) {
                    return Boolean.FALSE;
                }
            }
            // 扣款信息，赠送积分
            insertMemberTrade(saOrder, cuMemberAccountExt);
            cuMemberUpgradeService.updateCuMemberUpgrade(saOrder);
            // 判断订单类型，订单类型为创客或者赋能礼包，需要写入能量仓
            if (EOrderType.PICK_ORDER.getValue() == saOrder.getOrderType()) {
                // 提货订单处理成功后，需要更新提货数量
                if (!acPickServiceApi.handlePickOrder(saOrder.getPkMember(), saOrder.getOrderCode()).isSuccess()) {
                    throw new RuntimeException("提货数量更新失败");
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 保存奖衔
     *
     * @param cuMember   会员
     * @param levelType  升级类型
     * @param saOrder    订单
     * @param pkOldLevel 原等级
     */
    private Boolean saveLevelUpgrade(CuMember cuMember, Integer levelType, SaOrder saOrder, Integer pkOldLevel) {
        // 记录升级历史
        CuMemberLevel cuMemberLevel = CuMemberLevel.builder()
                .pkMember(cuMember.getPkId())
                .upType(levelType)
                .oldLevel(pkOldLevel)
                .newLevel(cuMember.getPkSettleGrade())
                .upgradeTime(saOrder.getPayTime())
                .pkOrder(saOrder.getPkId())
                .build();
        cuMemberLevel.setPkCountry(cuMember.getPkSettleCountry());
        cuMemberLevel.setPkCreator(cuMember.getPkId());
        return cuMemberLevelService.save(cuMemberLevel);
    }

    /**
     * 保存奖衔, 升级送奖项默认免考
     *
     * @param cuMember    会员
     * @param levelType   升级类型
     * @param saOrder     订单
     * @param pkOldAwards 会员
     */
    private void saveAwardsUpgrade(CuMember cuMember, Integer levelType, SaOrder saOrder, Integer pkOldAwards) {
        // 记录奖衔升级历史
        CuMemberSettlePeriod cuMemberSettlePeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, saOrder.getPayTime()));
        CuMemberAwards cuMemberAwards = CuMemberAwards.builder()
                .period(cuMemberSettlePeriod.getPkId())
                .pkMember(cuMember.getPkId())
                .upType(levelType)
                .oldLevel(pkOldAwards)
                .newLevel(cuMember.getPkAwards())
                // 默认免考
                .purchaseStatus(EYesNo.YES.getIntValue())
                .pkOrder(saOrder.getPkId())
                .build();
        cuMemberAwards.setPkCountry(cuMember.getPkSettleCountry());
        cuMemberAwards.setPkCreator(cuMember.getPkId());
        cuMemberAwardsService.save(cuMemberAwards);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMember(CuMember cuMember, SaOrderExt saOrder, Boolean isPay, CuMemberAccountExt cuMemberAccountExt) {
        // 插入账号信息
        saveMemberAccount(cuMember);
        if (isPay) {
            updateCuMember(cuMember);
        } else {
            if (cuMemberService.getMember(cuMember.getPkId()) != null) {
                updateCuMember(cuMember);
            } else {
                cuMemberService.saveMember(cuMember);
            }
        }
        // 代表在线支付，在线支付先插入一条充值信息
        if (cuMemberAccountExt == null) {
            // 报单订单 生成一条充值记录，更新会员账户信息
            cuMemberAccountExt = insertMemberRecharge(saOrder);
            if (cuMemberAccountExt == null) {
                return Boolean.FALSE;
            }
        }
        saveMemberRecords(cuMember, saOrder);
        // 扣款信息
        insertMemberTrade(saOrder, cuMemberAccountExt);

        if (EOrderType.REGISTER_ORDER.getValue() == saOrder.getOrderType()) {
            if (null != saOrder.getPkBank() &&
                    StringUtils.isNoneEmpty(saOrder.getCardNumber(), saOrder.getSubBankName(), saOrder.getAccountName(), saOrder.getIdCard())) {
                // 注册类订单，银行信息相关全不为空，则保存默认银行卡信息
                cuMemberBankService.saveMemberBank(CuMemberBankParam.builder()
                        .pkBank(saOrder.getPkBank())
                        .cardNumber(saOrder.getCardNumber())
                        .subBankName(saOrder.getSubBankName())
                        .accountName(saOrder.getAccountName())
                        .idCard(saOrder.getIdCard())
                        .pkMember(cuMember.getPkId())
                        .pkCountry(cuMember.getPkSettleCountry())
                        .build());
            }

        }
        // 孟加拉60天有一次补差升级的权益
//        cuMemberUpgradeService.saveCuMemberUpgrade(cuMember);
        // 解锁 安置位置
        redisService.unlock(CacheConstants.POSITION + cuMember.getPkPlaceParent() + cuMember.getPlaceDept());
        return true;
    }

    @Override
    public Boolean saveShareMember(CuMember cuMember) {
        // 保存会员
        cuMemberService.saveMember(cuMember);
        // 保存账户
        saveMemberAccount(cuMember);
        // 保存会员注册、等级信息
        // 用户注册信息
        CuMemberRegister cuMemberRegister = BeanUtil.copyProperties(cuMember, CuMemberRegister.class);
        cuMemberRegister.setPkMember(cuMember.getPkId());
        cuMemberRegisterService.save(cuMemberRegister);
        // 解锁 安置位置
        redisService.unlock(CacheConstants.POSITION + cuMember.getPkPlaceParent() + cuMember.getPlaceDept());
        return null;
    }

    /**
     * 保存会员账户信息
     *
     * @param cuMember 会员
     */
    private void saveMemberAccount(CuMember cuMember) {
        // 新会员生成账户，保存账户
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder()
                .pkMember(cuMember.getPkId())
//                .account6(saOrder.getOrderAmount())
                .build();
        cuMemberAccount.setPkCreator(cuMember.getPkCreator());
        cuMemberAccount.setPkCountry(cuMember.getPkSettleCountry());
        // 获取账户配置，判断是否有积分账户
        cuMemberAccountService.save(cuMemberAccount);
        // 验证订单是否存在购买的订单
    }

    private void saveMemberRecords(CuMember cuMember, SaOrder saOrder) {
        // 记录等级
        saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, 0);
        // 记录奖衔 需要判断奖项
        BdAwards bdAwards = awardsServiceApi.getAwardsOne(cuMember.getPkAwards()).getData();
        if (bdAwards != null && !bdAwards.getAwardsValue().equals(EAwards.MEMBER.getValue())) {
            saveAwardsUpgrade(cuMember, EUpgradeType.PURCHASE_GIFT.getValue(), saOrder, 0);
        }
        // 用户注册信息
        CuMemberRegister cuMemberRegister = BeanUtil.copyProperties(cuMember, CuMemberRegister.class);
        cuMemberRegister.setPkMember(cuMember.getPkId());
        cuMemberRegisterService.save(cuMemberRegister);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMember(CuMember cuMember, SaOrder saOrder) {
        // 生成会员
        cuMemberService.saveMember(cuMember);
        // 记录等级，记录注册记录
        saveMemberRecords(cuMember, saOrder);
        // 生成账户信息
        saveMemberAccount(cuMember);

        saveMemberOnLineTrade(null, saOrder, null);
        // 解锁 安置位置
        redisService.unlock(CacheConstants.POSITION + cuMember.getPkPlaceParent() + cuMember.getPlaceDept());
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMemberOnLineTrade(CuMember cuMember, SaOrder saOrder, CuMemberAccountExt cuMemberAccountExt) {
        // 插入充值记录
        if (cuMemberAccountExt == null) {
            // 更新会员账户
            BdAccount bdAccount = accountServiceApi.queryAccountByCondition(saOrder.getPkCountry()).getData();
            if (bdAccount == null) {
                return Boolean.FALSE;
            }
            cuMemberAccountExt = insertRechargeTrade(saOrder, bdAccount);
            CuMemberAccountExt updateMemberAccount = new CuMemberAccountExt();
            updateMemberAccount.setPkMember(cuMemberAccountExt.getPkMember());
            updateMemberAccount.setPkCountry(saOrder.getPkCountry());
            BigDecimal payAccount = ReflectUtils.invokeGetter(cuMemberAccountExt, MemberFieldConstants.PAY_ACCOUNT + bdAccount.getFieldValue());
            ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue(), payAccount);
            updateCuMemberAccount(updateMemberAccount);
        }
        if (cuMember != null) {
            // 验证等级是否发生了变化，海外存在累计升级的国家
            CuMember member = cuMemberService.getMember(cuMember.getPkId());
            if (!cuMember.getPkSettleGrade().equals(member.getPkSettleGrade())) {
                saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, member.getPkSettleGrade());
            }
            updateCuMember(cuMember);
        }
//        List<CuMemberTrade> cuMemberTradeList = getCuMemberTrade(saOrder, cuMemberAccountExt, new CuMemberAccount());
//        cuMemberTradeService.saveBatch(cuMemberTradeList);
        // 扣款信息，赠送积分
        insertMemberTrade(saOrder, cuMemberAccountExt);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CuMemberAccountExt insertMemberRecharge(SaOrder saOrder) {
        // 更新会员账户
        BdAccount bdAccount = accountServiceApi.queryAccountByCondition(saOrder.getPkCountry()).getData();
        if (bdAccount == null) {
            return null;
        }
        CuMemberAccountExt cuMemberAccountExt = insertRechargeTrade(saOrder, bdAccount);
        CuMemberAccountExt updateMemberAccount = new CuMemberAccountExt();
        updateMemberAccount.setPkMember(cuMemberAccountExt.getPkMember());
        updateMemberAccount.setPkCountry(saOrder.getPkCountry());
        BigDecimal payAccount = ReflectUtils.invokeGetter(cuMemberAccountExt, MemberFieldConstants.PAY_ACCOUNT + bdAccount.getFieldValue());
        ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue(), payAccount);
        updateCuMemberAccount(updateMemberAccount);
        // 更新会员账户
        return cuMemberAccountExt;
    }

    /**
     * 插入充值记录trade
     *
     * @param saOrder   订单编号
     * @param bdAccount 账户
     */
    private CuMemberAccountExt insertRechargeTrade(SaOrder saOrder, BdAccount bdAccount) {
        // 扣款 扣款信息
        Integer pkCountry = saOrder.getPkCountry();
        Long pkMember = saOrder.getPkCreator();
        CuMember cuMember = cuMemberService.getMember(saOrder.getPkCreator());
        if (cuMember != null) {
            pkCountry = cuMember.getPkSettleCountry();
            pkMember = cuMember.getPkId();
        }
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder().pkMember(pkMember).build();
        cuMemberAccount.setPkCountry(pkCountry);
        List<CuMemberAccountExt> cuMemberAccountExtList = cuMemberAccountService.queryMemberAccountByCondition(cuMemberAccount);
        if (cuMemberAccountExtList.size() == 0) {
            throw new RuntimeException("没有找到会员账户");
        }
        CuMemberAccountExt cuMemberAccountExt = cuMemberAccountExtList.get(0);
        // 插入一条充值记录
        BigDecimal tradeMoney = ComputeUtil.computeAdd(saOrder.getOrderAmount(), saOrder.getPostage());
        BigDecimal originalMoney = ReflectUtils.invokeGetter(cuMemberAccountExt, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue());
        CuMemberTrade cuMemberTrade = packageMemberTrade(saOrder, pkCountry, bdAccount.getPkId(), originalMoney, tradeMoney, ETradeClassify.RECHARGE.getValue());
        cuMemberTrade.setRemarks("在线充值");
        cuMemberTradeService.save(cuMemberTrade);
        BigDecimal afterAccount = ComputeUtil.computeAdd(ReflectUtils.invokeGetter(cuMemberAccountExt, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue()), tradeMoney);
        ReflectUtils.invokeSetter(cuMemberAccountExt, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue(), afterAccount);
        ReflectUtils.invokeSetter(cuMemberAccountExt, MemberFieldConstants.PAY_ACCOUNT + bdAccount.getFieldValue(), tradeMoney);
        return cuMemberAccountExt;
    }

    /**
     * 插入会员的交易明细
     *
     * @param saOrder         订单
     * @param cuMemberAccount 账户
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertMemberTrade(SaOrder saOrder, CuMemberAccountExt cuMemberAccount) {
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        List<CuMemberTrade> cuMemberTradeList = getCuMemberTrade(saOrder, cuMemberAccount, updateMemberAccount);
        saveAndUpdateCuMember(cuMemberTradeList, updateMemberAccount);
    }

    private List<CuMemberTrade> getCuMemberTrade(SaOrder saOrder, CuMemberAccountExt cuMemberAccount, CuMemberAccount updateMemberAccount) {
        List<CuMemberTrade> cuMemberTradeList = new ArrayList<>();
        // 获取专区币种，从redis中获得
        List<AreaCurrencyDTO> currencyDTOList = areaCurrencyServiceApi.queryAreaCurrencyByPkCountry(cuMemberAccount.getPkCountry()).getData();
        updateMemberAccount.setPkMember(cuMemberAccount.getPkMember());
        updateMemberAccount.setPkCountry(cuMemberAccount.getPkCountry());
        Set<Integer> currencyType = new HashSet<>();
        currencyDTOList.forEach(currencyDto -> {
            // 交易值,交易值是否已经取返
            BigDecimal tradeMoney = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + currencyDto.getFieldValue());
            // 比较交易值是否大于0
            if (tradeMoney == null || currencyType.contains(currencyDto.getPkAccount())) {
                return;
            }
            if (!ComputeUtil.compareValue(tradeMoney)) {
                return;
            }
            currencyType.add(currencyDto.getPkAccount());
            if (ComputeUtil.compareValue(tradeMoney)) {
                // 处理奖金币，扣除奖金币还是现金币
                handleBonusConsume(saOrder, cuMemberAccount, updateMemberAccount, currencyDto, tradeMoney);
                tradeMoney = tradeMoney.negate();
                BigDecimal originalMoney = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue());
                cuMemberTradeList.add(packageMemberTrade(saOrder, cuMemberAccount.getPkCountry(), currencyDto.getPkAccount(), originalMoney, tradeMoney, ETradeClassify.CONSUME.getValue()));
                // 用于更新账户余额
                ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue(), tradeMoney);
            }
        });
        return cuMemberTradeList;
    }

    private void handleBonusConsume(SaOrder saOrder, CuMemberAccountExt cuMemberAccount, CuMemberAccount updateMemberAccount, AreaCurrencyDTO currencyDto, BigDecimal tradeMoney) {
        // 验证是否是奖金币，奖金币需要记录交易明细，实现先进先出
        if (EAccount.BONUS.getValue() == currencyDto.getFieldValue()) {
            BigDecimal bonusTradeMoney = tradeMoney;
            // 先扣除可提现金额
            // 会员奖金消费明细，记录订单消费的奖金记录
            List<CuMemberTradeBonus> cuMemberTradeBonusList = new ArrayList<>();
            if (ComputeUtil.compareValue(cuMemberAccount.getWithdrawAccount4())) {
                CuMemberTradeBonus cuMemberTradeBonus = getCuMemberTradeBonus(saOrder, cuMemberAccount);
                if (ComputeUtil.compareValue(bonusTradeMoney, cuMemberAccount.getWithdrawAccount4())) {
                    bonusTradeMoney = ComputeUtil.computeSubtract(bonusTradeMoney, cuMemberAccount.getWithdrawAccount4());
                    updateMemberAccount.setWithdrawAccount4(cuMemberAccount.getWithdrawAccount4().negate());
                    cuMemberTradeBonus.setCashMoney(cuMemberAccount.getWithdrawAccount4().negate());
                } else {
                    updateMemberAccount.setWithdrawAccount4(bonusTradeMoney.negate());
                    cuMemberTradeBonus.setCashMoney(bonusTradeMoney.negate());
                    bonusTradeMoney = BigDecimal.ZERO;
                }
                cuMemberTradeBonusList.add(cuMemberTradeBonus);
            }
            // 查询会员的发放明细
            List<CuMemberTradeDetail> cuMemberTradeDetailList = cuMemberTradeDetailService.queryCuMemberTradeDetail(cuMemberAccount.getPkMember());
            if (cuMemberTradeDetailList.size() > 0 && ComputeUtil.compareValue(bonusTradeMoney)) {
                // 会员发放交易明细
                List<CuMemberTradeDetail> updMemberTradeDetailList = new ArrayList<>();
                BigDecimal consumeMoney = BigDecimal.ZERO;
                for (CuMemberTradeDetail cuMemberTradeDetail : cuMemberTradeDetailList) {
                    BigDecimal bonusValue = cuMemberTradeDetail.getConsumeMoney();
                    BigDecimal subTradeMoney;
                    // 待消费金额 > 奖金金额
                    if (ComputeUtil.compareValue(bonusTradeMoney, bonusValue)) {
                        bonusTradeMoney = ComputeUtil.computeSubtract(bonusTradeMoney, bonusValue);
                        subTradeMoney = bonusValue;
                    } else {
                        subTradeMoney = bonusTradeMoney;
                        bonusTradeMoney = BigDecimal.ZERO;
                    }
                    CuMemberTradeBonus cuMemberTradeBonus = getCuMemberTradeBonus(saOrder, cuMemberAccount);
                    cuMemberTradeBonus.setPkTradeDetail(cuMemberTradeDetail.getPkId());
                    cuMemberTradeDetail.setConsumeMoney(ComputeUtil.computeSubtract(cuMemberTradeDetail.getConsumeMoney(), subTradeMoney));
                    cuMemberTradeBonus.setConsumeMoney(subTradeMoney.negate());
                    consumeMoney = ComputeUtil.computeAdd(consumeMoney, subTradeMoney);
                    cuMemberTradeDetail.setPkModified(saOrder.getPkCreator());
                    cuMemberTradeDetail.setModifiedTime(saOrder.getPayTime());
                    updMemberTradeDetailList.add(cuMemberTradeDetail);
                    cuMemberTradeBonusList.add(cuMemberTradeBonus);
                    if (!ComputeUtil.compareValue(bonusTradeMoney)) {
                        break;
                    }
                }
                // 更新cu_member_account 可提现金额，可消费金额
                if (ComputeUtil.compareValue(consumeMoney)) {
                    updateMemberAccount.setConsumeAccount4(consumeMoney.negate());
                }
                // 更新会员发放交易流水表
                cuMemberTradeDetailService.updateCuMemberTradeDetail(updMemberTradeDetailList);
            }
            if (cuMemberTradeBonusList.size() > 0) {
                // 新增会员奖金交易流水表
                cuMemberTradeBonusService.batchInsertCuMemberTradeBonus(cuMemberTradeBonusList);
            }
        }
    }

    private CuMemberTradeBonus getCuMemberTradeBonus(SaOrder saOrder, CuMemberAccountExt cuMemberAccount) {
        CuMemberTradeBonus cuMemberTradeBonus = CuMemberTradeBonus.builder()
                .pkMember(cuMemberAccount.getPkMember())
                .consumeType(EConsumeType.ORDER.getValue())
                .pkOrder(saOrder.getPkId())
                .consumeMoney(BigDecimal.ZERO)
                .cashMoney(BigDecimal.ZERO)
                .build();
        cuMemberTradeBonus.setPkCountry(cuMemberAccount.getPkCountry());
        cuMemberTradeBonus.setPkCreator(saOrder.getPkCreator());
        return cuMemberTradeBonus;
    }

    private void saveAndUpdateCuMember(List<CuMemberTrade> cuMemberTradeList, CuMemberAccount updateMemberAccount) {
        if (cuMemberTradeList.size() > 0) {
            cuMemberTradeService.saveBatch(cuMemberTradeList);
        }
        if (updateMemberAccount.getPkMember() != null) {
            updateCuMemberAccount(updateMemberAccount);
        }
    }

    /**
     * 更新会员账户
     *
     * @param updateMemberAccount 账户
     * @throws RuntimeException 抛出异常
     */
    private void updateCuMemberAccount(CuMemberAccount updateMemberAccount) {
        Long pkMember = updateMemberAccount.getPkMember();
        if (!redisService.lockKeyMany(CacheConstants.MEMBER_ACCOUNT + pkMember)) {
            throw new RuntimeException("该账户有其他付款操作，请等待！");
        }
        // 更新账户余额
        try {
            if (!cuMemberAccountService.updateMemberAccount(updateMemberAccount, pkMember)) {
                throw new RuntimeException("用户付款失败，请重试！");
            }
        } finally {
            redisService.unlock(CacheConstants.MEMBER_ACCOUNT + pkMember);
        }
    }

    /**
     * 封装会员 消费的 交易流水
     *
     * @param saOrder       订单主表
     * @param pkAccount     账s户类型
     * @param originalMoney 原金额
     * @param tradeMoney    交易金额
     * @return CuMemberTrade
     */
    private CuMemberTrade packageMemberTrade(SaOrder saOrder, Integer pkCountry, Integer pkAccount, BigDecimal originalMoney, BigDecimal tradeMoney, Integer tradeClassify) {
        CuMemberTrade cuMemberTrade = CuMemberTrade.builder().tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .tradeClassify(tradeClassify)
                .pkMember(saOrder.getPkCreator())
                .pkAccount(pkAccount)
                .pkRate(saOrder.getPkRate())
                .tradeAmount(tradeMoney)
                .tradeBalance(originalMoney.add(tradeMoney))
                .tradeBeforeBalance(originalMoney)
                .sourceCode(saOrder.getOrderCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .build();
        for (ETradeType tradeType : ETradeType.values()) {
            if (ETradeClassify.REFUND.getValue() == tradeClassify) {
                if (-saOrder.getOrderType() == tradeType.getOrderType()) {
                    cuMemberTrade.setRemarks(tradeType.getKey());
                    cuMemberTrade.setTradeType(tradeType.getValue());
                    break;
                }
            } else {
                if (saOrder.getOrderType() == tradeType.getOrderType()) {
                    cuMemberTrade.setRemarks(tradeType.getKey());
                    cuMemberTrade.setTradeType(tradeType.getValue());
                    break;
                }
            }
        }
        cuMemberTrade.setPkCountry(pkCountry);
        cuMemberTrade.setPkCreator(saOrder.getPkCreator());
        cuMemberTrade.setCreationTime(saOrder.getPayTime());
        return cuMemberTrade;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean singleRevokeMemberByRegisterOrder(Long pkApprove, SaOrderExt saOrder, BusinessCommissionDTO businessCommissionDTO) {
        deductCancelOrderCost(businessCommissionDTO);
        // 回退给创建人
        CuMemberAccount payMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        if (EOrderType.REGISTER_ORDER.getValue() == saOrder.getOrderType()) {
            // 会员账号  验证会员账户是否存在金额
            CuMember member = cuMemberService.getMember(saOrder.getPkMember());
            // 会员变为死点
            member.setCategory(ECategory.LOGGED_OUT.getValue());
            member.setCustomerType(ECustomerType.DEAD_POINT.getValue());
            member.setPkModified(saOrder.getPkModified());
            member.setModifiedTime(DateUtils.currentDateTime());
            cuMemberService.updateById(member);
            // 撤销正常订单，修改 cu_member_register 账户状态为死点
            CuMemberRegister cuMemberRegister = new CuMemberRegister();
            cuMemberRegister.setPkMember(member.getPkId());
            cuMemberRegister.setPkCountry(saOrder.getPkCountry());
            cuMemberRegister.setPkModified(saOrder.getPkCreator());
            cuMemberRegisterService.updateCuMemberRegister(cuMemberRegister);
        }
        cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCuMemberAccountByDraw(Long pkMember, Integer pkCountry, Integer accountValue, BigDecimal rewardMoney) {
        CuMemberAccount cuMemberAccountParam = CuMemberAccount.builder().pkMember(pkMember).build();
        cuMemberAccountParam.setPkCountry(pkCountry);
        List<CuMemberAccountExt> cuMemberAccountExtList = cuMemberAccountService.queryMemberAccountByCondition(cuMemberAccountParam);
        if (CollectionUtil.isEmpty(cuMemberAccountExtList)) {
            return Boolean.FALSE;
        }
        CuMemberAccountExt cuMemberAccountExt = cuMemberAccountExtList.get(0);
        packageActivityTrade(pkMember, pkCountry, accountValue, rewardMoney, cuMemberAccountExt.getAccount11(),
                ETradeType.DRAW_REWARD, ETradeClassify.INCOME.getValue());
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        updateMemberAccount.setPkMember(pkMember);
        updateMemberAccount.setAccount11(rewardMoney);
        updateCuMemberAccount(updateMemberAccount);
        return Boolean.TRUE;
    }

    private void packageActivityTrade(Long pkMember, Integer pkCountry, Integer accountValue, BigDecimal rewardMoney,
                                      BigDecimal tradeBeforeBalance, ETradeType tradeType, Integer tradeClassify) {
        BdAccount bdAccount = accountServiceApi.getBdAccountByFieldValue(pkCountry, accountValue).getData();
        CurrencyDTO currencyDTO = currencyServiceApi.getCurrency(pkCountry).getData();
        CuMemberTrade cuMemberTrade = CuMemberTrade.builder().tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .tradeClassify(tradeClassify)
                .pkMember(pkMember)
                .pkAccount(bdAccount.getPkId())
                .pkRate(currencyDTO.getPkId())
                .tradeAmount(rewardMoney)
                .tradeBalance(tradeBeforeBalance.add(rewardMoney))
                .tradeBeforeBalance(tradeBeforeBalance)
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(tradeType.getKey())
                .tradeType(tradeType.getValue())
                .build();
        cuMemberTrade.setPkCountry(pkCountry);
        cuMemberTrade.setPkCreator(pkMember);
        cuMemberTradeService.save(cuMemberTrade);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCuMemberAccountByDraw(CuMemberAccountExt cuMemberAccountExt, BigDecimal payMoney) {
        // 添加交易明细
        packageActivityTrade(cuMemberAccountExt.getPkMember(), cuMemberAccountExt.getPkCountry(), EAccount.CONSUME.getValue(),
                payMoney.negate(), cuMemberAccountExt.getAccount1(),
                ETradeType.DRAW_PAY_NUMBER, ETradeClassify.CONSUME.getValue());
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        updateMemberAccount.setPkMember(cuMemberAccountExt.getPkMember());
        updateMemberAccount.setAccount1(payMoney.negate());
        updateMemberAccount.setPkCountry(cuMemberAccountExt.getPkCountry());
        updateCuMemberAccount(updateMemberAccount);
        return Boolean.TRUE;
    }

    /**
     * 插销订单，回退给创建人金额
     *
     * @param pkApprove        审核人
     * @param saOrder          订单
     * @param payMemberAccount 支付会员账户
     */
    private void cancelOrderBackAccount(Long pkApprove, SaOrder saOrder, CuMemberAccount payMemberAccount) {
        List<CuMemberTradeBonus> newCuMemberTradeBonusList = new ArrayList<>();
        List<CuMemberTradeDetail> cuMemberTradeDetailList = new ArrayList<>();
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        List<CuMemberTrade> cuMemberTradeList = packageCancelOrderCuMemberTrades(pkApprove, saOrder, payMemberAccount, newCuMemberTradeBonusList, cuMemberTradeDetailList, updateMemberAccount);
        if (newCuMemberTradeBonusList.size() > 0) {
            cuMemberTradeBonusService.batchInsertCuMemberTradeBonus(newCuMemberTradeBonusList);
        }
        // 根据 newCuMemberTradeBonusList 更新 cu_member_trade_detail
        cuMemberTradeDetailService.updateAddCuMemberTradeDetail(cuMemberTradeDetailList);
        saveAndUpdateCuMember(cuMemberTradeList, updateMemberAccount);
    }

    /**
     * 为了批量处理, 所有订单的账户都处理好了之后统一进行回退
     *
     * @param pkApprove        审核人
     * @param saOrder          订单
     * @param payMemberAccount 支付账号
     */
    private List<CuMemberTrade> packageCancelOrderCuMemberTrades(Long pkApprove, SaOrder saOrder, CuMemberAccount payMemberAccount,
                                                                 List<CuMemberTradeBonus> newCuMemberTradeBonusList, List<CuMemberTradeDetail> cuMemberTradeDetailList,
                                                                 CuMemberAccount updateMemberAccount) {
        // 最终所属国家
        Integer pkCountry = saOrder.getPkCountry();
        // 返回的流水明细
        List<CuMemberTrade> cuMemberTradeList = new ArrayList<>();

        List<CuMemberTrade> cuMemberTrades = cuMemberTradeService.queryCuMemberTrade(saOrder.getPkCreator(), saOrder.getOrderCode());
        // 如果有订单支付流水明细
        if (CollectionUtil.isNotEmpty(cuMemberTrades)) {
            // 订单所属国家和订单支付流水国家不相同则为跨国，需要以订单支付流水中的国家为准进行退款
            if (!pkCountry.equals(cuMemberTrades.get(0).getPkCountry())) {
                pkCountry = cuMemberTrades.get(0).getPkCountry();
            }
            updateMemberAccount.setPkMember(payMemberAccount.getPkMember());
            updateMemberAccount.setPkCountry(pkCountry);

            List<AreaCurrencyDTO> currencyDTOList = areaCurrencyServiceApi.queryAreaCurrencyByPkCountry(pkCountry).getData();
            Map<Integer, AreaCurrencyDTO> areaCurrencyMap = new HashMap<>();
            currencyDTOList.forEach(areaCurrencyDTO -> areaCurrencyMap.put(areaCurrencyDTO.getPkAccount(), areaCurrencyDTO));

            // 回退账户余额，余额回退到create_by
            cuMemberTrades.forEach(cuMemberTrade -> {
                BigDecimal tradeMoney = cuMemberTrade.getTradeAmount().negate();
                AreaCurrencyDTO currencyDto = areaCurrencyMap.get(cuMemberTrade.getPkAccount());
                revokeBonusAccount(pkApprove, saOrder, payMemberAccount, newCuMemberTradeBonusList, cuMemberTradeDetailList, updateMemberAccount, cuMemberTradeList, cuMemberTrade, tradeMoney, currencyDto);
                // 用于更新账户余额
                BigDecimal oriTradeMoney = ReflectUtils.invokeGetter(payMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue());
                ReflectUtils.invokeSetter(payMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue(), ComputeUtil.computeAdd(oriTradeMoney, tradeMoney));
            });
        }
        return cuMemberTradeList;
    }

    /**
     * 撤销订单，回退奖金账户金额
     */
    private void revokeBonusAccount(Long pkApprove, SaOrder saOrder, CuMemberAccount payMemberAccount,
                                    List<CuMemberTradeBonus> newCuMemberTradeBonusList, List<CuMemberTradeDetail> cuMemberTradeDetailList,
                                    CuMemberAccount updateMemberAccount, List<CuMemberTrade> cuMemberTradeList, CuMemberTrade cuMemberTrade,
                                    BigDecimal tradeMoney, AreaCurrencyDTO currencyDto) {
        // 奖金账户单独处理
        if (EAccount.BONUS.getValue() == currencyDto.getFieldValue()) {
            updateMemberAccount.setWithdrawAccount4(BigDecimal.ZERO);
            updateMemberAccount.setConsumeAccount4(BigDecimal.ZERO);
            BigDecimal bonusTradeMoney = tradeMoney;
            List<Integer> consumeTypeList = Arrays.asList(EConsumeType.ORDER.getValue(), EConsumeType.BACK_ORDER.getValue());
            List<CuMemberTradeBonus> cuMemberTradeBonusList = cuMemberTradeBonusService.queryCuMemberTradeBonus(consumeTypeList, saOrder.getPkId());
            for (CuMemberTradeBonus cuMemberTradeBonus : cuMemberTradeBonusList) {
                if (!ComputeUtil.compareValue(bonusTradeMoney)) {
                    break;
                }
                cuMemberTradeBonus.setConsumeType(EConsumeType.BACK_ORDER.getValue());
                BigDecimal cashTradeMoney = cuMemberTradeBonus.getCashMoney().negate();
                BigDecimal consumeTradeMoney = cuMemberTradeBonus.getConsumeMoney().negate();
                if (ComputeUtil.compareValue(cashTradeMoney)) {
                    if (ComputeUtil.compareValue(bonusTradeMoney, cashTradeMoney)) {
                        updateMemberAccount.setWithdrawAccount4(ComputeUtil.computeAdd(updateMemberAccount.getWithdrawAccount4(), cashTradeMoney));
                        bonusTradeMoney = ComputeUtil.computeSubtract(bonusTradeMoney, cashTradeMoney);
                        cuMemberTradeBonus.setCashMoney(cashTradeMoney);
                    } else {
                        updateMemberAccount.setWithdrawAccount4(ComputeUtil.computeAdd(updateMemberAccount.getWithdrawAccount4(), bonusTradeMoney));
                        bonusTradeMoney = BigDecimal.ZERO;
                        cuMemberTradeBonus.setCashMoney(bonusTradeMoney);
                    }
                } else if (ComputeUtil.compareValue(consumeTradeMoney)) {
                    if (ComputeUtil.compareValue(bonusTradeMoney, consumeTradeMoney)) {
                        updateMemberAccount.setConsumeAccount4(ComputeUtil.computeAdd(updateMemberAccount.getConsumeAccount4(), consumeTradeMoney));
                        bonusTradeMoney = ComputeUtil.computeSubtract(bonusTradeMoney, consumeTradeMoney);
                        cuMemberTradeBonus.setConsumeMoney(consumeTradeMoney);
                    } else {
                        updateMemberAccount.setConsumeAccount4(ComputeUtil.computeAdd(updateMemberAccount.getConsumeAccount4(), bonusTradeMoney));
                        bonusTradeMoney = BigDecimal.ZERO;
                        cuMemberTradeBonus.setConsumeMoney(bonusTradeMoney);
                    }
                    CuMemberTradeDetail cuMemberTradeDetail = CuMemberTradeDetail.builder()
                            .pkId(cuMemberTradeBonus.getPkTradeDetail())
                            .grantMoney(BigDecimal.ZERO)
                            .consumeMoney(cuMemberTradeBonus.getConsumeMoney())
                            .build();
                    cuMemberTradeDetailList.add(cuMemberTradeDetail);
                }
                cuMemberTradeBonus.setPkCreator(pkApprove);
                cuMemberTradeBonus.setPkCountry(saOrder.getPkCountry());
                newCuMemberTradeBonusList.add(cuMemberTradeBonus);
            }
        }
        BigDecimal originalMoney = ReflectUtils.invokeGetter(payMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue());
        CuMemberTrade memberTrade = packageMemberTrade(saOrder, updateMemberAccount.getPkCountry(), cuMemberTrade.getPkAccount(), originalMoney, tradeMoney, ETradeClassify.REFUND.getValue());
        memberTrade.setCreationTime(DateUtils.currentDateTime());
        cuMemberTradeList.add(memberTrade);
        // 用于更新账户余额
        BigDecimal oriTradeMoney = ReflectUtils.invokeGetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue());
        if (oriTradeMoney == null) {
            oriTradeMoney = BigDecimal.ZERO;
        }
        ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue(), ComputeUtil.computeAdd(oriTradeMoney, tradeMoney));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean mergeRevokeMemberByRegisterOrder(Long pkApprove, List<Long> memberList, Map<Long, SaOrderExt> saOrderMap, BusinessCommissionDTO businessCommissionDTO) {
        deductCancelOrderCost(businessCommissionDTO);
        // 按照memberList 倒叙往后删除
        Date currentDateTime = DateUtils.currentDateTime();
        List<Long> centerIdList = saOrderMap.values().stream().map(SaOrder::getPkCreator).distinct().collect(Collectors.toList());
        List<CuMemberAccount> cuMemberAccountList = cuMemberAccountService.queryCuMemberAccountByPkMembers(centerIdList);
        Map<Long, CuMemberAccount> cuMemberAccountMap = new HashMap<>(ComputeUtil.mapInitCapacity(cuMemberAccountList.size()));
        cuMemberAccountList.forEach(cuMemberAccount ->
                cuMemberAccountMap.put(cuMemberAccount.getPkMember(), cuMemberAccount));
        for (int i = memberList.size() - 1; i >= 0; i--) {
            Long pkMember = memberList.get(i);
            SaOrderExt saOrder = saOrderMap.get(pkMember);
            CuMember cuMember = cuMemberService.getMemberById(pkMember);
            // 删除等级
            cuMemberLevelService.deleteCuMemberLevelRecord(saOrder.getPkId(), pkApprove, currentDateTime);
            // 回退奖衔,根据订单从 cu_member_awards查询
            cuMemberAwardsService.deleteCuMemberAwards(saOrder.getPkId(), pkApprove, currentDateTime);
            cuMemberService.deleteCuMemberByPkMember(pkMember, pkApprove, currentDateTime, cuMember.getMemberCode(), saOrder.getOrderStatus());
            cuMemberAccountService.deleteCuMemberAccountByPkMember(pkMember, pkApprove, currentDateTime);
            // 撤销正常订单，修改 cu_member_register 账户状态为死点
            CuMemberRegister cuMemberRegister = new CuMemberRegister();
            cuMemberRegister.setPkMember(pkMember);
            cuMemberRegister.setPkCountry(saOrder.getPkCountry());
            cuMemberRegister.setPkModified(saOrder.getPkCreator());
            cuMemberRegisterService.updateCuMemberRegister(cuMemberRegister);
            CuMemberAccount payMemberAccount = cuMemberAccountMap.get(saOrder.getPkCreator());
            cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        }
        return Boolean.TRUE;
    }

    private void deductCancelOrderCost(BusinessCommissionDTO businessCommissionDTO) {
        if (businessCommissionDTO != null) {
            if (!cuMemberTradeService.businessCommissionSubmit(businessCommissionDTO)) {
                throw new RuntimeException("撤销订单扣除业务手续费失败");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean normalRevokeOrder(Long pkApprove, SaOrderExt saOrder, CuMember cuMember, List<Long> pkOrderItemList, BusinessCommissionDTO businessCommissionDTO) {
        deductCancelOrderCost(businessCommissionDTO);
        Date currentDateTime = DateUtils.currentDateTime();
        if (EOrderType.UPGRADE_ORDER.getValue() == saOrder.getOrderType()) {
            cuMemberService.updateById(cuMember);
            // 回退等级
            cuMemberLevelService.deleteCuMemberLevelRecord(saOrder.getPkId(), pkApprove, currentDateTime);
            // 回退奖衔,根据订单从 cu_member_awards查询
            cuMemberAwardsService.deleteCuMemberAwards(saOrder.getPkId(), pkApprove, currentDateTime);
        }
        // 部分撤单
        if (saOrder.getBackOrderAmount() != null && ComputeUtil.compareValue(saOrder.getBackOrderAmount())) {
            cancelPartOrderBackAmount(pkApprove, saOrder);
        } else {
            CuMemberAccount payMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
            // 回退账号余额
            cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        }
        if (EOrderType.RESALE_INTEGRAL_ORDER.getValue() == saOrder.getOrderType()) {
            // 回退会员剩余复销次数，复销积分
            if (!cuMemberService.updateMemberReSaleNumber(saOrder.getPkMember(), saOrder.getResaleIncomeNumber())) {
                throw new RuntimeException("更新会员复消剩余收益次数失败，不能撤销订单！");
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public void cancelPartOrderBackAmount(Long pkApprove, SaOrderExt saOrder) {
        CuMemberAccount payMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        BigDecimal backOrderAmount = saOrder.getBackOrderAmount();
        // 考虑部分撤单
        // 部分退，回退金额按照 币种扣除的倒叙扣除  现金->消费->奖金  奖金->消费->现金
        // 查询到必须扣除的币种
        // 查询专区所属币种
        List<AreaCurrencyDTO> areaCurrencyDTOList = areaCurrencyServiceApi.queryAreaCurrencyByCondition(saOrder.getOrderType(), saOrder.getPkCountry()).getData();
        Map<Integer, BigDecimal> mustPayMoneyMap = new HashMap<>();
        for (AreaCurrencyDTO areaCurrencyDTO : areaCurrencyDTOList) {
            BigDecimal mustPayMoney = BigDecimal.ZERO;
            if (ComputeUtil.compareValue(areaCurrencyDTO.getDeductRatio())) {
                mustPayMoney = ComputeUtil.computeAdd(mustPayMoney, ComputeUtil.computeDivide(ComputeUtil.computeAdd(saOrder.getOrderAmount(), saOrder.getBackOrderAmount()).multiply(areaCurrencyDTO.getDeductRatio()), BigDecimal.valueOf(100)));
            }
            if (mustPayMoneyMap.containsKey(areaCurrencyDTO.getPkAccount())) {
                mustPayMoney = ComputeUtil.computeAdd(mustPayMoneyMap.get(areaCurrencyDTO.getPkAccount()), mustPayMoney);
            }
            if (ComputeUtil.compareValue(mustPayMoney)) {
                mustPayMoneyMap.put(areaCurrencyDTO.getPkAccount(), mustPayMoney);
            }
        }
        List<CuMemberTrade> cuMemberTrades = cuMemberTradeService.queryCuMemberTrade(saOrder.getPkCreator(), saOrder.getOrderCode());
        Map<Integer, CuMemberTrade> cuMemberTradeMap = new HashMap<>(ComputeUtil.mapInitCapacity(cuMemberTrades.size()));
        cuMemberTrades.forEach(cuMemberTrade ->
                cuMemberTradeMap.put(cuMemberTrade.getPkAccount(), cuMemberTrade));
        // 倒叙回退
        List<CuMemberTradeBonus> newCuMemberTradeBonusList = new ArrayList<>();
        List<CuMemberTradeDetail> cuMemberTradeDetailList = new ArrayList<>();
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        updateMemberAccount.setPkMember(payMemberAccount.getPkMember());
        updateMemberAccount.setPkCountry(saOrder.getPkCountry());
        List<CuMemberTrade> cuMemberTradeList = new ArrayList<>();
        for (int i = areaCurrencyDTOList.size() - 1; i >= 0; i--) {
            AreaCurrencyDTO areaCurrencyDTO = areaCurrencyDTOList.get(i);
            CuMemberTrade cuMemberTrade = cuMemberTradeMap.get(areaCurrencyDTO.getPkAccount());
            if (cuMemberTrade == null) {
                continue;
            }
            // 验证有没有必须支付的金额
            BigDecimal tradeMoney = cuMemberTrade.getTradeAmount().negate();
            if (mustPayMoneyMap.containsKey(areaCurrencyDTO.getPkAccount())) {
                BigDecimal mustPayMoney = mustPayMoneyMap.get(areaCurrencyDTO.getPkAccount());
                if (ComputeUtil.compareValue(mustPayMoney, tradeMoney)) {
                    mustPayMoney = ComputeUtil.computeSubtract(mustPayMoney, tradeMoney);
                    tradeMoney = BigDecimal.ZERO;
                } else {
                    tradeMoney = ComputeUtil.computeSubtract(tradeMoney, mustPayMoney);
                    mustPayMoney = BigDecimal.ZERO;
                }
                mustPayMoneyMap.put(areaCurrencyDTO.getPkAccount(), mustPayMoney);
            }
            if (ComputeUtil.compareValue(tradeMoney) && ComputeUtil.compareValue(backOrderAmount)) {
                if (ComputeUtil.compareValue(backOrderAmount, tradeMoney)) {
                    backOrderAmount = ComputeUtil.computeSubtract(backOrderAmount, tradeMoney);
                } else {
                    tradeMoney = backOrderAmount;
                    backOrderAmount = BigDecimal.ZERO;
                }
                revokeBonusAccount(pkApprove, saOrder, payMemberAccount, newCuMemberTradeBonusList, cuMemberTradeDetailList,
                        updateMemberAccount, cuMemberTradeList, cuMemberTrade, tradeMoney, areaCurrencyDTO);
            }
            if (!ComputeUtil.compareValue(backOrderAmount)) {
                break;
            }
        }
        if (newCuMemberTradeBonusList.size() > 0) {
            cuMemberTradeBonusService.batchInsertCuMemberTradeBonus(newCuMemberTradeBonusList);
        }
        // 根据 newCuMemberTradeBonusList 更新 cu_member_trade_detail
        cuMemberTradeDetailService.updateAddCuMemberTradeDetail(cuMemberTradeDetailList);
        saveAndUpdateCuMember(cuMemberTradeList, updateMemberAccount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderChangeProduct(SaOrder saOrder, SaOrder updateOrder, Long userId, Object obj) {
        if (null != saOrder && null != updateOrder) {
            // 撤销订单
            this.cancelOrderBackAccount(userId, saOrder, cuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator()));

            // 查询会员当前余额
            CuMemberAccount cuMemberAccount = new CuMemberAccount();
            cuMemberAccount.setPkCountry(saOrder.getPkCountry());
            cuMemberAccount.setPkMember(saOrder.getPkCreator());
            CuMemberAccountExt tmpCuMemberAccount = cuMemberAccountService.queryMemberAccountByCondition(cuMemberAccount).get(0);

            // 获取需要扣除各币种金额
            R<CuMemberAccountExt> resultR = iSaOrderServiceApi.queryOrderSpendDetails(tmpCuMemberAccount, updateOrder, null);
            if (!resultR.isSuccess()) {
                log.error("调换货物重新扣款失败: {}", resultR.getMsg());
                throw new ServiceException("调换货物重新扣款失败");
            }
            CuMemberAccountExt cuMemberAccountExt = resultR.getData();
            if (!cuMemberAccountExt.getIsPayment()) {
                if (StringUtils.isEmpty(cuMemberAccountExt.getErrorMsg())) {
                    throw new ServiceException(TransactionUtils.getContent(MemberMsgConstants.MEMBER_BALANCE_NOT_PAY));
                } else {
                    throw new ServiceException(cuMemberAccountExt.getErrorMsg());
                }
            }

            for (EAccount eAccount : EAccount.values()) {
                ReflectUtils.invokeSetter(cuMemberAccountExt, MemberFieldConstants.ACCOUNT + eAccount.getValue(), ReflectUtils.invokeGetter(tmpCuMemberAccount, MemberFieldConstants.ACCOUNT + eAccount.getValue()));
            }
            // 支付流水中使用的时间为订单的支付时间，此处重新赋值，不然支付流水中创建时间不对
            saOrder.setPayTime(new Date());
            log.error("{}", cuMemberAccountExt);

            // 订单重新扣款
            this.insertMemberTrade(saOrder, cuMemberAccountExt);
        }

        if (null != obj) {
            // 追加业务实体不为null，需要处理
            if (obj instanceof BusinessCommissionDTO) {
                // 业务办理扣款逻辑
                if (!cuMemberTradeService.businessCommissionSubmit((BusinessCommissionDTO) obj)) {
                    throw new ServiceException("业务手续费扣款失败");
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderReturnMember(List<Long> pkMemberList, Long userId) {
        // 注册类订单，需要更新用户为已注销状态
        UpdateWrapper<CuMember> memberUpdateWrapper = new UpdateWrapper<>();
        memberUpdateWrapper.in(SystemFieldConstants.PK_ID, pkMemberList);
        memberUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
        memberUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, new Date());
        memberUpdateWrapper.set("CATEGORY", ECategory.LOGGED_OUT.getValue());
        cuMemberService.update(memberUpdateWrapper);
        // 添加会员信息修改记录
        List<CuMemberChangeLog> cuMemberChangeLogList = new ArrayList<>();
        for (Long pkMember : pkMemberList) {
            CuMemberChangeLog cuMemberChangeLog = new CuMemberChangeLog();
            cuMemberChangeLog.setPkMember(pkMember);
            cuMemberChangeLog.setChangeType(EMemberChangeType.ORDER_RETURN.getValue());
            cuMemberChangeLog.setChangeFront("");
            cuMemberChangeLog.setChangeAfter(ECategory.LOGGED_OUT.getLabel());
            cuMemberChangeLogList.add(cuMemberChangeLog);
        }
        cuMemberChangeLogService.saveBatch(cuMemberChangeLogList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateMemberLevel(CuMember cuMember, Integer pkOldLevel, EUpgradeType eUpgradeType, String remark) {
        CuMemberLevel cuMemberLevel = CuMemberLevel.builder()
                .pkMember(cuMember.getPkId())
                .upType(eUpgradeType.getValue())
                .oldLevel(pkOldLevel)
                .newLevel(cuMember.getPkSettleGrade())
                .upgradeTime(new Date())
                .remark(remark)
                .build();
        cuMemberLevel.setPkCountry(cuMember.getPkSettleCountry());
        cuMemberLevel.setPkCreator(cuMember.getPkId());
        // 记录升级历史
        if (cuMemberLevelService.save(cuMemberLevel)) {
            // 更新会员信息
            updateCuMember(cuMember);
        }
        return true;
    }

    @Override
    public CuMember queryCuMemberPlaceDept(CuMember cuMember, Boolean isFirst, Boolean isFirstAchieve) {
        Long pkMember = cuMember.getPkParent();
        Integer pkCountry = cuMember.getPkSettleCountry();
        // 获取推荐人的左右区
        CuMember parentMember = cuMemberService.getMember(pkMember);
        int placeDept;
        // 查询当前的业绩
        CuMemberAchieve cuMemberAchieve = cuMemberAchieveService.queryCuMemberAchieveByPkMember(pkMember, pkCountry);
        placeDept = getPlaceDept(isFirst, isFirstAchieve, cuMemberAchieve, parentMember.getPkId());
        CuMemberExt cuMemberExt = cuMemberService.queryPlaceSponsorLastLeft(pkMember, placeDept);
        CuMember placeCuMember = new CuMember();
        if (cuMemberExt != null) {
            placeCuMember.setPkPlaceParent(cuMemberExt.getPkId());
            placeCuMember.setMemberCode(cuMemberExt.getMemberCode());
            placeCuMember.setMemberName(cuMemberExt.getMemberName());
            placeDept = EPlaceDept.LEFT_DEPT.getValue();
            if (cuMemberExt.getPkId().equals(pkMember)) {
                placeDept = EPlaceDept.RIGHT_DEPT.getValue();
            }
        } else {
            placeCuMember.setPkPlaceParent(parentMember.getPkId());
            placeCuMember.setMemberCode(parentMember.getMemberCode());
            placeCuMember.setMemberName(parentMember.getMemberName());
        }
        placeCuMember.setPlaceDept(placeDept);
        return placeCuMember;
    }

    /**
     * 获得左右区
     *
     * @param isFirst         是否收单
     * @param isFirstAchieve  受否判断首购业绩
     * @param cuMemberAchieve 业绩
     */
    private Integer getPlaceDept(Boolean isFirst, Boolean isFirstAchieve, CuMemberAchieve cuMemberAchieve, Long pkParent) {
        int placeDept = EPlaceDept.LEFT_DEPT.getValue();
        if (!isFirst) {
//            if(cuMemberAchieve != null){
//                if(isFirstAchieve) {
//                    // 分享专区，快速注册判断首购业绩，比较左右区 放入小区
//                    if (ComputeUtil.compareValue(cuMemberAchieve.getASumPv(), cuMemberAchieve.getBSumPv())) {
//                        placeDept = EPlaceDept.RIGHT_DEPT.getValue();
//                    }
//                }else{
//                    // 嗨粉判断复购业绩 放入小区
//                    if(ComputeUtil.compareValue(ComputeUtil.computeAdd(cuMemberAchieve.getRepASumPv(), cuMemberAchieve.getRepBSumPv()))) {
//                        if (ComputeUtil.compareValue(cuMemberAchieve.getRepASumPv(), cuMemberAchieve.getRepBSumPv())) {
//                            placeDept = EPlaceDept.RIGHT_DEPT.getValue();
//                        }
//                    }else {
//                        // 验证左右区人数，放入人数少的
//                        List<CuMember> personNumList = cuMemberService.queryMemberLeftRightCount(pkParent);
//                        if (personNumList != null && personNumList.size() > 1) {
//                            long leftNum = 0;
//                            long rigthNum = 0;
//                            for (CuMember member : personNumList) {
//                                if (EPlaceDept.LEFT_DEPT.getValue() == member.getPlaceDept()) {
//                                    leftNum = member.getPkId();
//                                } else {
//                                    rigthNum = member.getPkId();
//                                }
//                            }
//                            if (leftNum > rigthNum) {
//                                placeDept = EPlaceDept.RIGHT_DEPT.getValue();
//                            }
//                        }
//                    }
//                }
//            }
        }
        return placeDept;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean handleOrderPolicy(SaOrderExt saOrderExt, BigDecimal policyCurrency) {
        // 支付会员
        Long pkMember = saOrderExt.getPkCreator();
        // 所属国家
        Integer pkCountry = saOrderExt.getPkCountry();

        // 币种
        BdAccount bdAccount = accountServiceApi.getBdAccountByFieldValue(pkCountry, EAccount.POLICY.getValue()).getData();
        // 汇率
        CurrencyDTO currencyDTO = currencyServiceApi.getCurrency(pkCountry).getData();
        // 变动金额
        BigDecimal tradeAmount = policyCurrency.multiply(currencyDTO.getInExchangeRate());
        // 账户
        CuMemberAccount cuMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);

        CuMemberTrade cuMemberTrade = CuMemberTrade.builder()
                .pkMember(pkMember)
                .tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .pkAccount(bdAccount.getPkId())
                .tradeType(ETradeType.GIVE_POLICY.getValue())
                .tradeClassify(ETradeClassify.RECHARGE.getValue())
                .pkRate(currencyDTO.getPkId())
                .tradeBeforeBalance(cuMemberAccount.getAccount3())
                .tradeAmount(tradeAmount)
                .tradeBalance(cuMemberAccount.getAccount3().add(tradeAmount))
                .sourceCode(saOrderExt.getOrderCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(ETradeType.GIVE_POLICY.getKey())
                .build();
        cuMemberTrade.setPkCountry(pkCountry);
        cuMemberTrade.setPkCreator(pkMember);
        if (cuMemberTradeService.save(cuMemberTrade)) {
            CuMemberAccount updateMemberAccount = new CuMemberAccount();
            updateMemberAccount.setAccount3(tradeAmount);
            updateMemberAccount.setPkMember(pkMember);
            updateMemberAccount.setPkModified(pkMember);
            updateMemberAccount.setPkCountry(pkCountry);
            cuMemberAccountService.updateMemberAccount(updateMemberAccount, pkMember);

            return true;
        }
        return false;
    }

    @Override
    public Boolean backOrderPolicy(SaOrderExt saOrderExt, CuMemberTrade cuMemberTrade) {
        // 支付会员
        Long pkMember = saOrderExt.getPkCreator();
        // 所属国家
        Integer pkCountry = saOrderExt.getPkCountry();

        log.info("撤单活动MQ异步处理 member：{}", saOrderExt);

        // 变动金额
        BigDecimal tradeAmount = cuMemberTrade.getTradeAmount().negate();
        // 账户
        CuMemberAccount cuMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        // 变动后余额
        BigDecimal tradeBalance = cuMemberAccount.getAccount3().add(tradeAmount);
        if (tradeBalance.compareTo(BigDecimal.ZERO) < 0) {
            // 如果出现负的，则置为0
            tradeBalance = BigDecimal.ZERO;
        }

        CuMemberTrade saveCuMemberTrade = CuMemberTrade.builder()
                .pkMember(pkMember)
                .tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .pkAccount(cuMemberTrade.getPkAccount())
                .tradeType(ETradeType.BACK_GIVE_POLICY.getValue())
                .tradeClassify(ETradeClassify.REFUND.getValue())
                .pkRate(cuMemberTrade.getPkRate())
                .tradeBeforeBalance(cuMemberAccount.getAccount3())
                .tradeAmount(tradeAmount)
                .tradeBalance(tradeBalance)
                .sourceCode(saOrderExt.getOrderCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(ETradeType.BACK_GIVE_POLICY.getKey())
                .build();
        saveCuMemberTrade.setPkCountry(pkCountry);
        saveCuMemberTrade.setPkCreator(pkMember);
        if (cuMemberTradeService.save(saveCuMemberTrade)) {
            CuMemberAccount updateMemberAccount = new CuMemberAccount();
            if (cuMemberAccount.getAccount3().compareTo(cuMemberTrade.getTradeAmount()) >= 0) {
                // 如果剩余政策币大于等于回退政策币，则直接扣减赠送政策币
                updateMemberAccount.setAccount3(tradeAmount);
            } else {
                // 如果剩余政策币小于回退政策币，则直接扣减剩余政策币
                updateMemberAccount.setAccount3(cuMemberAccount.getAccount3().negate());
            }
            updateMemberAccount.setPkMember(pkMember);
            updateMemberAccount.setPkModified(pkMember);
            updateMemberAccount.setPkCountry(pkCountry);
            cuMemberAccountService.updateMemberAccount(updateMemberAccount, pkMember);

            return true;
        }
        return false;
    }

}
