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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hzs.activity.pick.IAcPickServiceApi;
import com.hzs.bonus.settle.IMemberSettleBonusApi;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.constant.msg.CommonMsgConstants;
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.exception.base.BaseException;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.CommonUtil;
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.reflect.ReflectUtils;
import com.hzs.common.core.web.domain.BaseEntity;
import com.hzs.common.domain.activity.draw.ext.AcDrawRewardNumExt;
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.CuMemberExpireHistory;
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.common.domain.third.pay.TOnlinePayment;
import com.hzs.common.util.TransactionUtils;
import com.hzs.member.account.dto.BusinessCommissionDTO;
import com.hzs.member.account.service.ICuMemberAccountService;
import com.hzs.member.account.service.ICuMemberTradeBonusService;
import com.hzs.member.account.service.ICuMemberTradeDetailService;
import com.hzs.member.account.service.ICuMemberTradeService;
import com.hzs.member.achieve.service.ICuMemberAchieveService;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.member.base.dto.MemberContinueDTO;
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 com.hzs.third.pay.ITOnlinePaymentServiceApi;
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 iAreaCurrencyServiceApi;
    @DubboReference
    IAccountServiceApi iAccountServiceApi;
    @DubboReference
    IAwardsServiceApi iAwardsServiceApi;
    @DubboReference
    ICurrencyServiceApi iCurrencyServiceApi;
    @DubboReference
    IAcPickServiceApi iAcPickServiceApi;
    @DubboReference
    ISaOrderServiceApi iSaOrderServiceApi;
    @DubboReference
    IMemberSettleBonusApi iMemberSettleBonusApi;

    @Autowired
    private MemberToolsHandler memberToolsHandler;
    @Autowired
    private ICuMemberAchieveService iCuMemberAchieveService;
    @Autowired
    private ICuMemberExpireHistoryService iCuMemberExpireHistoryService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ICuMemberService iCuMemberService;
    @Autowired
    private ICuMemberRegisterService iCuMemberRegisterService;
    @Autowired
    private ICuMemberAccountService iCuMemberAccountService;
    @Autowired
    private ICuMemberTradeService iCuMemberTradeService;
    @Autowired
    private ICuMemberLevelService iCuMemberLevelService;
    @Autowired
    private ICuMemberAwardsService iCuMemberAwardsService;
    @Autowired
    private ICuMemberChangeLogService iCuMemberChangeLogService;
    @Autowired
    private ICuMemberShareService iCuMemberShareService;
    @Autowired
    private ICuMemberTradeDetailService iCuMemberTradeDetailService;
    @Autowired
    private ICuMemberTradeBonusService iCuMemberTradeBonusService;
    @Autowired
    private ICuMemberSettlePeriodService iCuMemberSettlePeriodService;

    @DubboReference
    ITOnlinePaymentServiceApi itOnlinePaymentServiceApi;

    @Override
    public void updateCuMember(CuMember cuMember) {
        redisService.lockKeyMany(CacheConstants.UPD_MEMBER + cuMember.getMemberCode());
        try {
            iCuMemberService.updateById(cuMember);
        } 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 {
            // 当cuMember为空时，不更新会员表
            if (cuMember != null) {
                // 验证等级是否发生了变化
                CuMember member = iCuMemberService.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);

            if (EOrderType.PICK_ORDER.getValue() == saOrder.getOrderType()) {
                // 提货订单处理成功后，需要更新提货数量
                if (!iAcPickServiceApi.handlePickOrder(saOrder.getPkMember(), saOrder.getOrderCode()).isSuccess()) {
                    throw new RuntimeException("提货数量更新失败");
                }
            }
        } catch (Exception e) {
            log.error("saveMember error: {}", e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 保存奖衔
     *
     * @param cuMember   会员
     * @param levelType  升级类型
     * @param saOrder    订单
     * @param pkOldLevel 原等级
     */
    private void 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());
        iCuMemberLevelService.save(cuMemberLevel);
    }

    /**
     * @param cuMember    会员
     * @param levelType   升级类型
     * @param saOrder     订单
     * @param pkOldAwards 会员
     * @Description: 保存奖衔, 升级送奖项默认免考
     */
    private void saveAwardsUpgrade(CuMember cuMember, Integer levelType, SaOrder saOrder, Integer pkOldAwards) {
        // 记录奖衔升级历史
        CuMemberSettlePeriod cuMemberSettlePeriod = iCuMemberSettlePeriodService.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());
        iCuMemberAwardsService.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 (iCuMemberService.getMember(cuMember.getPkId()) != null) {
                updateCuMember(cuMember);
            } else {
                iCuMemberService.saveMember(cuMember);
            }
        }
        // 代表在线支付，在线支付先插入一条充值信息
        if (cuMemberAccountExt == null) {
            // 报单订单 生成一条充值记录，更新会员账户信息
            cuMemberAccountExt = insertMemberRecharge(saOrder);
            if (cuMemberAccountExt == null) {
                return Boolean.FALSE;
            }
        }
        // 会员升级记录
        saveMemberRecords(cuMember, saOrder);
        // 扣款信息
        insertMemberTrade(saOrder, cuMemberAccountExt);
        // 解锁 安置位置
        redisService.unlock(CacheConstants.POSITION + cuMember.getPkPlaceParent() + cuMember.getPlaceDept());
        // 扣除可用量
        return true;
    }

    /**
     * 保存会员账户信息
     *
     * @param cuMember 会员
     */
    private void saveMemberAccount(CuMember cuMember) {
        // 新会员生成账户，保存账户
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder()
                .pkMember(cuMember.getPkId())
                .build();
        cuMemberAccount.setPkCreator(cuMember.getPkCreator());
        cuMemberAccount.setPkCountry(cuMember.getPkSettleCountry());
        // 获取账户配置，判断是否有积分账户
        iCuMemberAccountService.save(cuMemberAccount);
    }

    private void saveMemberRecords(CuMember cuMember, SaOrder saOrder) {
        // 记录等级
        saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, 0);
        // 记录奖衔 需要判断奖项
        BdAwards bdAwards = iAwardsServiceApi.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());
        cuMemberRegister.setPkRegisterGrade(cuMember.getPkSettleGrade());
        iCuMemberRegisterService.save(cuMemberRegister);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMember(CuMember cuMember, SaOrder saOrder) {
        // 生成会员
        iCuMemberService.saveMember(cuMember);
        // 记录等级，记录注册记录
        saveMemberRecords(cuMember, saOrder);
        // 生成账户信息
        saveMemberAccount(cuMember);
        // 更新分享会员表状态
        iCuMemberShareService.updateCuMemberShare(cuMember.getPkCreator());

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean handleZeroMember(CuMember cuMember, SaOrder saOrder) {
        // 更新会员信息
        updateCuMember(cuMember);
        // 会员升级记录
        saveMemberRecords(cuMember, saOrder);

        // 代表在线支付，在线支付先插入一条充值信息
        CuMemberAccountExt cuMemberAccountExt = insertMemberRecharge(saOrder);
        // 扣款信息
        insertMemberTrade(saOrder, cuMemberAccountExt);

        // 解锁 安置位置
        redisService.unlock(CacheConstants.POSITION + cuMember.getPkPlaceParent() + cuMember.getPlaceDept());
        // 扣除可用量
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMemberOnLineTrade(CuMember cuMember, SaOrder saOrder, CuMemberAccountExt cuMemberAccountExt) {
        // 插入充值记录
        if (cuMemberAccountExt == null) {
            // 更新会员账户
            BdAccount bdAccount = iAccountServiceApi.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 = iCuMemberService.getMember(cuMember.getPkId());
            if (!cuMember.getPkSettleGrade().equals(member.getPkSettleGrade())) {
                saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, member.getPkSettleGrade());
            }
            updateCuMember(cuMember);
        }
        // 扣款信息，赠送积分
        insertMemberTrade(saOrder, cuMemberAccountExt);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CuMemberAccountExt insertMemberRecharge(SaOrder saOrder) {
        // 更新会员账户
        BdAccount bdAccount = iAccountServiceApi.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 = iCuMemberService.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 = iCuMemberAccountService.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("在线充值");
        iCuMemberTradeService.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 = iAreaCurrencyServiceApi.queryAreaCurrencyByPkCountry(cuMemberAccount.getPkCountry()).getData();
        updateMemberAccount.setPkMember(cuMemberAccount.getPkMember());
        updateMemberAccount.setPkCountry(cuMemberAccount.getPkCountry());
        Set<Integer> currencyType = new HashSet<>();
        currencyDTOList.forEach(currencyDto -> {
            if (EAccount.CASH_COUPON.getValue() == currencyDto.getFieldValue()) {
                return;
            }
            // 交易值,交易值是否已经取返
            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 = iCuMemberTradeDetailService.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());
                }
                // 更新会员发放交易流水表
                iCuMemberTradeDetailService.updateCuMemberTradeDetail(updMemberTradeDetailList);
            }
            if (cuMemberTradeBonusList.size() > 0) {
                // 新增会员奖金交易流水表
                iCuMemberTradeBonusService.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) {
            iCuMemberTradeService.saveBatch(cuMemberTradeList);
        }
        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 (!iCuMemberAccountService.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);
        if (EOrderType.REGISTER_ORDER.getValue() == saOrder.getOrderType()
                || EOrderType.SPECIAL_REGISTER_ORDER.getValue() == saOrder.getOrderType()
                || (EOrderType.REPURCHASE_ORDER.getValue() == saOrder.getOrderType() && EOrderTypeExtend.REG_REP.getValue() == saOrder.getOrderTypeExtend())
        ) {
            // 注册类订单 或 注册转复购 订单
            // 会员账号 验证会员账户是否存在金额
            CuMember member = iCuMemberService.getMemberById(saOrder.getPkMember());
            // 会员变为死点
            member.setCategory(ECategory.LOGGED_OUT.getValue());
            member.setCustomerType(ECustomerType.DEAD_POINT.getValue());
            member.setPkModified(saOrder.getPkModified());
            member.setModifiedTime(DateUtils.currentDateTime());
            iCuMemberService.updateById(member);
            // 撤销正常订单，修改 cu_member_register 账户状态为死点
            CuMemberRegister cuMemberRegister = new CuMemberRegister();
            cuMemberRegister.setPkMember(member.getPkId());
            cuMemberRegister.setPkCountry(saOrder.getPkCountry());
            cuMemberRegister.setPkModified(saOrder.getPkCreator());
            iCuMemberRegisterService.updateCuMemberRegister(cuMemberRegister);
        }

        if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
            // 钱包支付，则需要回退金额
            // 默认回退给创建人
            CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
            cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        } else {
            // 在线支付，处理退款
            this.handleOnlineRefund(saOrder);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean singleRevokeMemberBySelfRevokeOrder(Long pkApprove, SaOrderExt saOrder, BusinessCommissionDTO businessCommissionDTO) {
        deductCancelOrderCost(businessCommissionDTO);
        // 回退给创建人
        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        if (EOrderType.REGISTER_ORDER.getValue() == saOrder.getOrderType()
                || EOrderType.SPECIAL_REGISTER_ORDER.getValue() == saOrder.getOrderType()
                || (EOrderType.REPURCHASE_ORDER.getValue() == saOrder.getOrderType() && EOrderTypeExtend.REG_REP.getValue() == saOrder.getOrderTypeExtend())
        ) {
            // 会员账号  验证会员账户是否存在金额
            CuMember member = iCuMemberService.getMember(saOrder.getPkMember());

            //删除会员
            LambdaUpdateWrapper<CuMember> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(CuMember::getMemberCode, CommonUtil.deleteMemberCode(member.getMemberCode()));
            updateWrapper.set(CuMember::getDelFlag, EDelFlag.DELETE.getValue());
            updateWrapper.set(CuMember::getModifiedTime, DateUtils.currentDateTime());
            updateWrapper.set(CuMember::getPkModified, saOrder.getPkModified());
            updateWrapper.eq(CuMember::getPkId, member.getPkId());
            iCuMemberService.update(updateWrapper);

            // 删除会员注册表
            LambdaUpdateWrapper<CuMemberRegister> updateWrapperRegister = new LambdaUpdateWrapper<>();
            updateWrapperRegister.set(CuMemberRegister::getDelFlag, EDelFlag.DELETE.getValue());
            updateWrapperRegister.set(CuMemberRegister::getModifiedTime, DateUtils.currentDateTime());
            updateWrapperRegister.set(CuMemberRegister::getPkModified, saOrder.getPkModified());
            updateWrapperRegister.eq(CuMemberRegister::getPkMember, member.getPkId());
            iCuMemberRegisterService.update(updateWrapperRegister);
        }
        if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
            // 钱包支付，则需要回退金额
            cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        } else {
            // 在线支付，处理退款
            this.handleOnlineRefund(saOrder);
        }
        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 = iCuMemberAccountService.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 = iAccountServiceApi.getBdAccountByFieldValue(pkCountry, accountValue).getData();
        CurrencyDTO currencyDTO = iCurrencyServiceApi.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);
        iCuMemberTradeService.save(cuMemberTrade);
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCuMemberAccountByDraw(Integer payNum, AcDrawRewardNumExt acDrawRewardNumExt) {
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder().pkMember(acDrawRewardNumExt.getPkMember()).build();
        cuMemberAccount.setPkCountry(acDrawRewardNumExt.getPkCountry());
        List<CuMemberAccountExt> cuMemberAccountExtList = iCuMemberAccountService.queryMemberAccountByCondition(cuMemberAccount);
        if (cuMemberAccountExtList.size() == 0) {
            throw new RuntimeException("没有找到会员账户");
        }
        BigDecimal payMoney = ComputeUtil.computeMultiply(acDrawRewardNumExt.getPayMoney(), payNum);
        CuMemberAccountExt cuMemberAccountExt = cuMemberAccountExtList.get(0);
        // 在线支付
        packageActivityTrade(cuMemberAccountExt.getPkMember(), cuMemberAccountExt.getPkCountry(), EAccount.CASH.getValue(),
                payMoney, cuMemberAccountExt.getAccount2(), ETradeType.RECHARGE_DRAW_PAY_NUMBER, ETradeClassify.RECHARGE.getValue());
        cuMemberAccountExt.setAccount2(ComputeUtil.computeAdd(cuMemberAccount.getAccount2(), payMoney));
        packageActivityTrade(cuMemberAccountExt.getPkMember(), cuMemberAccountExt.getPkCountry(), EAccount.CASH.getValue(),
                payMoney.negate(), cuMemberAccountExt.getAccount2(), ETradeType.DRAW_PAY_NUMBER, ETradeClassify.CONSUME.getValue());
        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) {
            iCuMemberTradeBonusService.batchInsertCuMemberTradeBonus(newCuMemberTradeBonusList);
        }
        // 根据 newCuMemberTradeBonusList 更新 cu_member_trade_detail
        iCuMemberTradeDetailService.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();

        updateMemberAccount.setPkMember(payMemberAccount.getPkMember());
        updateMemberAccount.setPkCountry(pkCountry);

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

            List<AreaCurrencyDTO> currencyDTOList = iAreaCurrencyServiceApi.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 = iCuMemberTradeBonusService.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(BaseEntity::getPkCreator).distinct().collect(Collectors.toList());
        List<CuMemberAccount> cuMemberAccountList = iCuMemberAccountService.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);
            // 删除等级
            iCuMemberLevelService.deleteCuMemberLevelRecord(saOrder.getPkId(), pkApprove, currentDateTime);
            // 回退奖衔,根据订单从 cu_member_awards查询
            iCuMemberAwardsService.deleteCuMemberAwards(saOrder.getPkId(), pkApprove, currentDateTime);
            iCuMemberService.deleteCuMemberByPkMember(pkMember, pkApprove, currentDateTime);
            iCuMemberAccountService.deleteCuMemberAccountByPkMember(pkMember, pkApprove, currentDateTime);
            // 撤销正常订单，修改 cu_member_register 账户状态为死点
            CuMemberRegister cuMemberRegister = new CuMemberRegister();
            cuMemberRegister.setPkMember(pkMember);
            cuMemberRegister.setPkCountry(saOrder.getPkCountry());
            cuMemberRegister.setPkModified(saOrder.getPkCreator());
            iCuMemberRegisterService.updateCuMemberRegister(cuMemberRegister);

            if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
                // 钱包支付，则需要回退金额
                CuMemberAccount payMemberAccount = cuMemberAccountMap.get(saOrder.getPkCreator());
                cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
            }
        }
        for (int i = memberList.size() - 1; i >= 0; i--) {
            Long pkMember = memberList.get(i);
            SaOrderExt saOrder = saOrderMap.get(pkMember);

            if (saOrder.getPayType().equals(EOrderPayType.ONLINE.getValue())) {
                // 在线支付，处理退款
                this.handleOnlineRefund(saOrder);
            }
        }
        return Boolean.TRUE;
    }

    private void deductCancelOrderCost(BusinessCommissionDTO businessCommissionDTO) {
        if (businessCommissionDTO != null) {
            if (!iCuMemberTradeService.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()
                || EOrderType.SPECIAL_UPGRADE_ORDER.getValue() == saOrder.getOrderType()
        ) {
            iCuMemberService.updateById(cuMember);
            // 回退等级
            iCuMemberLevelService.deleteCuMemberLevelRecord(saOrder.getPkId(), pkApprove, currentDateTime);
            // 回退奖衔,根据订单从 cu_member_awards查询
            iCuMemberAwardsService.deleteCuMemberAwards(saOrder.getPkId(), pkApprove, currentDateTime);
        }
        if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
            // 钱包支付，则需要回退金额
            // 部分撤单
            if (saOrder.getBackOrderAmount() != null && ComputeUtil.compareValue(saOrder.getBackOrderAmount())) {
                cancelPartOrderBackAmount(pkApprove, saOrder);
            } else {
                CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
                // 回退账号余额
                cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
            }
        } else {
            // 在线支付，处理退款
            this.handleOnlineRefund(saOrder);
        }
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelMemberAccount(Long pkMember, SaOrder saOrder) {
        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        // 回退账号余额
        cancelOrderBackAccount(pkMember, saOrder, payMemberAccount);
        return Boolean.TRUE;
    }

    @Override
    public void cancelPartOrderBackAmount(Long pkApprove, SaOrderExt saOrder) {
        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        BigDecimal backOrderAmount = saOrder.getBackOrderAmount();
        // 考虑部分撤单
        // 部分退，回退金额按照 币种扣除的倒叙扣除  现金->消费->奖金  奖金->消费->现金
        // 查询到必须扣除的币种
        // 查询专区所属币种
        List<AreaCurrencyDTO> areaCurrencyDTOList = iAreaCurrencyServiceApi.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 = iCuMemberTradeService.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) {
            iCuMemberTradeBonusService.batchInsertCuMemberTradeBonus(newCuMemberTradeBonusList);
        }
        // 根据 newCuMemberTradeBonusList 更新 cu_member_trade_detail
        iCuMemberTradeDetailService.updateAddCuMemberTradeDetail(cuMemberTradeDetailList);
        saveAndUpdateCuMember(cuMemberTradeList, updateMemberAccount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String orderChangeProductPre(SaOrder saOrder, SaOrder updateOrder) {
        // 查询会员订单支付币种
        List<CuMemberTrade> cuMemberTrades = iCuMemberTradeService.queryCuMemberTrade(saOrder.getPkCreator(), saOrder.getOrderCode());

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

        if (CollectionUtil.isNotEmpty(cuMemberTrades)) {
            List<AreaCurrencyDTO> currencyDTOList = iAreaCurrencyServiceApi.queryAreaCurrencyByPkCountry(saOrder.getPkCountry()).getData();
            Map<Integer, AreaCurrencyDTO> areaCurrencyMap = new HashMap<>();
            currencyDTOList.forEach(areaCurrencyDTO -> areaCurrencyMap.put(areaCurrencyDTO.getPkAccount(), areaCurrencyDTO));

            for (CuMemberTrade cuMemberTrade : cuMemberTrades) {
                BigDecimal tradeMoney = cuMemberTrade.getTradeAmount().negate();

                AreaCurrencyDTO currencyDto = areaCurrencyMap.get(cuMemberTrade.getPkAccount());
                // 用于更新账户余额
                BigDecimal oriTradeMoney = ReflectUtils.invokeGetter(tmpCuMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue());
                ReflectUtils.invokeSetter(tmpCuMemberAccount, MemberFieldConstants.ACCOUNT + currencyDto.getFieldValue(), ComputeUtil.computeAdd(oriTradeMoney, tradeMoney));
            }
        }

        // 获取需要扣除币种金额
        R<CuMemberAccountExt> resultR = iSaOrderServiceApi.queryOrderSpendDetails(tmpCuMemberAccount, updateOrder, null);
        if (!resultR.isSuccess()) {
            log.error("调换货物校验余额是否足够失败: {}", resultR.getMsg());
            return "调换货物校验余额是否足够失败";
        }
        CuMemberAccountExt cuMemberAccountExt = resultR.getData();
        if (!cuMemberAccountExt.getIsPayment()) {
            if (StringUtils.isEmpty(cuMemberAccountExt.getErrorMsg())) {
                return TransactionUtils.getContent(MemberMsgConstants.MEMBER_BALANCE_NOT_PAY);
            } else {
                return cuMemberAccountExt.getErrorMsg();
            }
        }
        return null;
    }

    @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, iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator()));

            // 查询会员当前余额
            CuMemberAccount cuMemberAccount = new CuMemberAccount();
            cuMemberAccount.setPkCountry(saOrder.getPkCountry());
            cuMemberAccount.setPkMember(saOrder.getPkCreator());
            CuMemberAccountExt tmpCuMemberAccount = iCuMemberAccountService.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 (!iCuMemberTradeService.businessCommissionSubmit((BusinessCommissionDTO) obj)) {
                    throw new ServiceException("业务手续费扣款失败");
                }
            }
        }
    }

    @Override
    public String orderSelfDeliver(Long pkMember, Integer pkRate, Integer pkCountry, BigDecimal postage, Long userId) {
        // 查询退邮费对应币种
        BdAccount bdAccount = iAccountServiceApi.queryPostageAccount(pkCountry).getData();
        if (null == bdAccount) {
            log.error("订单自提邮费返还失败，未配置对应币种。 pkMember: {}, postage: {}", pkMember, postage);
            return "订单自提邮费返还失败，未配置对应币种";
        }

        // 当前时间
        Date nowDate = new Date();

        // 会员账户
        CuMemberAccount cuMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        // 会员更新账户
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        updateMemberAccount.setPkMember(pkMember);
        updateMemberAccount.setPkCountry(cuMemberAccount.getPkCountry());
        ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.PAY_ACCOUNT + bdAccount.getFieldValue(), postage);

        // 修改前余额
        BigDecimal tradeBeforeBalance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + bdAccount.getFieldValue());
        // 会员交易明细
        CuMemberTrade cuMemberTrade = new CuMemberTrade();
        cuMemberTrade.setPkMember(pkMember);
        cuMemberTrade.setTradeCode(CommonUtil.createSerialNumber(EOrderPrefix.TRADE_CODE.getValue()));
        cuMemberTrade.setPkAccount(bdAccount.getPkId());
        cuMemberTrade.setTradeType(ETradeType.ORDER_SELF_DELIVER.getValue());
        cuMemberTrade.setTradeClassify(ETradeClassify.REFUND.getValue());
        cuMemberTrade.setPkRate(pkRate);
        cuMemberTrade.setTradeBeforeBalance(tradeBeforeBalance);
        cuMemberTrade.setTradeAmount(postage);
        cuMemberTrade.setTradeBalance(tradeBeforeBalance.add(postage));
        cuMemberTrade.setTradeStatue(ETradeStatus.TAKE_EFFECT.getValue());
        cuMemberTrade.setRemarks(ETradeType.ORDER_SELF_DELIVER.getLabel());
        cuMemberTrade.setPkCountry(pkCountry);
        cuMemberTrade.setPkCreator(userId);
        cuMemberTrade.setCreationTime(nowDate);

        // 保存会员交易明细
        iCuMemberTradeService.save(cuMemberTrade);
        // 更新会员账户
        iCuMemberAccountService.updateMemberAccount(updateMemberAccount, userId);

        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateMemberLevel(CuMember cuMember, SaOrder saOrder, Integer pkOldLevel) {
        updateCuMember(cuMember);
        saveLevelUpgrade(cuMember, EUpgradeType.ACTIVITY_UPGRADE.getValue(), saOrder, pkOldLevel);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void reduceMemberLevel(CuMember cuMember, Long pkOrder) {
        updateCuMember(cuMember);
        iCuMemberLevelService.update(Wrappers.<CuMemberLevel>lambdaUpdate()
                .eq(CuMemberLevel::getPkMember, cuMember.getPkId())
                .eq(CuMemberLevel::getUpType, EUpgradeType.ACTIVITY_UPGRADE.getValue())
                .eq(CuMemberLevel::getPkOrder, pkOrder)
                .set(CuMemberLevel::getDelFlag, EDelFlag.DELETE.getValue())
                .set(CuMemberLevel::getUpgradeTime, new Date())
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeMemberLevel(SaOrder saOrder, SaOrder newOrder) {
        iCuMemberLevelService.update(Wrappers.<CuMemberLevel>lambdaUpdate()
                .eq(CuMemberLevel::getPkMember, saOrder.getPkReference())
                .eq(CuMemberLevel::getUpType, EUpgradeType.ACTIVITY_UPGRADE.getValue())
                .eq(CuMemberLevel::getPkOrder, saOrder.getPkId())
                .set(CuMemberLevel::getPkOrder, newOrder.getPkId())
                .set(CuMemberLevel::getUpgradeTime, newOrder.getPayTime())
        );
    }

    @Override
    public CuMember queryCuMemberPlaceDept(CuMember cuMember, Boolean isFirst, Boolean isFirstAchieve) {
        Long pkMember = cuMember.getPkParent();
        Integer pkCountry = cuMember.getPkSettleCountry();
        // 获取推荐人的左右区
        CuMember parentMember = iCuMemberService.queryMember(pkMember);
        int placeDept;
        // 查询当前的业绩
        CuMemberAchieve cuMemberAchieve = iCuMemberAchieveService.queryCuMemberAchieveByPkMember(pkMember, pkCountry);
        placeDept = getPlaceDept(isFirst, isFirstAchieve, cuMemberAchieve, parentMember.getPkId());
        CuMemberExt cuMemberExt = iCuMemberService.queryPlaceSponsorLastLeft(pkMember, placeDept);
        CuMember placeCuMember = new CuMember();
        if (cuMemberExt != null) {
            placeCuMember.setPkPlaceParent(cuMemberExt.getPkId());
            placeCuMember.setMemberCode(cuMemberExt.getMemberCode());
            placeCuMember.setMemberName(cuMemberExt.getMemberName());
            placeCuMember.setPkVertex(cuMemberExt.getPkVertex());
            placeCuMember.setServiceCode(cuMemberExt.getServiceCode());
            placeCuMember.setNickName(cuMemberExt.getNickName());
            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.setPkVertex(parentMember.getPkVertex());
            placeCuMember.setServiceCode(parentMember.getServiceCode());
            placeCuMember.setNickName(parentMember.getNickName());
        }
        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.compareGreaterThan(cuMemberAchieve.getASumPv(), cuMemberAchieve.getBSumPv())) {
                        placeDept = EPlaceDept.RIGHT_DEPT.getValue();
                    }
                } else {
                    // 188判断左右区真实业绩，放入小区
                    if (ComputeUtil.compareValue(ComputeUtil.computeAdd(cuMemberAchieve.getASumRealPv(), cuMemberAchieve.getBSumRealPv()))) {
                        if (ComputeUtil.compareValue(cuMemberAchieve.getASumRealPv(), cuMemberAchieve.getBSumRealPv())) {
                            placeDept = EPlaceDept.RIGHT_DEPT.getValue();
                        }
                    } else {
                        // 验证左右区人数，放入人数少的
                        List<CuMember> personNumList = iCuMemberService.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 String handleMemberContinue(MemberContinueDTO memberContinueDTO) {
        // 会员ID列表
        List<Long> pkMemberList = memberContinueDTO.getPkMemberList();
        // 会员续约类型
        EMemberContinue eMemberContinue = memberContinueDTO.getEMemberContinue();

        for (Long pkMember : pkMemberList) {
            String str = null;
            switch (eMemberContinue) {
                case REGISTER_ORDER:
                case UPGRADE_ORDER:
                case UPGRADE_CANCEL:
                case CHANGE_AWARDS:
                case CHANGE_INFO:
                case BUY_GIFT:
                    // 注册订单、升级订单、升级撤单、会员修改奖衔、修改会员姓名或手机号、续约礼包
                    // 走会员存在的处理方式
                    str = this.handleExistMemberContinue(pkMember, eMemberContinue);
                    break;
                case REGISTER_CANCEL:
                    // 注册撤单
                    // 走会员不存在的处理方式
                    str = this.handleNotExistMemberContinue(pkMember);
                    break;
                default:
                    log.error("会员续约处理传入类型错误，memberContinueDTO : {}", memberContinueDTO);
                    break;
            }
            if (null != str) {
                log.error("会员续约处理失败: {}", str);
                return "会员续约处理失败: " + str;
            }
        }

        return null;
    }

    /**
     * 存在会员处理续约
     *
     * @param pkMember        会员ID
     * @param eMemberContinue 续约处理类型
     * @return
     */
    private String handleExistMemberContinue(Long pkMember, EMemberContinue eMemberContinue) {
        // 查询会员信息
        CuMember cuMember = iCuMemberService.queryMember(pkMember);
        if (null == cuMember) {
            log.error("会员续约有效期处理，会员不存在 pkMember ：{}", pkMember);
            return "会员不存在";
        }

        // 会员姓名
        String memberName = cuMember.getMemberName();
        // 联系方式
        String phone = cuMember.getPhone();
        // 所属国家
        Integer pkCountry = cuMember.getPkSettleCountry();

        // 查询同姓名、同手机号最高奖衔
        CuMemberExt cuMemberExt = iCuMemberService.querySameMemberByAwards(memberName, phone, pkCountry);

        // 休止期月数会员为6个月
        int stopMonth = 6;
        if (cuMemberExt.getAwardsValue() > EAwards.MEMBER.getValue()) {
            // 最高奖衔不是会员，休止期时间为12个月
            stopMonth = 12;
        }

        switch (eMemberContinue) {
            case REGISTER_ORDER:
                // 注册订单
                // 更新前，记录历史同姓名、同手机号【有效期】和【休止期】，撤单时需要使用
                iCuMemberExpireHistoryService.saveExpireHistory(pkMember, memberName, phone, pkCountry);
                // 【有效期】只更新同手机号比自己有效期早的，【休止期】按照同姓名、同手机号下最高奖衔的来算 -- 新注册订单，有效期肯定是最大的
                iCuMemberService.updateExpireAndStopDate(pkMember, memberName, phone, cuMember.getExpireDate(), stopMonth, pkCountry);
                break;
            case UPGRADE_ORDER:
                // 升级订单
                if (DateUtils.betweenDay(cuMemberExt.getExpireDate(), cuMemberExt.getStopDate()) >= 190 || stopMonth == 6) {
                    // 【休止期】已经比【有效期】大6个月以上，已经是最长时间了，不需要任何处理
                    // 最长休止期为6个月，不需要任何处理
                    return null;
                } else {
                    // 只需要处理【休止期】
                    iCuMemberService.updateStopDate(pkMember, memberName, phone, stopMonth, pkCountry);
                }
                break;
            case UPGRADE_CANCEL:
                // 升级撤单
                if (stopMonth == 6) {
                    // 休止期是6个月，只需要处理【休止期】
                    iCuMemberService.updateStopDate(pkMember, memberName, phone, stopMonth, pkCountry);
                }
                break;
            case CHANGE_AWARDS:
                // 会员修改奖衔
                // 只需要处理【休止期】
                iCuMemberService.updateStopDate(pkMember, memberName, phone, stopMonth, pkCountry);
                break;
            case BUY_GIFT:
                // 续约礼包，下单成功后，更新【有效期】【休止期】
                // 【有效期】【休止期】全部更新为续约这个最新的会员数据
                iCuMemberService.updateExpireAndStopDate(pkMember, memberName, phone, null, stopMonth, pkCountry);
                break;
            case CHANGE_INFO:
                // 变更户籍（修改会员姓名 或 手机号）
                // 更新前，记录历史同姓名、同手机号【有效期】和【休止期】
                iCuMemberExpireHistoryService.saveExpireHistory(pkMember, memberName, phone, pkCountry);
                // 【有效期】按最新更新，【休止期】按照同姓名、同手机号下最高奖衔的来算
                iCuMemberService.updateExpireAndStopDateByChange(pkMember, memberName, phone, stopMonth, pkCountry);
                break;
            default:
                log.error("会员续约处理传入类型错误，eMemberContinue : {}", eMemberContinue);
                return "会员续约处理传入类型错误";
        }

        // 更新有效状态
        iCuMemberService.updateExpireStatus(null, memberName, phone, pkCountry);

        return null;
    }

    /**
     * 不存在会员处理续约
     * 注册撤单处理时，会员信息已经不存在，需要单独处理
     *
     * @param pkMember 会员ID
     * @return
     */
    private String handleNotExistMemberContinue(Long pkMember) {
        // 查询会员信息
        CuMember cuMember = iCuMemberService.queryMemberNotFlag(null, pkMember);
        if (null == cuMember) {
            log.error("会员续约有效期处理，会员不存在 pkMember ：{}", pkMember);
            return "会员不存在";
        }

        // 会员姓名
        String memberName = cuMember.getMemberName();
        // 联系方式
        String phone = cuMember.getPhone();
        // 所属国家
        Integer pkCountry = cuMember.getPkSettleCountry();

        // 查询同姓名、同手机号最高奖衔
        CuMemberExt cuMemberExt = iCuMemberService.querySameMemberByAwards(memberName, phone, pkCountry);
        if (null == cuMemberExt) {
            log.info("会员续约不处理，会员撤单后不存在相同户籍数据");
            return null;
        }

        // 休止期月数会员为6个月
        int stopMonth = 6;
        if (cuMemberExt.getAwardsValue() > EAwards.MEMBER.getValue()) {
            // 最高奖衔不是会员，休止期时间为12个月
            stopMonth = 12;
        }

        // 查询历史【有效期】记录
        CuMemberExpireHistory cuMemberExpireHistory = iCuMemberExpireHistoryService.queryLastData(pkMember, memberName, phone, pkCountry);
        if (null != cuMemberExpireHistory) {
            // 有历史【有效期】记录
            // 同姓名、同手机号，重置有效期等为历史记录中数据
            iCuMemberService.resetExpireAndStopDate(memberName, phone, cuMemberExpireHistory.getExpireDate(), cuMemberExpireHistory.getStopDate(), pkCountry);
        } else {
            // 没有历史【有效期】记录
            // 只需要处理【休止期】
            iCuMemberService.updateStopDate(pkMember, memberName, phone, stopMonth, pkCountry);
        }
        // 更新有效状态
        iCuMemberService.updateExpireStatus(null, memberName, phone, pkCountry);

        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderReturnBatch(SaOrder saOrder, Long userId) {
        // 当前时间
        Date nowDate = new Date();
//        // 交易明细数据 -- 入库使用
//        List<CuMemberTrade> saveMemberTradeList = new ArrayList<>();
//        // 会员账户map（key：会员ID， value：会员账户）
//        Map<Long, CuMemberAccount> memberAccountMap = new HashMap<>();
//        // 更新会员账户map（key：会员ID， value：会员账户） -- 入库使用
//        Map<Long, CuMemberAccount> updateMemberAccountMap = new HashMap<>();
//        // 需要清除会员列表
//        List<Long> pkMemberList = new ArrayList<>();
//
//        for (OrderReturnPaymentDTO paymentDTO : returnDTOList) {
//            // 订单
//            SaOrder saOrder = paymentDTO.getSaOrder();
//            // 订单编号
//            String orderCode = saOrder.getOrderCode();
//            // 订单所属国
//            int pkCountry = saOrder.getPkCountry();
//            // 订单购买人
//            long pkMember = saOrder.getPkCreator();
//            // 记录会员ID，最后用于清除会员信息
//            pkMemberList.add(pkMember);
//
//            // 订单创建人账户
//            CuMemberAccount cuMemberAccount = memberAccountMap.get(pkMember);
//            if (null == cuMemberAccount) {
//                // 不存在则查询
//                cuMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
//                memberAccountMap.put(pkMember, cuMemberAccount);
//            }
//            // 更新会员账户
//            CuMemberAccount updateMemberAccount = updateMemberAccountMap.get(pkMember);
//            if (null == updateMemberAccount) {
//                // 不存在则新建
//                updateMemberAccount = new CuMemberAccount();
//                updateMemberAccount.setPkMember(pkMember);
//                updateMemberAccount.setPkCountry(pkCountry);
//                updateMemberAccountMap.put(pkMember, updateMemberAccount);
//            }
//
//            // 订单所属专区扣币的第一位配置
//            AreaCurrencyDTO areaCurrencyDTO = iAreaCurrencyServiceApi.queryAreaCurrencyByCondition(saOrder.getOrderType(), pkCountry).getData().get(0);
//            // 专区扣币的第一位配置所用字段
//            String accountField = MemberFieldConstants.ACCOUNT + areaCurrencyDTO.getFieldValue();
//
//            if (EOrderPayType.WALLET.getValue() == saOrder.getPayType()) {
//                // 钱包支付
//                // 查询之前订单的支付明细
//                List<CuMemberTrade> memberTradeList = iCuMemberTradeService.querySourceCodeLastTrade(pkMember, orderCode, null);
//
//                // 获取所有账户配置ID
//                List<Integer> pkAccountList = memberTradeList.stream().map(CuMemberTrade::getPkAccount).collect(Collectors.toList());
//                // 账户对应账户配置map
//                Map<Integer, BdAccount> accountMap = iAccountServiceApi.getAccountMap(pkAccountList).getData();
//
//                // 根据之前交易明细，生成红冲交易数据
//                for (CuMemberTrade cuMemberTrade : memberTradeList) {
//                    // 账户取值所用字段
//                    String field = MemberFieldConstants.ACCOUNT + accountMap.get(cuMemberTrade.getPkAccount()).getFieldValue();
//                    // 交易金额
//                    BigDecimal tradeAmount = cuMemberTrade.getTradeAmount().negate();
//                    // 交易前余额
//                    BigDecimal tradeBeforeBalance = ReflectUtils.invokeGetter(cuMemberAccount, field);
//                    // 交易余额
//                    BigDecimal tradeBalance = tradeBeforeBalance.add(tradeAmount);
//
//                    // 封装交易明细
//                    saveMemberTradeList.add(this.createMemberTradeByTrade(cuMemberTrade, ETradeType.ORDER_REFUND_ADJUST, ETradeClassify.REFUND, tradeBeforeBalance, tradeBalance, null, userId));
//
//                    // 原账户余额
//                    ReflectUtils.invokeSetter(cuMemberAccount, field, tradeBalance);
//                    // 设置更新账户变动余额
//                    ReflectUtils.invokeSetter(updateMemberAccount, field, tradeAmount);
//                }
//            } else {
//                // 在线支付
//                // 交易金额（订单金额 + 邮费）
//                BigDecimal tradeAmount = saOrder.getOrderAmount().add(saOrder.getPostage());
//                // 交易前余额
//                BigDecimal tradeBeforeBalance = ReflectUtils.invokeGetter(cuMemberAccount, accountField);
//                // 交易余额
//                BigDecimal tradeBalance = tradeBeforeBalance.add(tradeAmount);
//
//                // 封装交易流水
//                saveMemberTradeList.add(this.createMemberTradeByOrder(saOrder, areaCurrencyDTO.getPkAccount(), ETradeType.RETURN_MONEY, ETradeClassify.REFUND, tradeBeforeBalance, tradeAmount, ETradeType.RETURN_MONEY.getLabel(), userId));
//
//                // 原账户余额
//                ReflectUtils.invokeSetter(cuMemberAccount, accountField, tradeBalance);
//                // 设置更新账户余额
//                ReflectUtils.invokeSetter(updateMemberAccount, accountField, tradeAmount);
//            }
//
//            // 变动金额
//            BigDecimal changeAmount = paymentDTO.getReturnAmount();
//            // 变动备注
//            String changeRemark = paymentDTO.getReturnRemark();
//
//            if (null != changeAmount && changeAmount.compareTo(BigDecimal.ZERO) != 0) {
//                // 存在退返金额 并且不为0，则进行处理，退回给订单所属专区扣币第一位配置
//                // 交易前余额
//                BigDecimal tradeBeforeBalance = ReflectUtils.invokeGetter(cuMemberAccount, accountField);
//
//                // 封装交易流水
//                saveMemberTradeList.add(this.createMemberTradeByOrder(saOrder, areaCurrencyDTO.getPkAccount(), ETradeType.ORDER_REFUND_ADJUST, ETradeClassify.REFUND, tradeBeforeBalance, changeAmount, changeRemark, userId));
//
//                // 变动前账户
//                BigDecimal changeBeforeAccount = ReflectUtils.invokeGetter(updateMemberAccount, accountField);
//                if (null == changeBeforeAccount) {
//                    // 如果为空，直接赋值
//                    ReflectUtils.invokeSetter(updateMemberAccount, accountField, changeAmount);
//                } else {
//                    // 如果不为空，进行累加
//                    ReflectUtils.invokeSetter(updateMemberAccount, accountField, changeBeforeAccount.add(changeAmount));
//                }
//            }
//        }
//
//        // 批量插入会员明细
//        iCuMemberTradeService.batchSaveTradeByMemberCode(saveMemberTradeList);
//
//        // 批量更新会员余额
//        for (Long key : updateMemberAccountMap.keySet()) {
//            CuMemberAccount cuMemberAccount = updateMemberAccountMap.get(key);
//            // 奖金账户有变化，需要同步处理 可提现奖金账户
//            BigDecimal bonusBigDecimal = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + 4);
//            if (null != bonusBigDecimal && bonusBigDecimal.compareTo(BigDecimal.ZERO) != 0) {
//                // 奖金账户变化不为空，则需要同步处理 奖金可提现账户
//                ReflectUtils.invokeSetter(cuMemberAccount, MemberFieldConstants.WITHDRAW_ACCOUNT + 4, bonusBigDecimal);
//            }
//            iCuMemberAccountService.updateMemberAccount(cuMemberAccount, userId);
//        }

        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        // 回退账号余额
        cancelOrderBackAccount(userId, saOrder, payMemberAccount);

        if (EOrderType.REGISTER_ORDER.getValue() == saOrder.getOrderType()
                || EOrderType.SPECIAL_REGISTER_ORDER.getValue() == saOrder.getOrderType()) {
            // 注册类订单，需要更新用户为已注销状态
            LambdaUpdateWrapper<CuMember> memberUpdateWrapper = new LambdaUpdateWrapper<>();
            memberUpdateWrapper.eq(CuMember::getPkId, saOrder.getPkMember());
            memberUpdateWrapper.set(CuMember::getPkModified, userId);
            memberUpdateWrapper.set(CuMember::getModifiedTime, nowDate);
            memberUpdateWrapper.set(CuMember::getCategory, ECategory.LOGGED_OUT.getValue());
            iCuMemberService.update(memberUpdateWrapper);
            // 添加会员信息修改记录
            CuMemberChangeLog cuMemberChangeLog = new CuMemberChangeLog();
            cuMemberChangeLog.setPkMember(saOrder.getPkMember());
            cuMemberChangeLog.setChangeType(EMemberChangeType.ORDER_RETURN.getValue());
            cuMemberChangeLog.setChangeFront("");
            cuMemberChangeLog.setChangeAfter(ECategory.LOGGED_OUT.getLabel());
            iCuMemberChangeLogService.save(cuMemberChangeLog);
        }

        // 根据订单退业绩
        Boolean bool = iMemberSettleBonusApi.chargeBackSaOrder(saOrder);
        if (!bool) {
            log.error("订单退单同意处理失败: 订单退业绩失败");
            throw new BaseException(TransactionUtils.getContent(CommonMsgConstants.APPROVAL_ERROR) + "：" + "订单业务回退失败");
        }

    }

    /**
     * 在线支付退款
     *
     * @param saOrder
     */
    private void handleOnlineRefund(SaOrderExt saOrder) {
        R<TOnlinePayment> onlinePaymentR = itOnlinePaymentServiceApi.getOnlinePayment(saOrder.getOrderCode());
        if (ObjectUtil.isNotEmpty(onlinePaymentR)) {
            TOnlinePayment onlinePayment = onlinePaymentR.getData();
            if (ObjectUtil.isNotEmpty(onlinePayment)) {
                R<String> result = itOnlinePaymentServiceApi.refund(saOrder.getOrderCode(), saOrder.getPkCreator());
                if (!result.isSuccess()) {
                    throw new ServiceException(result.getMsg());
                }
            }
        }
    }

}
