
package com.tmerclub.cloud.supplier.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import com.tmerclub.cloud.api.multishop.bo.OrderChangeShopWalletAmountBO;
import com.tmerclub.cloud.api.payment.constant.PaySysType;
import com.tmerclub.cloud.api.payment.vo.SplitRuleVO;
import com.tmerclub.cloud.api.supplier.bo.SupplierWalletBO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.order.vo.OrderSimpleAmountInfoBO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.supplier.constant.SupplierWalletAmountType;
import com.tmerclub.cloud.supplier.constant.SupplierWalletChangeReason;
import com.tmerclub.cloud.supplier.dto.SupplierWalletLogSearchDTO;
import com.tmerclub.cloud.supplier.mapper.SupplierWalletMapper;
import com.tmerclub.cloud.supplier.mongo.MongoSupplierWalletLogBO;
import com.tmerclub.cloud.supplier.service.SupplierAllinpayService;
import com.tmerclub.cloud.supplier.service.SupplierWalletLogService;
import com.tmerclub.cloud.supplier.service.SupplierWalletService;
import com.tmerclub.cloud.supplier.vo.SupplierWalletVO;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 商家钱包信息
 *
 * @author tmerclub
 * @date 2021-01-07 16:41:03
 */
@Service
public class SupplierWalletServiceImpl implements SupplierWalletService {

    @Autowired
    private SupplierWalletMapper supplierWalletMapper;
    @Autowired
    private SupplierWalletLogService supplierWalletLogService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private SegmentManager segmentManager;
    @Autowired
    private RocketMQTemplate addSupplierWalletLogTemplate;
    @Autowired
    private SupplierAllinpayService supplierAllinpayService;


