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.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hzs.common.core.constant.*;
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.*;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.core.web.domain.BaseEntity;
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.retail.member.CuMemberRetailRegion;
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.system.config.BdGrade;
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.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.retail.member.service.ICuMemberRetailRegionService;
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.IGradeServiceApi;
import com.hzs.system.config.dto.AreaCurrencyDTO;
import com.hzs.system.config.dto.GradeDTO;
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
    IGradeServiceApi iGradeServiceApi;
    @DubboReference
    ICurrencyServiceApi iCurrencyServiceApi;
    @DubboReference
    ISaOrderServiceApi iSaOrderServiceApi;

    @DubboReference
    ITOnlinePaymentServiceApi itOnlinePaymentServiceApi;

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


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCuMember(CuMember cuMember) {
        redisService.lockKeyMany(CacheConstants.UPD_MEMBER + cuMember.getMemberCode());
        try {
            iCuMemberService.updateById(cuMember);
        } finally {
            redisService.unlock(CacheConstants.UPD_MEMBER + cuMember.getMemberCode());
        }
    }

    @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);
        } 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 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 iCuMemberLevelService.save(cuMemberLevel);
    }

    /**
     * 保存奖衔, 升级送奖项默认免考
     *
     * @param cuMember    会员
     * @param levelType   升级类型
     * @param saOrder     订单
     * @param pkOldAwards 会员
     */
    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;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveShareMember(CuMember cuMember) {
        // 保存会员
        iCuMemberService.saveMember(cuMember);
        // 保存账户
        saveMemberAccount(cuMember);
        // 用户注册信息
        CuMemberRegister cuMemberRegister = BeanUtil.copyProperties(cuMember, CuMemberRegister.class);
        cuMemberRegister.setPkMember(cuMember.getPkId());
        iCuMemberRegisterService.save(cuMemberRegister);
    }

    /**
     * 保存会员账户信息
     *
     * @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());
        iCuMemberRegisterService.save(cuMemberRegister);
    }

    @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;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CuMemberAccountExt insertRetailMemberRecharge(SaOrder saOrder) {
        // 更新会员账户
        BdAccount bdAccount = iAccountServiceApi.queryAccountByCondition(saOrder.getPkCountry()).getData();
        if (bdAccount == null) {
            return null;
        }
        return insertRechargeTrade(saOrder, bdAccount);
    }

    /**
     * 插入充值记录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 账户
     * @Description: 插入会员的交易明细
     * @return: void
     * @Author: sui q
     * @Date: 2022/9/13 15:12
     */
    @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);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertRetailMemberTrade(SaOrder saOrder, CuMemberAccountExt cuMemberAccount) {
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        List<CuMemberTrade> cuMemberTradeList = getCuMemberTrade(saOrder, cuMemberAccount, updateMemberAccount);
        saveAndUpdateCuMember(cuMemberTradeList, null);
    }

    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 -> {
            // 交易值,交易值是否已经取返
            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);
        }
        if (null != updateMemberAccount) {
            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);
        Date currentDateTime = DateUtils.currentDateTime();

        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        if (EOrderType.RETAIL_REGISTER.getValue() == saOrder.getOrderType()) {
            // 会员账号  验证会员账户是否存在金额
            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);
        }

        // 处理推荐人等级
        handleParentLevel(saOrder, currentDateTime);
        // 删除会员区域
        iCuMemberRetailRegionService.update(Wrappers.<CuMemberRetailRegion>lambdaUpdate()
                .eq(CuMemberRetailRegion::getPkMember, saOrder.getPkMember())
                .set(CuMemberRetailRegion::getDelFlag, EDelFlag.DELETE.getValue())
                .set(CuMemberRetailRegion::getModifiedTime, currentDateTime)
        );

        if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
            // 钱包支付，则需要回退金额
            // 默认回退给创建人
            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);
        Date currentDateTime = DateUtils.currentDateTime();
        // 回退给创建人
        CuMemberAccount payMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(saOrder.getPkCreator());
        if (EOrderType.RETAIL_REGISTER.getValue() == saOrder.getOrderType()) {
            // 会员账号  验证会员账户是否存在金额
            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, 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, currentDateTime);
            updateWrapperRegister.set(CuMemberRegister::getPkModified, saOrder.getPkModified());
            updateWrapperRegister.eq(CuMemberRegister::getPkMember, member.getPkId());
            iCuMemberRegisterService.update(updateWrapperRegister);
        }

        // 处理推荐人等级
        handleParentLevel(saOrder, currentDateTime);
        // 删除会员区域
        iCuMemberRetailRegionService.update(Wrappers.<CuMemberRetailRegion>lambdaUpdate()
                .eq(CuMemberRetailRegion::getPkMember, saOrder.getPkMember())
                .set(CuMemberRetailRegion::getDelFlag, EDelFlag.DELETE.getValue())
                .set(CuMemberRetailRegion::getModifiedTime, currentDateTime)
        );
        if (saOrder.getPayType().equals(EOrderPayType.WALLET.getValue())) {
            // 钱包支付，则需要回退金额
            cancelOrderBackAccount(pkApprove, saOrder, payMemberAccount);
        } else {
            // 在线支付，处理退款
            this.handleOnlineRefund(saOrder);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void selfInsertMemberTrade(SaOrder saOrder, CuMemberAccount cuMemberAccount) {
        CuMemberAccountExt ext = BeanUtil.copyProperties(cuMemberAccount, CuMemberAccountExt.class);
        insertMemberTrade(saOrder, ext);
    }

    @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;
    }

    /**
     * 插销订单，回退给创建人金额
     *
     * @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;
    }

    /**
     * @Description: 撤销订单，回退奖金账户金额
     * @return: void
     * @Author: sui q
     * @Date: 2023/3/30 15:32
     */
    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("撤销订单扣除业务手续费失败");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean normalRevokeOrder(Long pkApprove, SaOrderExt saOrder, CuMember cuMember, BusinessCommissionDTO businessCommissionDTO) {
        deductCancelOrderCost(businessCommissionDTO);
        Date currentDateTime = DateUtils.currentDateTime();

        if (EOrderType.RETAIL_UPGRADE.getValue() == saOrder.getOrderType()) {
            // 升级订单
            // 回退等级
            iCuMemberLevelService.deleteCuMemberLevelRecord(saOrder.getPkId(), pkApprove, currentDateTime);
            // 删除会员区域
            iCuMemberRetailRegionService.update(Wrappers.<CuMemberRetailRegion>lambdaUpdate()
                    .eq(CuMemberRetailRegion::getPkMember, saOrder.getPkMember())
                    .set(CuMemberRetailRegion::getDelFlag, EDelFlag.DELETE.getValue())
                    .set(CuMemberRetailRegion::getModifiedTime, currentDateTime)
            );
        }

        // 更新会员标记，如果是则更新会员信息
        if (saOrder.getUpdateFlag() != null && EYesNo.YES.getIntValue() == saOrder.getUpdateFlag()) {
            if (null != cuMember) {
                // 更新会员信息
                iCuMemberService.updateById(cuMember);
            }
        }

        // 处理推荐人等级
        this.handleParentLevel(saOrder, currentDateTime);

        // 部分撤单 todo  发货后邮费不退，未发货退邮费
        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("业务手续费扣款失败");
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderReturn(SaOrder saOrder, Long userId, BigDecimal changeAmount, String changeRemark) {
        // 当前时间
        Date nowDate = new Date();
        // 订单编号
        String orderCode = saOrder.getOrderCode();
        // 订单购买人
        Long pkMember = saOrder.getPkCreator();
        // 订单所属国
        Integer pkCountry = saOrder.getPkCountry();

        // 更新账户余额
        CuMemberAccount updateMemberAccount = new CuMemberAccount();
        updateMemberAccount.setPkMember(pkMember);
        updateMemberAccount.setPkCountry(pkCountry);
        // 红冲交易明细数据
        List<CuMemberTrade> saveMemberTradeList = new ArrayList<>();

        // 查询订单创建人账户
        CuMemberAccount cuMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        // 订单所属专区扣币的第一位配置
        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.RETURN_MONEY, ETradeClassify.REFUND, tradeBeforeBalance, tradeAmount, ETradeType.RETURN_MONEY.getLabel(), 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);
        }

        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);

        // 奖金账户有变化，需要同步处理 可提现奖金账户
        BigDecimal bonusBigDecimal = ReflectUtils.invokeGetter(updateMemberAccount, MemberFieldConstants.ACCOUNT + 4);
        if (null != bonusBigDecimal && bonusBigDecimal.compareTo(BigDecimal.ZERO) != 0) {
            // 奖金账户变化不为空，则需要同步处理 奖金可提现账户
            ReflectUtils.invokeSetter(updateMemberAccount, MemberFieldConstants.WITHDRAW_ACCOUNT + 4, bonusBigDecimal);
        }
        // 更新会员余额
        iCuMemberAccountService.updateMemberAccount(updateMemberAccount, userId);

        // 更新创建人账号（根据订单类型不同，进行处理）
        switch (EOrderType.getEnumByValue(saOrder.getOrderType())) {
            case REGISTER_ORDER:
                // 注册类订单，需要更新用户为已注销状态
                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.setChangeAfter(ECategory.LOGGED_OUT.getLabel());
                iCuMemberChangeLogService.save(cuMemberChangeLog);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderReturnMember(List<Long> pkMemberList, Long userId) {
        // 注册类订单，需要更新用户为已注销状态
        LambdaUpdateWrapper<CuMember> memberUpdateWrapper = new LambdaUpdateWrapper<>();
        memberUpdateWrapper.in(CuMember::getPkId, pkMemberList);
        memberUpdateWrapper.set(CuMember::getPkModified, userId);
        memberUpdateWrapper.set(CuMember::getModifiedTime, new Date());
        memberUpdateWrapper.set(CuMember::getCategory, ECategory.LOGGED_OUT.getValue());
        iCuMemberService.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);
        }
        iCuMemberChangeLogService.saveBatch(cuMemberChangeLogList);
    }


    /**
     * 根据订单生成
     *
     * @param saOrder        订单
     * @param pkAccount      账户类型
     * @param eTradeType     交易类型（小类）
     * @param eTradeClassify 交易分类（大类）
     * @param beforeBalance  交易前余额
     * @param tradeAmount    交易金额
     * @param remarks        备注
     * @param userId         操作用户
     * @return
     */
    private CuMemberTrade createMemberTradeByOrder(SaOrder saOrder, Integer pkAccount, ETradeType eTradeType, ETradeClassify eTradeClassify,
                                                   BigDecimal beforeBalance, BigDecimal tradeAmount, String remarks, Long userId) {
        CuMemberTrade result = CuMemberTrade.builder()
                .pkMember(saOrder.getPkCreator())
                .tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .pkAccount(pkAccount)
                .tradeType(eTradeType.getValue())
                .tradeClassify(eTradeClassify.getValue())
                .pkRate(saOrder.getPkRate())
                .tradeBeforeBalance(beforeBalance)
                .tradeAmount(tradeAmount)
                .tradeBalance(beforeBalance.add(tradeAmount))
                .sourceCode(saOrder.getOrderCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(remarks)
                .build();
        result.setPkCountry(saOrder.getPkCountry());
        result.setPkCreator(userId);
        result.setCreationTime(new Date());
        return result;
    }

    /**
     * 根据交易明细生成
     *
     * @param cuMemberTrade  交易明细
     * @param eTradeType     交易类型（小类）
     * @param eTradeClassify 交易分类（大类）
     * @param beforeBalance  交易前余额
     * @param tradeAmount    交易金额
     * @param remarks        备注
     * @param userId         操作用户
     * @return
     */
    private CuMemberTrade createMemberTradeByTrade(CuMemberTrade cuMemberTrade, ETradeType eTradeType, ETradeClassify eTradeClassify,
                                                   BigDecimal beforeBalance, BigDecimal tradeAmount, String remarks, Long userId) {
        CuMemberTrade result = CuMemberTrade.builder()
                .pkMember(cuMemberTrade.getPkMember())
                .tradeCode(memberToolsHandler.createTradeCode(EOrderPrefix.TRADE_CODE.getValue()))
                .pkAccount(cuMemberTrade.getPkAccount())
                .tradeType(eTradeType.getValue())
                .tradeClassify(eTradeClassify.getValue())
                .pkRate(cuMemberTrade.getPkRate())
                .tradeBeforeBalance(beforeBalance)
                .tradeAmount(tradeAmount)
                .tradeBalance(beforeBalance.add(tradeAmount))
                .sourceCode(cuMemberTrade.getSourceCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(remarks)
                .build();
        result.setPkCountry(cuMemberTrade.getPkCountry());
        result.setPkCreator(userId);
        result.setCreationTime(new Date());
        return result;
    }

    @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;
    }

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

    @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 业绩
     * @return: Integer
     * @Author: sui q
     * @Date: 2023/3/15 9:35
     */
    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 {
                    // 嗨粉判断复购业绩 放入小区
                    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 = 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 void saveRetailMember(CuMember cuMember, SaOrderExt saOrder, CuMemberAccountExt cuMemberAccountExt) {
        // 保存会员信息
        iCuMemberService.saveMember(cuMember);

        // 保存会员账户信息
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder()
                .pkMember(cuMember.getPkId())
                .build();
        cuMemberAccount.setPkCreator(cuMember.getPkCreator());
        cuMemberAccount.setPkCountry(cuMember.getPkSettleCountry());
        iCuMemberAccountService.save(cuMemberAccount);

        // 保存会员注册信息
        CuMemberRegister cuMemberRegister = BeanUtil.copyProperties(cuMember, CuMemberRegister.class);
        cuMemberRegister.setPkMember(cuMember.getPkId());
        iCuMemberRegisterService.save(cuMemberRegister);

        // 会员等级
        GradeDTO gradeDTO = iGradeServiceApi.getGrade(cuMember.getPkSettleGrade()).getData();
        // 保存会员等级变动
        saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, 0);

        if (EGrade.VIP.getValue() == gradeDTO.getGradeValue()
                || EGrade.BRANCH_COMPANY.getValue() == gradeDTO.getGradeValue()) {
            // 店主、分公司级别，判断处理区域
            if (null != saOrder.getRegionProvince()
                    && null != saOrder.getRegionCity()) {
                iCuMemberRetailRegionService.mergeMemberRetailRegion(CuMemberRetailRegion.builder()
                        .pkMember(cuMember.getPkId())
                        .province(saOrder.getRegionProvince())
                        .city(saOrder.getRegionCity())
                        .county(saOrder.getRegionCounty())
                        .build());
            }
        }

        // 判断处理推荐人等级
        handleParentUpgrade(cuMember, saOrder, gradeDTO);

        this.handleRetailMemberAccount(saOrder, cuMemberAccountExt);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateRetailMember(CuMember cuMember, SaOrderExt saOrder, CuMemberAccountExt cuMemberAccountExt) {
        // 更新会员信息
        updateCuMember(cuMember);

        // 会员等级
        GradeDTO gradeDTO = iGradeServiceApi.getGrade(cuMember.getPkSettleGrade()).getData();
        if (!cuMember.getPkSettleGrade().equals(saOrder.getPkGradeOld())) {
            // 保存会员等级变动（如果旧等级和新等级相同，则不记录）
            saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, saOrder.getPkGradeOld());

            if (EGrade.VIP.getValue() == gradeDTO.getGradeValue()
                    || EGrade.BRANCH_COMPANY.getValue() == gradeDTO.getGradeValue()) {
                // 店主、分公司级别，判断处理区域
                if (null != saOrder.getRegionProvince()
                        && null != saOrder.getRegionCity()) {
                    iCuMemberRetailRegionService.mergeMemberRetailRegion(CuMemberRetailRegion.builder()
                            .pkMember(cuMember.getPkId())
                            .province(saOrder.getRegionProvince())
                            .city(saOrder.getRegionCity())
                            .county(saOrder.getRegionCounty())
                            .build());
                }
            }
        }

        // 判断处理推荐人等级
        handleParentUpgrade(cuMember, saOrder, gradeDTO);

        this.handleRetailMemberAccount(saOrder, cuMemberAccountExt);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void otherRetailMember(CuMember cuMember, SaOrderExt saOrder, CuMemberAccountExt cuMemberAccountExt, Boolean activateFlag) {
        boolean updateFlag = false;

        LambdaUpdateWrapper<CuMember> updateWrapper = new LambdaUpdateWrapper<>();
//        if (null != saOrder.getPkGrade()) {
//            updateWrapper.set(CuMember::getPkSettleGrade, saOrder.getPkGrade());
//            updateFlag = true;
//
//            cuMember.setPkSettleGrade(saOrder.getPkGrade());
//        }
        if (activateFlag) {
            updateWrapper.set(null != cuMember.getIsActivate(), CuMember::getIsActivate, cuMember.getIsActivate());
            updateWrapper.set(null != cuMember.getPayStatus(), CuMember::getPayStatus, cuMember.getPayStatus());
            updateWrapper.set(null != cuMember.getPayTime(), CuMember::getPayTime, cuMember.getPayTime());
            updateFlag = true;
        }
        if (updateFlag) {
            // 更新会员信息
            updateWrapper.eq(CuMember::getPkId, cuMember.getPkId());
            updateWrapper.set(CuMember::getModifiedTime, new Date());
            iCuMemberService.update(updateWrapper);
        }

//        if (!cuMember.getPkSettleGrade().equals(saOrder.getPkGradeOld())) {
//            // 保存会员等级变动（如果旧等级和新等级相同，则不记录）
//            saveLevelUpgrade(cuMember, EUpgradeType.BUY_UPGRADE.getValue(), saOrder, saOrder.getPkGradeOld());
//        }

        this.handleRetailMemberAccount(saOrder, cuMemberAccountExt);
    }

    /**
     * 处理新零售会员账户
     *
     * @param saOrder
     * @param cuMemberAccountExt
     */
    private void handleRetailMemberAccount(SaOrderExt saOrder, CuMemberAccountExt cuMemberAccountExt) {
        // 代表在线支付，在线支付先插入一条充值信息
        if (null == cuMemberAccountExt) {
            // 生成一条充值记录，更新会员账户信息
            cuMemberAccountExt = insertRetailMemberRecharge(saOrder);
            if (cuMemberAccountExt == null) {
                return;
            }
            insertRetailMemberTrade(saOrder, cuMemberAccountExt);
        } else {
            insertMemberTrade(saOrder, cuMemberAccountExt);
        }
    }

    /**
     * 判断推送MQ处理推荐人等级
     *
     * @param cuMember
     */
    private void handleParentUpgrade(CuMember cuMember, SaOrderExt saOrder, GradeDTO gradeDTO) {
        if (null == gradeDTO) {
            gradeDTO = iGradeServiceApi.getGrade(cuMember.getPkSettleGrade()).getData();
        }
        if (EGrade.VIP.getValue() == gradeDTO.getGradeValue()) {
            // 会员等级为 博羚店主，推荐人如果也是博羚店主，需要升级为高级店主
            CuMember parentMember = iCuMemberService.getShopkeeperMember(cuMember.getPkParent());
            if (null != parentMember) {
                // 记录升级历史
                GradeDTO upgradeDTO = iGradeServiceApi.getGradeByGradeValue(EGrade.S_VIP.getValue(), cuMember.getPkSettleCountry()).getData();
                CuMemberLevel cuMemberLevel = CuMemberLevel.builder()
                        .pkMember(parentMember.getPkId())
                        .upType(EUpgradeType.AUTO_UPGRADE.getValue())
                        .oldLevel(parentMember.getPkSettleGrade())
                        .newLevel(upgradeDTO.getPkId())
                        .upgradeTime(saOrder.getPayTime())
                        .pkOrder(saOrder.getPkId())
                        .build();
                cuMemberLevel.setPkCountry(cuMember.getPkSettleCountry());
                cuMemberLevel.setPkCreator(cuMember.getPkId());
                iCuMemberLevelService.save(cuMemberLevel);

                LambdaUpdateWrapper<CuMember> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(CuMember::getPkSettleGrade, upgradeDTO.getPkId());
                updateWrapper.eq(CuMember::getPkId, parentMember.getPkId());
                updateWrapper.set(CuMember::getPkModified, cuMember.getPkId());
                updateWrapper.set(CuMember::getModifiedTime, new Date());
                iCuMemberService.update(updateWrapper);
            }
        }
    }

    /**
     * 处理推荐人等级
     *
     * @param saOrder
     * @param currentDateTime
     */
    private void handleParentLevel(SaOrderExt saOrder, Date currentDateTime) {
        // 注册、升级订单，需要判断是否有推荐人升级的
        if (EOrderType.RETAIL_REGISTER.getValue() == saOrder.getOrderType()
                || EOrderType.RETAIL_UPGRADE.getValue() == saOrder.getOrderType()) {
            // 查询订单是否带有自动升级记录
            LambdaQueryWrapper<CuMemberLevel> memberLevelQuery = new LambdaQueryWrapper<>();
            memberLevelQuery.eq(CuMemberLevel::getPkOrder, saOrder.getPkId());
            memberLevelQuery.eq(CuMemberLevel::getUpType, EUpgradeType.AUTO_UPGRADE.getValue());
            CuMemberLevel parentLevel = iCuMemberLevelService.getOne(memberLevelQuery);
            if (null != parentLevel) {
                // 查询推荐人信息（必须是高级店主）
                CuMember parentMember = iCuMemberService.getGradeSvipMember(parentLevel.getPkMember());
                if (null != parentMember) {
                    // 推荐是高级店主，查询直推博羚店主以上订单
                    SaOrder parentOrder = iCuMemberService.listRecommendVipOrder(parentMember.getPkId(), saOrder.getOrderCode());
                    if (null != parentOrder) {
                        // 存在其它博羚店主订单，重新处理升级记录
                        CuMemberLevel parentNewLevel = BeanUtil.copyProperties(parentLevel, CuMemberLevel.class);
                        parentNewLevel.setPkId(null);
                        parentNewLevel.setPkOrder(parentOrder.getPkId());
                        parentNewLevel.setUpgradeTime(parentOrder.getPayTime());
                        parentNewLevel.setModifiedTime(parentOrder.getPayTime());
                        parentNewLevel.setPkModified(parentOrder.getPkMember());
                        iCuMemberLevelService.save(parentNewLevel);
                    } else {
                        // 不存在其它博羚店主订单，会员需要降级处理
                        LambdaUpdateWrapper<CuMember> parentMemberUpdate = new LambdaUpdateWrapper<>();
                        parentMemberUpdate.eq(CuMember::getPkId, parentMember.getPkId());
                        parentMemberUpdate.set(CuMember::getPkSettleGrade, parentLevel.getOldLevel());
                        parentMemberUpdate.set(CuMember::getModifiedTime, currentDateTime);
                        iCuMemberService.update(parentMemberUpdate);
                    }
                    // 删除原来升级记录
                    LambdaUpdateWrapper<CuMemberLevel> updateMemberLevel = new LambdaUpdateWrapper<>();
                    updateMemberLevel.eq(CuMemberLevel::getPkId, parentLevel.getPkId());
                    updateMemberLevel.set(CuMemberLevel::getDelFlag, EDelFlag.DELETE.getValue());
                    updateMemberLevel.set(CuMemberLevel::getModifiedTime, currentDateTime);
                    iCuMemberLevelService.update(updateMemberLevel);
                }
            }
        }

    }


    /**
     * 在线支付退款
     *
     * @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());
                }
            }
        }
    }

}