    private static final Logger logger = LoggerFactory.getLogger(SupplierWalletServiceImpl.class);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAmountByOrder(List<OrderSimpleAmountInfoBO> orderSimpleAmountInfos) {

        // 进行分账，添加一个分账记录表，因为每一个订单进行分完帐后要进行退款，那么退款的时候也应该按照下单的时候的分账比例进行原路返回
        // 获取当前分账的比例

        List<MongoSupplierWalletLogBO> supplierWalletLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (OrderSimpleAmountInfoBO orderSimpleAmountInfo : orderSimpleAmountInfos) {
            // 商家之所以会从一笔订单拿到钱，是因为订单支付成功
            long count = supplierWalletLogService.countInAmountByOrderId(orderSimpleAmountInfo.getOrderId(), SupplierWalletChangeReason.PAY.value());
            // 幂等
            if (count > 0) {
                return;
            }
            // 供应商收入金额为 = 采购金额 + 运费 - 平台佣金，在之前已经处理，这里直接拿
            Long changeAmount = orderSimpleAmountInfo.getPurchaseAmount();

            // 商家添加未结算金额(因为添加了唯一索引，所以是不用怕多次加钱)
            supplierWalletMapper.addUnsettledAmount(orderSimpleAmountInfo.getSupplierId(), changeAmount, orderSimpleAmountInfo.getPaySysType());
            MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();

            supplierWalletLog.setWalletLogId(orderSimpleAmountInfo.getWalletLogId());
            supplierWalletLog.setOrderId(orderSimpleAmountInfo.getOrderId());
            supplierWalletLog.setPaySysType(Objects.isNull(orderSimpleAmountInfo.getPaySysType()) ? 0 : orderSimpleAmountInfo.getPaySysType());
            supplierWalletLog.setReason(SupplierWalletChangeReason.PAY.value());
            supplierWalletLog.setSupplierId(orderSimpleAmountInfo.getSupplierId());
            supplierWalletLog.setIoType(1);
            supplierWalletLog.setCreateTime(new Date());
            supplierWalletLog.setUpdateTime(new Date());
            supplierWalletLog.setChangeAmount(changeAmount);
            supplierWalletLog.setFreightAmount(orderSimpleAmountInfo.getFreightAmount() + Math.abs(orderSimpleAmountInfo.getFreeFreightAmount()));
            supplierWalletLog.setAmountType(SupplierWalletAmountType.UNSETTLED_AMOUNT.value());
            supplierWalletLog.setUserAmount(orderSimpleAmountInfo.getActualTotal());
            supplierWalletLog.setDistributionAmount(orderSimpleAmountInfo.getDistributionAmount());
            supplierWalletLog.setPlatformAmount(orderSimpleAmountInfo.getPlatformAmount());
            supplierWalletLog.setPlatformCommission(orderSimpleAmountInfo.getPurchasePlatformCommission());
            logger.info("供应商添加待结算金额完成，增加结算日志{}", supplierWalletLog);
            // 添加日志
            supplierWalletLogList.add(supplierWalletLog);
        }
        logger.info("供应商添加待结算金额完成，增加结算日志{}条", supplierWalletLogList.size());
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(supplierWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAmountBySettledOrder(Long orderId) {

        // 商家之所以会从一笔订单拿到钱，是因为确认收货 or 订单退款时有部分不退
        long count = supplierWalletLogService.countInAmountByOrderId(orderId, SupplierWalletChangeReason.SETTLED.value());
        // 幂等
        if (count > 0) {
            return;
        }

        SupplierWalletLogSearchDTO supplierWalletLogSearchDTO = new SupplierWalletLogSearchDTO();
        supplierWalletLogSearchDTO.setOrderId(orderId);
        List<MongoSupplierWalletLogBO> supplierWalletLogs = supplierWalletLogService.listByParam(supplierWalletLogSearchDTO);
        if (CollectionUtil.isEmpty(supplierWalletLogs)) {
            return;
        }
        // 商家需要结算的钱
        MongoSupplierWalletLogBO supplierPayLog = null;

        MongoSupplierWalletLogBO supplierRefundLog = new MongoSupplierWalletLogBO();
        supplierRefundLog.setChangeAmount(0L);
        supplierRefundLog.setPlatformAmount(0L);
        supplierRefundLog.setPlatformCommission(0L);
        supplierRefundLog.setUserAmount(0L);
        supplierRefundLog.setDistributionAmount(0L);
        for (MongoSupplierWalletLogBO supplierWalletLog : supplierWalletLogs) {
            // 下单
            MongoSupplierWalletLogBO payLog = polymerizationSupplierWalletLog(supplierRefundLog, supplierWalletLog);
            if (payLog != null) {
                supplierPayLog = payLog;
            }
        }
        // 非积分订单需要保存供应商结算记录
        if (Objects.nonNull(supplierPayLog)) {
            // 保存供应商结算记录
            saveSettledLog(supplierPayLog, supplierRefundLog);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SplitRuleVO getSupplierSettledInfoByOrderId(Long orderId) {

        // 商家之所以会从一笔订单拿到钱，是因为确认收货 or 订单退款时有部分不退
        long count = supplierWalletLogService.countInAmountByOrderId(orderId, SupplierWalletChangeReason.SETTLED.value());
        // 幂等
        if (count > 0) {
            return null;
        }

        SupplierWalletLogSearchDTO supplierWalletLogSearchDTO = new SupplierWalletLogSearchDTO();
        supplierWalletLogSearchDTO.setOrderId(orderId);
        List<MongoSupplierWalletLogBO> supplierWalletLogs = supplierWalletLogService.listByParam(supplierWalletLogSearchDTO);
        if (CollectionUtil.isEmpty(supplierWalletLogs)) {
            return null;
        }
        // 商家需要结算的钱
        MongoSupplierWalletLogBO supplierPayLog = null;

        MongoSupplierWalletLogBO supplierRefundLog = new MongoSupplierWalletLogBO();
        supplierRefundLog.setUserAmount(0L);
        supplierRefundLog.setDistributionAmount(0L);
        supplierRefundLog.setPlatformAmount(0L);
        supplierRefundLog.setPlatformCommission(0L);
        for (MongoSupplierWalletLogBO supplierWalletLog : supplierWalletLogs) {
            // 下单
            MongoSupplierWalletLogBO payLog = polymerizationSupplierWalletLog(supplierRefundLog, supplierWalletLog);
            if (payLog != null) {
                supplierPayLog = payLog;
            }
        }
        // 非积分订单需要保存供应商结算记录
        if (Objects.nonNull(supplierPayLog)) {
            Long changeAmount = supplierPayLog.getChangeAmount();
            SplitRuleVO splitRuleVO = new SplitRuleVO();
            splitRuleVO.setAmount(changeAmount - supplierRefundLog.getChangeAmount());
            splitRuleVO.setFee(supplierPayLog.getPlatformCommission() - supplierRefundLog.getPlatformCommission());
            splitRuleVO.setBizUserId(supplierPayLog.getSupplierId().toString());
            splitRuleVO.setOrderId(supplierPayLog.getOrderId());
            return splitRuleVO;
        }
        return null;
    }

    /**
     * 聚合订单支付退款导致商家金额变更的记录
     *
     * @param refundWalletLog
     * @param supplierWalletLog
     * @return
     */
    private MongoSupplierWalletLogBO polymerizationSupplierWalletLog(MongoSupplierWalletLogBO refundWalletLog, MongoSupplierWalletLogBO supplierWalletLog) {
        if (Objects.equals(SupplierWalletChangeReason.PAY.value(), supplierWalletLog.getReason())) {
            return supplierWalletLog;
        }
        // 退款
        else if (Objects.equals(SupplierWalletChangeReason.ORDER_REFUND.value(), supplierWalletLog.getReason())) {
            refundWalletLog.setPaySysType(Objects.isNull(supplierWalletLog.getPaySysType()) ? 0 : supplierWalletLog.getPaySysType());
            refundWalletLog.setUserAmount(refundWalletLog.getUserAmount() + supplierWalletLog.getUserAmount());
            refundWalletLog.setDistributionAmount(0L);
            refundWalletLog.setPlatformAmount(0L);
            refundWalletLog.setPlatformCommission(refundWalletLog.getPlatformCommission() + supplierWalletLog.getPlatformCommission());
            // 如果因为退款收入，实际上是减少了退款的钱
            Long changeAmount = (supplierWalletLog.getIoType() == 1) ? -supplierWalletLog.getChangeAmount() : supplierWalletLog.getChangeAmount();
            refundWalletLog.setChangeAmount(refundWalletLog.getChangeAmount() + changeAmount);
        }
        return null;
    }


    private void saveSettledLog(MongoSupplierWalletLogBO supplierPayLog, MongoSupplierWalletLogBO supplierRefundLog) {
        Long changeAmount = supplierPayLog.getChangeAmount();
        MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
        supplierWalletLog.setOrderId(supplierPayLog.getOrderId());
        Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
        supplierWalletLog.setWalletLogId(walletLogId);
        supplierWalletLog.setReason(SupplierWalletChangeReason.SETTLED.value());
        supplierWalletLog.setSupplierId(supplierPayLog.getSupplierId());
        supplierWalletLog.setPaySysType(Objects.isNull(supplierPayLog.getPaySysType()) ? 0 : supplierPayLog.getPaySysType());
        supplierWalletLog.setCreateTime(new Date());
        supplierWalletLog.setUpdateTime(new Date());
        int ioType = supplierPayLog.getIoType();
        if (changeAmount - supplierRefundLog.getChangeAmount() < 0) {
            ioType = 0;
        }
        // 如果之前未结算为负收入或者当前金额小于退款金额，则已结算的收入是负收入
        if (Objects.equals(ioType, 0)) {
            changeAmount = -changeAmount - supplierRefundLog.getChangeAmount();
        } else {
            changeAmount = changeAmount - supplierRefundLog.getChangeAmount();
        }
        supplierWalletLog.setIoType(ioType);
        supplierWalletLog.setAmountType(SupplierWalletAmountType.SETTLED_AMOUNT.value());
        supplierWalletLog.setChangeAmount(Math.abs(changeAmount));
        supplierWalletLog.setUserAmount(supplierPayLog.getUserAmount() - supplierRefundLog.getUserAmount());
        supplierWalletLog.setDistributionAmount(0L);
        supplierWalletLog.setPlatformAmount(0L);
        supplierWalletLog.setPlatformCommission(supplierPayLog.getPlatformCommission() - supplierRefundLog.getPlatformCommission());

        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(supplierWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 供应商结算，分成 1.减少待结算金额 和 2.增加结算金额以及总结算金额 两步操作，因为添加结算金额需要上锁操作，细粒化
        // 1.减少待结算金额
        boolean subUnsettledAmountSuccess = subUnsettledAmount(supplierWalletLog.getSupplierId(), supplierPayLog.getOrderId(), changeAmount, supplierPayLog.getPaySysType());
        if (!subUnsettledAmountSuccess) {
            throw new LuckException("您的待结算金额不足，无法进行结算");
        }

        // 2.增加结算金额以及总结算金额
        boolean addSettledAmountSuccess = supplierWalletMapper.addSettledAmount(supplierWalletLog.getSupplierId(), changeAmount, supplierPayLog.getPaySysType(), true) > 0;
        if (!addSettledAmountSuccess) {
            throw new LuckException("结算失败");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundSupplierAmountByRefund(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = supplierWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), SupplierWalletChangeReason.ORDER_REFUND.value());
        // 幂等
        if (count > 0) {
            return;
        }
        // 供应商发货订单，未发货单项退款，且是最后一个订单的运费处理-- 赋值位置：com.tmerclub.cloud.order.controller.supplier.OrderRefundController.agreeRefund
        if (Objects.nonNull(orderChangeShopWalletAmountBO.getSupplierFreightAmount()) && BooleanUtil.isTrue(orderChangeShopWalletAmountBO.getLastOrder())) {
            // 添加供应商发货的订单的运费，这个运费与商家和平台的运费处理规则不一致
            // 供应商发货的订单单项退款包含的运费为商品原本的运费，不受平台和商家运费减免金额的影响（商家不能修改供应商发货订单的运费，平台减免金额是给商家的，跟供应商没有关系）
            orderChangeShopWalletAmountBO.setFreightAmount(orderChangeShopWalletAmountBO.getSupplierFreightAmount());
        }
        // 供应商改变金额 = 供应商改变金额 + 供应商商品运费 - 平台供应商佣金改变量
        Long supplierRealRefundAmount = orderChangeShopWalletAmountBO.getChangePurchaseAmount() + orderChangeShopWalletAmountBO.getFreightAmount() - orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission();
        MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
        supplierWalletLog.setWalletLogId(orderChangeShopWalletAmountBO.getWalletLogIds().remove(0));
        supplierWalletLog.setRefundId(orderChangeShopWalletAmountBO.getRefundId());
        supplierWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        supplierWalletLog.setPaySysType(Objects.isNull(orderChangeShopWalletAmountBO.getPaySysType()) ? 0 : orderChangeShopWalletAmountBO.getPaySysType());
        supplierWalletLog.setReason(SupplierWalletChangeReason.ORDER_REFUND.value());
        supplierWalletLog.setSupplierId(orderChangeShopWalletAmountBO.getSupplierId());
        supplierWalletLog.setCreateTime(new Date());
        supplierWalletLog.setUpdateTime(new Date());
        supplierWalletLog.setFreightAmount(orderChangeShopWalletAmountBO.getFreightAmount());

        // 用户申请的退款金额
        supplierWalletLog.setUserAmount(orderChangeShopWalletAmountBO.getRefundAmount());
        // 回退的分销金额
        supplierWalletLog.setDistributionAmount(0L);
        // 回退的平台补贴
        supplierWalletLog.setPlatformAmount(0L);
        // 回退的平台佣金
        supplierWalletLog.setPlatformCommission(orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission());
        // 商家改变金额
        supplierWalletLog.setChangeAmount(supplierRealRefundAmount);
        // 扣除
        supplierWalletLog.setIoType(0);

        // 1. 订单未确认收货则扣未结算金额
        // 2. 商家撤销拼团活动时失效拼团时，将待成团的队伍进行退款

        // 减少未结算金额
        boolean isSuccess = subUnsettledAmount(orderChangeShopWalletAmountBO.getSupplierId(), orderChangeShopWalletAmountBO.getOrderId(), supplierRealRefundAmount, orderChangeShopWalletAmountBO.getPaySysType());
        if (!isSuccess) {
            throw new LuckException("您的待结算金额不足，无法进行退款");
        }

        supplierWalletLog.setAmountType(SupplierWalletAmountType.UNSETTLED_AMOUNT.value());

        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(supplierWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementSupplierAmountByRefund(OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO) {

        // 看看这个订单有没有锁定过
        long count = supplierWalletLogService.countOutAmountByRefundId(orderChangeShopWalletAmountBO.getRefundId(), SupplierWalletChangeReason.SETTLED.value());
        // 幂等
        if (count > 0) {
            return;
        }
        // 供应商收入，供应商收入 = 供应商剩余待结算金额 + 运费 - 已退金额 - 供应商剩余佣金
        Long supplierAmount = orderChangeShopWalletAmountBO.getChangePurchaseAmount() + orderChangeShopWalletAmountBO.getFreightAmount() - orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission();
        if (Objects.equals(supplierAmount, 0L) || Objects.equals(orderChangeShopWalletAmountBO.getSupplierId(), 0L)) {
            return;
        }
        // 平台佣金改变量
        Long changePlatformCommission = orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission();
        MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
        Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
        supplierWalletLog.setWalletLogId(walletLogId);
        supplierWalletLog.setOrderId(orderChangeShopWalletAmountBO.getOrderId());
        supplierWalletLog.setReason(SupplierWalletChangeReason.SETTLED.value());
        supplierWalletLog.setPaySysType(Objects.isNull(orderChangeShopWalletAmountBO.getPaySysType()) ? 0 : orderChangeShopWalletAmountBO.getPaySysType());
        supplierWalletLog.setSupplierId(orderChangeShopWalletAmountBO.getSupplierId());
        supplierWalletLog.setCreateTime(new Date());
        supplierWalletLog.setUpdateTime(new Date());

        // 结算的金额
        supplierWalletLog.setUserAmount(supplierAmount);
        // 回退的分销金额
        supplierWalletLog.setDistributionAmount(0L);
        // 回退的平台补贴
        supplierWalletLog.setPlatformAmount(0L);
        // 回退的平台佣金
        supplierWalletLog.setPlatformCommission(changePlatformCommission);
        // 商家改变金额
        supplierWalletLog.setChangeAmount(supplierAmount);
        // 增加
        supplierWalletLog.setIoType(1);
        // 1. 订单部分退款导致订单关闭 商家结算操作
        // 供应商结算操作同订单结算一样，分成两步
        //      1.减少待结算金额，订单在哪个分片加的待结算金额就从哪里减掉
        boolean subUnsettledAmountSuccess = subUnsettledAmount(supplierWalletLog.getSupplierId(), orderChangeShopWalletAmountBO.getOrderId(), supplierAmount, orderChangeShopWalletAmountBO.getPaySysType());
        if (!subUnsettledAmountSuccess) {
            throw new LuckException("您的待结算金额不足，无法进行退款");
        }

        //      2.增加结算金额以及总结算金额，这里可以随机加在某个分片中
        boolean addSettledAmountSuccess = supplierWalletMapper.addSettledAmount(supplierWalletLog.getSupplierId(), supplierAmount, orderChangeShopWalletAmountBO.getPaySysType(), true) > 0;
        if (!addSettledAmountSuccess) {
            throw new LuckException("供应商结算失败，无法进行退款");
        }

        supplierWalletLog.setAmountType(SupplierWalletAmountType.SETTLED_AMOUNT.value());
        // 添加日志
        // 用mq保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(Collections.singleton(supplierWalletLog))).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateByDistributionAmount(List<SupplierWalletBO> message) {
        if (CollUtil.isEmpty(message)) {
            return;
        }
        List<MongoSupplierWalletLogBO> supplierWalletLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (SupplierWalletBO supplierWalletBO : message) {
            Long supplierId = supplierWalletBO.getSupplierId();
            Long orderId = supplierWalletBO.getOrderId();
            // 商家待结算改变金额，从分销过来的待结算金额是个负数，用来减少待结算金额
            Long unsettledAmount = supplierWalletBO.getUnsettledAmount();
            // 幂等处理
            long count = supplierWalletLogService.countInAmountByOrderId(orderId, SupplierWalletChangeReason.DISTRIBUTION_AMOUNT.value());
            if (count > 0) {
                continue;
            }

            // 修改支付成功结算的供应商钱包日志
            SupplierWalletLogSearchDTO supplierWalletLogQuery = new SupplierWalletLogSearchDTO();
            supplierWalletLogQuery.setOrderId(orderId);
            supplierWalletLogQuery.setReason(SupplierWalletChangeReason.PAY.value());
            supplierWalletLogQuery.setSupplierId(supplierId);
            supplierWalletLogQuery.setIoType(1);
            supplierWalletLogQuery.setAmountType(SupplierWalletAmountType.UNSETTLED_AMOUNT.value());
            // 必须保存供应商分账完成，有该条分账记录后，才可以分销
            MongoSupplierWalletLogBO supplierWalletLogUpdate = supplierWalletLogService.listByParam(supplierWalletLogQuery).get(0);
            if (Objects.isNull(supplierWalletLogUpdate)) {
                throw new LuckException("未找到支付成功结算的供应商钱包日志");
            }
            supplierWalletLogUpdate.setDistributionAmount(Math.abs(unsettledAmount));

            // 修改钱包日志分销金额
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(supplierWalletLogUpdate.getWalletLogId()));
            Update update = new Update();
            update.set("distributionAmount", supplierWalletLogUpdate.getDistributionAmount());
            update.set("updateTime", new Date());
            mongoTemplate.updateFirst(query, update, MongoSupplierWalletLogBO.class);

            // 更新钱包未结算金额
            supplierWalletMapper.addUnsettledAmount(supplierId, unsettledAmount, supplierWalletLogUpdate.getPaySysType());

            // 分销减少供应商钱包日志，只是为了添加一条日志，保证幂等
            MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
            Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
            supplierWalletLog.setWalletLogId(walletLogId);
            supplierWalletLog.setSupplierId(supplierId);
            supplierWalletLog.setOrderId(orderId);
            supplierWalletLog.setCreateTime(new Date());
            supplierWalletLog.setUpdateTime(new Date());
            supplierWalletLog.setIoType(unsettledAmount >= 0 ? 1 : 0);
            supplierWalletLog.setPaySysType(Objects.isNull(supplierWalletLogUpdate.getPaySysType()) ? 0 : supplierWalletLogUpdate.getPaySysType());
            supplierWalletLog.setAmountType(SupplierWalletAmountType.UNSETTLED_AMOUNT.value());
            supplierWalletLog.setReason(SupplierWalletChangeReason.DISTRIBUTION_AMOUNT.value());
            supplierWalletLog.setDistributionAmount(Math.abs(unsettledAmount));
            supplierWalletLog.setChangeAmount(Math.abs(unsettledAmount));
            supplierWalletLog.setUserAmount(supplierWalletLogUpdate.getUserAmount());
            supplierWalletLogList.add(supplierWalletLog);
        }
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(supplierWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public PageVO<SupplierWalletVO> pageSupplierWalletByTime(PageDTO pageDTO, SupplierWalletLogSearchDTO supplierWalletLogSearchDTO) {
        Integer paySysType = supplierAllinpayService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        PageVO<SupplierWalletVO> supplierWalletPage;
        if (Objects.nonNull(supplierWalletLogSearchDTO.getStartTime()) && Objects.nonNull(supplierWalletLogSearchDTO.getEndTime())) {
            supplierWalletPage = supplierWalletLogService.pageSupplierWalletByTime(pageDTO, supplierWalletLogSearchDTO);
        } else {
            supplierWalletPage = PageUtil.doPage(pageDTO, () -> supplierWalletMapper.listAllSupplierWallet(supplierWalletLogSearchDTO, paySysType));
        }
        return supplierWalletPage;
    }

    @Override
    public SupplierWalletVO getBySupplierId(Long supplierId) {
        Integer paySysType = supplierAllinpayService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        return supplierWalletMapper.getBySupplierId(supplierId, paySysType);
    }

    @Override
    public SupplierWalletVO getAllSupplier(SupplierWalletLogSearchDTO supplierWalletLogSearchDTO) {
        Integer paySysType = supplierAllinpayService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        SupplierWalletVO supplierWallet;
        if (Objects.nonNull(supplierWalletLogSearchDTO.getStartTime()) && Objects.nonNull(supplierWalletLogSearchDTO.getEndTime())) {
            supplierWallet = supplierWalletLogService.getSupplierWalletByTime(supplierWalletLogSearchDTO);
        } else {
            supplierWallet = supplierWalletMapper.getAllSupplier(supplierWalletLogSearchDTO, paySysType);
        }
        return supplierWallet;
    }

    /**
     * 退款减少待结算金额
     */
    private boolean subUnsettledAmount(Long supplierId, Long orderId, Long changeAmount, Integer paySysType) {
        if (Objects.equals(changeAmount, 0L)) {
            return true;
        }
        if (Objects.isNull(paySysType)) {
            paySysType = 0;
        }
        return supplierWalletMapper.subUnsettledAmount(supplierId, changeAmount, paySysType) > 0;
    }

    /**
     * 增加结算金额
     */
    private boolean addSettledAmount(Long shopId, Long changeAmount, Integer paySysType) {
        if (Objects.equals(changeAmount, 0L)) {
            return true;
        }
        if (Objects.isNull(paySysType)) {
            paySysType = 0;
        }
        return supplierWalletMapper.addSettledAmount(shopId, changeAmount, paySysType, true) > 0;
    }
}
