package com.yn.bftl.thirdparty.modules.business.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yn.bftl.common.common.exception.YnceError;
import com.yn.bftl.common.common.util.ByxRouteUtil;
import com.yn.bftl.common.common.util.RouteUtil;
import com.yn.bftl.common.modules.account.entity.Payment;
import com.yn.bftl.common.modules.account.enums.AccountChangeType;
import com.yn.bftl.common.modules.account.enums.ChangeDirection;
import com.yn.bftl.common.modules.account.enums.PaymentType;
import com.yn.bftl.common.modules.account.vo.BalanceAcctsVO;
import com.yn.bftl.common.modules.company.entity.Brand;
import com.yn.bftl.common.modules.company.entity.Company;
import com.yn.bftl.common.modules.order.entity.*;
import com.yn.bftl.common.modules.order.enums.*;
import com.yn.bftl.common.modules.relation.entity.BusinessRelations;
import com.yn.bftl.common.modules.subaccount.entity.*;
import com.yn.bftl.common.modules.subaccount.enums.StatementState;
import com.yn.bftl.common.modules.subaccount.enums.StatementType;
import com.yn.bftl.common.modules.subaccount.enums.SubaccountState;
import com.yn.bftl.common.modules.subaccount.enums.SubaccountType;
import com.yn.bftl.thirdparty.common.exception.YnceErrorException;
import com.yn.bftl.thirdparty.common.repository.*;
import com.yn.bftl.thirdparty.common.service.ByxTradeWayService;
import com.yn.bftl.thirdparty.common.util.DateTimeUtils;
import com.yn.bftl.thirdparty.common.util.SequenceUtil;
import com.yn.bftl.thirdparty.modules.business.abstracts.AbstractBusinessService;
import com.yn.bftl.thirdparty.modules.business.dto.AccountChangeCreateDTO;
import com.yn.bftl.thirdparty.modules.business.dto.CreatePaymentDTO;
import com.yn.bftl.thirdparty.modules.business.dto.OrderRefundItemDTO;
import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsPaymentRepository;
import com.yn.bftl.thirdparty.modules.business.repository.ChinaumsRefundRepository;
import com.yn.bftl.thirdparty.modules.business.service.AccountService;
import com.yn.bftl.thirdparty.modules.business.service.PaymentService;
import com.yn.bftl.thirdparty.modules.business.service.SubaccountService;
import com.yn.bftl.thirdparty.modules.chinaums.dto.BrandAuthFeeDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxChinaumsGuaranteePayConfirmsDetailDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsAllocationsDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayConfirmsDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsGuaranteePayExtraDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.chinaums.ChinaumsTransferParamsDTO;
import com.yn.bftl.thirdparty.modules.chinaums.repository.ChinaumsAuthInfoRepository;
import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService;
import com.yn.bftl.thirdparty.modules.chinaums.util.ByxChinaumsUtil;
import com.yn.bftl.thirdparty.modules.chinaums.util.ChinaumsUtil;
import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsAllocationsVO;
import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsGuaranteePayConfirmsVO;
import com.yn.bftl.thirdparty.modules.chinaums.vo.chinaums.ChinaumsTransferResultsVO;
import com.yn.bftl.thirdparty.modules.unionpay.enums.UnionpayAppOrderType;
import com.yn.bftl.thirdparty.modules.unionpay.repository.OrderFeeRatioRepository;
import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.ProfitSharingCallbackVO;
import com.yn.bftl.thirdparty.modules.unionpay.vo.callback.SettlementCallbackVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分账服务实现
 *
 * @author huabiao
 * @create 2022/9/14  17:25
 **/
@Service
public class SubaccountServiceImpl extends AbstractBusinessService implements SubaccountService {

    private static final Log log = LogFactory.getLog(SubaccountServiceImpl.class);

    @Resource
    private AfterSaleRepository afterSaleRepository;
    @Resource
    private OrderRepository orderRepository;
    @Resource
    private SubaccountRepository subaccountRepository;
    @Resource
    private StatementRepository statementRepository;
    @Resource
    private SequenceUtil sequenceUtil;
    @Resource
    private PaymentRepository paymentRepository;
    @Resource
    private ShippingRepository shippingRepository;
    @Resource
    private TemporaryStatementRepository temporaryStatementRepository;
    @Resource
    private OrderFeeRatioRepository orderFeeRatioRepository;
    @Resource
    private StatementLineRepository statementLineRepository;
    @Resource
    private WalletService walletService;
    @Resource
    private ChinaumsUtil chinaumsUtil;
    @Resource
    private OrderItemRepository orderItemRepository;
    @Resource
    private ChinaumsPaymentRepository chinaumsPaymentRepository;
    @Resource
    private CompanyRepository companyRepository;
    @Resource
    private AccountService accountService;
    @Resource
    private ChinaumsRefundRepository chinaumsRefundRepository;
    @Resource
    private BrandRepository brandRepository;
    @Resource
    private RefundRepository refundRepository;
    @Resource
    private PaymentService paymentService;

    @Resource
    private ChinaumsAuthInfoRepository chinaumsAuthInfoRepository;

    @Resource
    private ByxTradeWayService byxTradeWayService;

    @Resource
    private ByxChinaumsUtil byxChinaumsUtil;

    @Resource
    private BusinessRelationsRepository businessRelationsRepository;

    @Override
    public void generateTemporaryStatement(Long orderId) {
        log.info("开始生成临时结算单");
        // 查询订单
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order == null) {
            writeCommissionLog("[临时服务费][普通订单]订单ID：" + orderId + "，未查到");
            return;
        }
        if (CollectionUtils.isEmpty(order.getReceipt())) {
            writeCommissionLog(String.format("[临时服务费][普通订单][%s]，收款单不存在", order.getSn()));
            return;
        }
        // 授信支付
        if (PaymentMethod.CREDIT_PAY.equals(order.getReceipt().get(0).getPaymentMethod())) {
            // 判断是否已支付
            if (PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) {
                writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单未付款", order.getSn()));
            }
        }
        // 其他支付方式
        else {
            // 查看付款单是否支付
            Payment payment = paymentRepository.findFirstByOrderIdAndPayStatusOrderByIdDesc(orderId.toString(), PayStatus.SUCC);
            if (payment == null) {
                writeCommissionLog(String.format("[临时服务费][普通订单][%s]，支付单未付款", order.getSn()));
                return;
            }
        }

        // 判断订单是否已创建服务单据
        TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersId(orderId);
        if (temporaryStatement != null) {
            writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单已创建过临时服务费单据", order.getSn()));
            return;
        }
        List<TemporaryStatement> temporaryStatementList = new ArrayList<>();
        // 总临时结算单数量
        Integer totalNumber = 0;
        // 生成货款临时结算单
        log.info("======================order.getGoodsPayment():" + order.getGoodsPayment());
        if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) {
            temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.GOODS_COST, order, order.getSellerCompany()));
            totalNumber++;
        }
        log.info("======================order.getBrandCost():" + order.getBrandCost());
        // 生成品牌临时结算单
        if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) {
            temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.BRAND_FEE, order, order.getBrandCompany()));
            totalNumber++;
        }
        log.info("======================order.getDeviseCost():" + order.getDeviseCost());
        // 生成策划临时结算单
        if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) {
            temporaryStatementList.add(generateTemporaryStatementByType(SubaccountType.DEVISE_FEE, order, order.getDeviseCompany()));
            totalNumber++;
        }
        if (totalNumber != temporaryStatementList.size()) {
            return;
        }
        log.info("temporaryStatementList:" + JSON.toJSONString(temporaryStatementList));
        temporaryStatementRepository.saveAll(temporaryStatementList);
        writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单临时服务费单据已创建完成", order.getSn()));
        log.info("生成临时结算单结束");
    }

    /**
     * 临时结算单-根据分账类型生成
     *
     * @param order:订单
     * @param subaccountType:分账类型
     * @param company:分账企业
     * @return 临时结算单
     * @author huabiao
     * @create 2022/9/19  11:24
     */
    private TemporaryStatement generateTemporaryStatementByType(SubaccountType subaccountType, Order order, Company company) {
        TemporaryStatement temporaryStatement = new TemporaryStatement();
        temporaryStatement.setOrderNo(sequenceUtil.getNextSequenceNumber("TFEE"));
        temporaryStatement.setOrders(order);
        temporaryStatement.setCompany(order.getSellerCompany());
        temporaryStatement.setSubaccountType(subaccountType);
        // 通过商品明细计算对应单据
        List<TemporaryStatementLine> temporaryStatementLineList = new ArrayList<>();
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 计算总结算金额
        BigDecimal statementAmount = BigDecimal.ZERO;
        for (OrderItem orderItem : order.getOrderItems()) {
            TemporaryStatementLine temporaryStatementLine = new TemporaryStatementLine();
            if (subaccountType.equals(SubaccountType.GOODS_COST)) {
                temporaryStatementLine.setStatementAmount(orderItem.getGoodsPayment());
                temporaryStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio()));
                temporaryStatementLine.setCompany(order.getSellerCompany());
            } else if (subaccountType.equals(SubaccountType.BRAND_FEE)) {
                temporaryStatementLine.setStatementAmount(orderItem.getBrandCost());
                temporaryStatementLine.setCompany(order.getBrandCompany());
                temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null);
            } else if (subaccountType.equals(SubaccountType.DEVISE_FEE)) {
                temporaryStatementLine.setStatementAmount(orderItem.getDeviseCost());
                temporaryStatementLine.setCompany(order.getDeviseCompany());
                temporaryStatementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null);
            }
            temporaryStatementLine.setTemporaryStatement(temporaryStatement);
            temporaryStatementLine.setOrderItem(orderItem);
            temporaryStatementLineList.add(temporaryStatementLine);
            statementAmount = statementAmount.add(temporaryStatementLine.getStatementAmount());

        }
        temporaryStatement.setTemporaryStatementLines(temporaryStatementLineList);
        temporaryStatement.setStatementAmount(statementAmount);
        temporaryStatement.setCompany(company);
        // 判断订单项结算金额和订单结算金额是否一致
        if (subaccountType.equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(statementAmount) != 0) {
            log.error(String.format("[临时服务费][普通订单][%s]，订单的货款与订单行不一致", order.getSn()));
            writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单的货款与订单行不一致", order.getSn()));
            return null;
        } else if (subaccountType.equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(statementAmount) != 0) {
            log.error(String.format("[临时服务费][普通订单][%s]，订单的品牌费与订单行不一致", order.getSn()));
            writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单的品牌费与订单行不一致", order.getSn()));
            return null;
        } else if (subaccountType.equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(statementAmount) != 0) {
            log.error(String.format("[临时服务费][普通订单][%s]，订单的策划费与订单行不一致", order.getSn()));
            writeCommissionLog(String.format("[临时服务费][普通订单][%s]，订单的策划费与订单行不一致", order.getSn()));
            return null;
        }
        return temporaryStatement;
    }

    @Override
    public void generateStatementByOrder(Long orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order == null) {
            writeCommissionLog("[服务费][普通订单]订单ID：" + orderId + "，订单不存在");
        }
        // 判断是否已存在对应的结算单
        if (statementRepository.existsByOrdersIdAndStatementType(orderId, StatementType.NORMALORDER)) {
            writeCommissionLog(String.format("[服务费][普通订单][%s]，订单已创建过服务费单据", order.getSn()));
        }
        // 临时结算单
        List<TemporaryStatement> temporaryStatementList = new ArrayList<>();
        // 结算单
        List<Statement> statementList = new ArrayList<>();

        // 生成货款结算单
        if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) {
            // 获取货款临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的货款临时服务费单据不存在", order.getSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true));
            temporaryStatement.setIsStatement(true);
            temporaryStatementList.add(temporaryStatement);
        }
        // 生成品牌结算单
        if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) {
            // 获取品牌临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的品牌临时服务费单据不存在", order.getSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true));
            temporaryStatement.setIsStatement(true);
            temporaryStatementList.add(temporaryStatement);
        }
        // 生成策划结算单
        if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) {
            // 获取品牌临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的策划临时服务费单据不存在", order.getSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, null, order, true));
            temporaryStatement.setIsStatement(true);
            temporaryStatementList.add(temporaryStatement);
        }
        if (temporaryStatementList.size() != statementList.size()) {
            return;
        }
        statementRepository.saveAll(statementList);
        // 修改临时结算单状态
        temporaryStatementRepository.saveAll(temporaryStatementList);
        writeCommissionLog(String.format("[服务费][普通订单][%s]，订单服务费单据已创建完成", order.getSn()));
    }

    @Override
    public void generateStatementByShipping(Long shippingId) {
        // 获取发货单
        Shipping shipping = shippingRepository.findById(shippingId).orElse(null);
        if (shipping == null) {
            writeCommissionLog("[服务费][普通订单]发货单ID：" + shippingId + "，发货单的不存在");

            return;
        }
        // 判断发货单是否已创建结算单
        Statement statementRow = statementRepository.findFirstByShippingId(shippingId);
        if (statementRow != null) {
            writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，发货单已创建过服务费单据", shipping.getOrders().getSn(), shipping.getShippingSn()));
            return;
        }
        // 获取订单数据
        Order order = shipping.getOrders();
        Long orderId = shipping.getOrders().getId();
        // 临时结算单
        List<TemporaryStatement> temporaryStatementList = new ArrayList<>();
        // 结算单
        List<Statement> statementList = new ArrayList<>();
        // 生成货款结算单
        if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) {
            // 获取货款临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.GOODS_COST);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，订单的货款临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false));
            temporaryStatementList.add(temporaryStatement);
        }
        // 生成品牌结算单
        if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) {
            // 获取品牌临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.BRAND_FEE);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，订单的品牌临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false));
            temporaryStatementList.add(temporaryStatement);
        }
        // 生成策划结算单
        if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) {
            // 获取品牌临时结算单
            TemporaryStatement temporaryStatement = temporaryStatementRepository.findFirstByOrdersIdAndSubaccountType(orderId, SubaccountType.DEVISE_FEE);
            if (temporaryStatement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，订单的策划临时服务费单据不存在", shipping.getOrders().getSn(), shipping.getShippingSn()));
                return;
            }
            statementList.add(createStatementByTemporaryStatement(temporaryStatement, shipping, order, false));
            temporaryStatementList.add(temporaryStatement);
        }
        if (temporaryStatementList.size() != statementList.size()) {
            return;
        }
        statementRepository.saveAll(statementList);
        // 获取已结算单据
        List<Statement> allStatementList = statementRepository.findAllByOrdersId(orderId);
        // 计算总结算金额
        BigDecimal totalStatementAmount = allStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 判断该临时结算是否结算完毕
        if (totalStatementAmount.compareTo(order.getPayAmount()) == 0) {
            for (TemporaryStatement temporaryStatement : temporaryStatementList) {
                temporaryStatement.setIsStatement(true);
            }
            temporaryStatementRepository.saveAll(temporaryStatementList);
        }
        writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，发货单服务费单据已创建完成", shipping.getOrders().getSn(), shipping.getShippingSn()));
    }

    /**
     * 结算单-根据临时结算单生成
     * <p>若是直接结算则不需要传发货单</p>
     *
     * @param temporaryStatement 临时结算单
     * @param shipping           发货单
     * @param order              订单
     * @param isDirectSettlement 是否直接结算
     * @return 结算单
     * @description
     * @author huabiao
     * @create 2022/9/2  16:15
     */
    private Statement createStatementByTemporaryStatement(TemporaryStatement temporaryStatement, Shipping shipping, Order order, Boolean isDirectSettlement) {
        // 获取订单相关数据
        Long orderId = order.getId();
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId);
        // 结算单构建
        Statement statement = new Statement();
        statement.setOrders(order);
        statement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE"));
        statement.setStatementType(StatementType.NORMALORDER);
        statement.setSubaccountType(temporaryStatement.getSubaccountType());
        statement.setStatementState(StatementState.NOTRECORDED);
        statement.setShipping(shipping);
        statement.setCompany(temporaryStatement.getCompany());
        // 结算单项
        List<StatementLine> statementLineList = new ArrayList<>();
        // 结算金额
        BigDecimal subaccountAmount = BigDecimal.ZERO;
        if (isDirectSettlement) {
            for (OrderItem orderItem : order.getOrderItems()) {
                StatementLine statementLine = new StatementLine();
                statementLine.setStatement(statement);
                if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
                    statementLine.setSubaccountAmount(orderItem.getGoodsPayment());
                    statementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio()));
                    statementLine.setCompany(temporaryStatement.getCompany());
                    // 计算品牌授权费
                    if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                        OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderItem.getId())).findFirst().orElse(null);
                        if (orderItemFeeRatio != null) {
                            statementLine.setBrandAuthFee(orderItem.getGoodsPayment().multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) {
                    statementLine.setSubaccountAmount(orderItem.getBrandCost());
                    statementLine.setCompany(temporaryStatement.getCompany());
                    statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getBrandCostRatio() : null);
                } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) {
                    statementLine.setSubaccountAmount(orderItem.getDeviseCost());
                    statementLine.setCompany(temporaryStatement.getCompany());
                    statementLine.setSubaccountRatio(orderFeeRatio != null ? orderFeeRatio.getDeviseCostRatio() : null);
                }
                statementLine.setOrderItem(orderItem);
                statementLine.setQuantity(orderItem.getQuantity());
                subaccountAmount = subaccountAmount.add(statementLine.getSubaccountAmount());
                statementLineList.add(statementLine);
            }
            // 判断订单项分账金额和订单分账金额是否一致
            if (temporaryStatement.getSubaccountType().equals(SubaccountType.GOODS_COST) && order.getGoodsPayment().compareTo(subaccountAmount) != 0) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的货款与订单行不一致", order.getSn()));
                return null;
            } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE) && order.getBrandCost().compareTo(subaccountAmount) != 0) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的品牌费与订单行不一致", order.getSn()));
                return null;
            } else if (temporaryStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE) && order.getDeviseCost().compareTo(subaccountAmount) != 0) {
                writeCommissionLog(String.format("[服务费][普通订单][%s]，订单的策划费与订单行不一致", order.getSn()));
                return null;
            }
        } else {
            for (ShippingItem shippingItem : shipping.getShippingItem()) {
                StatementLine statementLine = new StatementLine();
                List<OrderItem> orderItemList = order.getOrderItems().stream().filter(filterOrderItem -> filterOrderItem.getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(orderItemList)) {
                    writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，发货单的订单明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId()));
                    return null;
                }
                if (orderItemList.size() > 1) {
                    writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，发货单的订单明细[SKU_ID:%s]存在多条", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId()));
                    return null;
                }
                OrderItem orderItem = orderItemList.get(0);
                // 获取临时结算单项
                TemporaryStatementLine temporaryStatementLine = temporaryStatement.getTemporaryStatementLines().stream().filter(filterTemporaryStatementLine -> filterTemporaryStatementLine.getOrderItem().equals(orderItem)).findFirst().orElse(null);

                if (temporaryStatementLine == null) {
                    writeCommissionLog(String.format("[服务费][普通订单][%s][发货单][%s]，发货单的临时结算明细[SKU_ID:%s]不存在", shipping.getOrders().getSn(), shipping.getShippingSn(), shippingItem.getSkuId()));
                    return null;
                }
                BigDecimal subaccountLineAmount;
                // 判断是否部分发货
                if (shippingItem.getShippingQuantity().equals(orderItem.getQuantity())) {
                    // 一次性全部发完
                    subaccountLineAmount = temporaryStatementLine.getStatementAmount();
                } else {
                    // 获取已结算数量
                    BigDecimal statementQuantity = statementLineRepository.calculateSubaccountQuantity(orderItem.getId());
                    // 判断是否最后一次结算
                    if (orderItem.getQuantity().equals(shippingItem.getShippingQuantity() + statementQuantity.intValue())) {
                        // 最后一次发货 总的减去之前计算的
                        BigDecimal subaccountAmountSum = statementLineRepository.calculateSubaccountAmount(orderItem.getId());
                        subaccountLineAmount = temporaryStatementLine.getStatementAmount().subtract(subaccountAmountSum);
                    } else {
                        // 部分发货
                        // 计算比例 总分账*(当前发货数量/总购买数量)
                        subaccountLineAmount = temporaryStatementLine.getStatementAmount()
                                .multiply(new BigDecimal(shippingItem.getShippingQuantity()))
                                .divide(new BigDecimal(orderItem.getQuantity()), 2, BigDecimal.ROUND_HALF_UP);
                    }
                }
                statementLine.setCompany(temporaryStatementLine.getCompany());
                statementLine.setSubaccountAmount(subaccountLineAmount);
                statementLine.setOrderItem(orderItem);
                statementLine.setShippingItem(shippingItem);
                statementLine.setSubaccountRatio(temporaryStatementLine.getSubaccountRatio());
                statementLine.setStatement(statement);
                // 计算品牌授权费
                if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                    OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(Long.valueOf(shippingItem.getOrderItemId()))).findFirst().orElse(null);
                    if (orderItemFeeRatio != null) {
                        statementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
                    }
                }
                statementLine.setQuantity(shippingItem.getShippingQuantity());
                subaccountAmount = subaccountAmount.add(subaccountLineAmount);
                statementLineList.add(statementLine);
            }
        }
        statement.setStatementLine(statementLineList);
        statement.setStatementAmount(subaccountAmount);
        return statement;
    }

    @Override
    public void generateStatementByAfterSale(Long afterSaleId) {
        AfterSale afterSale = afterSaleRepository.findById(afterSaleId).orElse(null);
        if (afterSale == null) {
            writeCommissionLog("[服务费][普通订单]售后单ID：" + afterSaleId + "，售后单不存在");
            return;
        }
        // 判断是否已存在对应的结算单
        if (statementRepository.existsByAfterSaleId(afterSaleId)) {
            writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，售后单已创建过服务费单据", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
            return;
        }
        List<Statement> refundStatementList = new ArrayList<>();
        /**
         * 先算品牌和策划的退款金额，而剩下的则是货款的金额
         */
        // 生成品牌结算单
        Order order = afterSale.getOrders();
        List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(order.getId(), StatementType.NORMALORDER);
        if (CollectionUtils.isEmpty(statementList)) {
            writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
            return;
        }
        if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) {
            // 获取对应订单结算单
            Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.BRAND_FEE)).findFirst().orElse(null);
            if (statement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，对应的品牌费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
                return;
            }
            Statement refundStatement = createRefundStatement(statement, afterSale);
            refundStatementList.add(refundStatement);
        }
        // 生成策划结算单
        if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) {
            Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)).findFirst().orElse(null);
            if (statement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，对应的策划费结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
                return;
            }
            refundStatementList.add(createRefundStatement(statement, afterSale));
        }
        // 生成货款结算单
        if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) {
            Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null);
            if (statement == null) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，对应的货款结算单不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
                return;
            }
            // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额
            refundStatementList.add(createRefundStatement(statement, afterSale));
        }
        // 判断退款结算单和售后单的退款金额是否一致
        BigDecimal totalRefundAmount = refundStatementList.stream().map(statement -> statement.getStatementAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (totalRefundAmount.add(afterSale.getAmount()).compareTo(BigDecimal.ZERO) != 0) {
            writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，订单对冲服务费单据金额不一致", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
            return;
        }
        statementRepository.saveAll(refundStatementList);
        writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，订单对冲服务费单据已创建完成", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn()));
    }

    /**
     * 退款结算单-生成
     *
     * @param statement:结算单
     * @param afterSale:售后单
     * @return 结算单
     * @description
     * @author huabiao
     * @create 2022/9/2  16:15
     */
    private Statement createRefundStatement(Statement statement, AfterSale afterSale) {
        Long afterSaleId = afterSale.getId();
        Long orderId = afterSale.getOrders().getId();

        // 拼接退款结算单
        Statement refundStatement = new Statement();
        refundStatement.setOrders(afterSale.getOrders());
        refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE"));
        refundStatement.setStatementType(StatementType.AFTERSALES);
        refundStatement.setSubaccountType(statement.getSubaccountType());
        refundStatement.setStatementState(StatementState.NOTRECORDED);

        // 拼接退款结算单行
        List<StatementLine> refundStatementLineList = new ArrayList<>();
        // 退款金额
        BigDecimal subaccountAmount = BigDecimal.ZERO;
        for (AfterSaleItem afterSaleItem : afterSale.getAfterSaleItems()) {
            StatementLine refundStatementLine = new StatementLine();
            refundStatementLine.setStatement(refundStatement);
            // 退款时不会有发货单
            if (afterSale.getAfterSaleType().equals(AfterSaleType.RETURN_REFUND)) {
                // 查找对应发货单项
                List<ShippingItem> shippingItemList = afterSale.getShipping().getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(shippingItemList)) {
                    writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，发货单项明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId()));
                    return null;
                }
                if (shippingItemList.size() > 1) {
                    writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，发货单项明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId()));
                    return null;
                }
                ShippingItem shippingItem = shippingItemList.get(0);
                refundStatementLine.setShippingItem(shippingItem);
            }
            // 获取订单结算单的结算单行
            List<StatementLine> statementLineList = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getSkuId().equals(afterSaleItem.getSkuId())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(statementLineList)) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，售后单的订单明细[SKU_ID:[%s]不存在", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId()));
                return null;
            }
            if (statementLineList.size() > 1) {
                writeCommissionLog(String.format("[服务费][普通订单][%s][售后单][%s]，售后单的订单明细[SKU_ID:[%s]存在多条", afterSale.getOrders().getSn(), afterSale.getAfterSaleSn(), afterSaleItem.getSkuId()));
                return null;
            }
            StatementLine statementLine = statementLineList.get(0);

            // 获取订单费用比例
            OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(orderId);
            refundStatementLine.setCompany(statementLine.getCompany());
            refundStatementLine.setOrderItem(statementLine.getOrderItem());
            // 计算每个售后项的退款金额
            BigDecimal subaccountLineAmount = BigDecimal.ZERO;
            switch (statement.getSubaccountType()) {
                case GOODS_COST:
                    subaccountLineAmount = afterSaleItem.getAmount().multiply(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio())).setScale(2, BigDecimal.ROUND_HALF_UP);
                    break;
                case BRAND_FEE:
                    refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio());
                    subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    break;
                case DEVISE_FEE:
                    refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio());
                    subaccountLineAmount = afterSaleItem.getAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    break;
            }
            subaccountAmount = subaccountAmount.add(subaccountLineAmount);
            refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate());
            // 计算品牌授权费
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(afterSaleItem.getOrderItem().getId())).findFirst().orElse(null);
                if (orderItemFeeRatio != null) {
                    refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            }
            refundStatementLine.setQuantity(afterSaleItem.getQuantity());
            refundStatementLineList.add(refundStatementLine);
        }
        refundStatement.setStatementLine(refundStatementLineList);
        refundStatement.setShipping(afterSale.getShipping());
        refundStatement.setAfterSale(afterSale);
        refundStatement.setCompany(statement.getCompany());
        refundStatement.setStatementAmount(subaccountAmount.negate());
        return refundStatement;
    }

    @Override
    public void generateSubaccountByOrder(Long orderId) {
        Order order = getOrderAndCheck(orderId);
        if (order == null) {
            return;
        }

        // 获取所有的退款单并判断退款结算单是否都生成
        if (checkRefundList(orderId, order)) {
            return;
        }

        // 根据支付方式进行分账
        Receipt receipt = order.getReceipt().get(0);
        // 电子账簿支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) {
            confirmsCombinedGuaranteeByOrder(order);
        }
        // POS、微信、支付宝、云闪付支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT)
                || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY)
                || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS)
                || receipt.getPaymentMethod().equals(PaymentMethod.POS)
                || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) {
            createSubaccountByOrder(order, receipt.getPaymentMethod());
        }
    }

    private boolean checkRefundList(Long orderId, Order order) {
        List<Refund> refundList = refundRepository.findAllByOrdersId(orderId);
        if (CollectionUtils.isNotEmpty(refundList)) {
            BigDecimal refundAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 获取退款结算单
            List<Statement> statementList = statementRepository.findAllByOrdersIdAndStatementType(orderId, StatementType.AFTERSALES);
            BigDecimal refundStatementAmount = statementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (refundAmount.add(refundStatementAmount).compareTo(BigDecimal.ZERO) != 0) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，退款单金额与退款结算单金额不一致，分账失败。", order.getSn()));
                return true;
            }
            // 判断所有退款单状态是否都为已退款
            if(refundList.stream().filter(refund -> !RefundStatus.REFUNDED.equals(refund.getRefundStatus())).findAny().isPresent()){
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，存在未完成退款的退款单，分账失败。", order.getSn()));
                return true;
            }
        }
        return false;
    }

    private Order getOrderAndCheck(Long orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order == null) {
            throw new YnceErrorException(YnceError.YNCE_204003);
        }
        // 判断订单是否在申请售后中
        if (order.getIsReturnRefund() || order.getIsRefund()) {
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，订单在售后中。", order.getSn()));
            return null;
        }
        // 判断是否当前订单所有的商品是否全部退货
        Optional<OrderItem> orderItemOptional = order.getOrderItems().stream().filter(orderItem -> orderItem.getQuantity() > (orderItem.getReturnCount() + orderItem.getCloseCount())).findAny();
        if (BooleanUtils.isFalse(orderItemOptional.isPresent())) {
            // 此订单下面的所有商品已全部退退货，不执行分账
            stopOrderSubaccount(order.getId());
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，订单已退货，不执行分账。", order.getSn()));
            return null;
        }
        // 判断当前订单是否已经退款
        if (order.getPaymentStatus().equals(PaymentStatus.REFUNDED)) {
            stopOrderSubaccount(order.getId());
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，订单已退款，不执行分账。", order.getSn()));
            return null;
        }
        return order;
    }

    @Override
    public void handleSubaccount(SettlementCallbackVO settlementCallbackVO) {
        // 获取分账单
        List<Subaccount> subaccountList = subaccountRepository.findAllByExternalId(settlementCallbackVO.getSettOrderNo());
        Boolean isSeparate = false;
        // 存在订单结算和发货单结算
        Long orderId = null;
        Long shippingId = null;
        for (Subaccount subaccount : subaccountList) {
            orderId = subaccount.getOrders().getId();
            if (subaccount.getShipping() != null) {
                shippingId = subaccount.getShipping().getId();
            }
            ProfitSharingCallbackVO profitSharingCallbackVO = settlementCallbackVO.getProfitSharingList().stream().filter(filterProfitSharingCallbackVO -> filterProfitSharingCallbackVO.getProfitSharingWalletId().equals(subaccount.getCompany().getWalletId())).findFirst().orElse(null);
            if (profitSharingCallbackVO != null) {
                // 分账成功
                if (profitSharingCallbackVO.getProfitSharingStatus().equals("02")) {
                    subaccount.setSeparateTime(LocalDateTime.now());
                    subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC);
                    subaccountRepository.save(subaccount);
                }
                // 分账失败
                else if (profitSharingCallbackVO.getProfitSharingStatus().equals("03")) {
                    subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL);
                    subaccountRepository.save(subaccount);
                }
            }
        }
        if (isSeparate) {
            if (shippingId != null) {
                // 更新发货单已分账
                shippingRepository.updateIsSeparateAccountsById(orderId);
            } else if (orderId != null) {
                // 更新订单已分账
                orderRepository.updateIsSeparateAccountsById(orderId);
            }
        }
    }

    @Override
    public void handleBrandAuthFee(String subaccountNo) {
        // 获取所有品牌授权费
        Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo);
        if (ObjectUtil.isNull(subaccount)) {
            throw new YnceErrorException("分帐单不存在");
        }
        if (!subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) {
            throw new YnceErrorException("分帐单类型不是品牌授权费");
        }
        if (subaccount.getOrders().getIsSeparateAccounts()) {
            throw new YnceErrorException("对应订单已分账");
        }
        // 查询订单
        Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null);
        if (ObjectUtil.isNull(order)) {
            throw new YnceErrorException(YnceError.YNCE_211004);
        }
        // 区分预存款和其他支付方式
        Receipt receipt = order.getReceipt().get(0);
        // 获取货款数据，可获得品牌授权费
        Subaccount goodsCostSubaccount = subaccountRepository.findByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST);
        // 预存款支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) {
            // 品牌授权费差额 = 银联支付单金额-已分账金额
            ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.BRAND_AUTH_FEE);
            BigDecimal balance = chinaumsPayment.getAmount().subtract(subaccount.getSubaccountAmount());
            // 调用分账确认接口
            // 拼接扩展字段：商品信息
            ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
            chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), balance));
            // 拼接分账确认请求参数
            ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO
                    .builder()
                    .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE")
                    .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId())
                    .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                    .amount(balance.multiply(new BigDecimal(100)).intValue())
                    .extra(chinaumsGuaranteePayExtraDTO)
                    .build();
            ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO;
            try {
                chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO);
            } catch (Exception exception) {
                throw new YnceErrorException("分账确认失败");
            }
            // 当为处理中时需要调用接口查询
            if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) {
                try {
                    long currentTimeMillis = System.currentTimeMillis();
                    while (true) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                        chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class);
                        // 当请求成功或者时间超时时，结束循环
                        if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) {
                            break;
                        }
                    }
                } catch (Exception exception) {
                    log.error(exception.getMessage());
                    throw new YnceErrorException("循环查询合并消费担保确认失败");
                }
            }
            subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()));
            // 修改分账总金额
            subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee());
            // 修改分账净额
            subaccount.setSubaccountAmount(chinaumsPayment.getAmount());
            // 修改服务费比例
            OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
            if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio());
            }
            // 修改平台服务费：平台服务费 = 分账总额 - 分账净额
            subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount()));
            subaccountRepository.save(subaccount);

            // 处理预存款账户
            AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO
                    .builder()
                    .company(subaccount.getCompany())
                    .direction(ChangeDirection.ADD)
                    .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue()))
                    .amount(balance)
                    .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo())
                    .sourceCompanyId(subaccount.getSourceCompany().getId())
                    .build();
            accountService.intoAccount(accountChangeCreateDTO);
            // 修改已确认金额
            chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance));
            chinaumsPaymentRepository.saveAndFlush(chinaumsPayment);
        } else {
            // 其他支付方式所生成的分帐单金额是正确的，但是分帐单有问题
            // 修改分账总金额
            subaccount.setSubaccountTotalAmount(goodsCostSubaccount.getBrandAuthFee());
            // 修改服务费比例
            OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
            if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                subaccount.setPlatformServiceCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostServiceCostRatio());
            }
            // 修改平台服务费：平台服务费 = 分账总额 - 分账净额
            subaccount.setPlatformServiceFee(subaccount.getSubaccountTotalAmount().subtract(subaccount.getSubaccountAmount()));
            subaccountRepository.save(subaccount);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateStatementByOrderRefund(Long orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order == null) {
            throw new YnceErrorException(YnceError.YNCE_204003);
        }
        // 获取所有退款单
        List<Refund> refundList = refundRepository.findAllByOrdersId(orderId);
        if (CollectionUtils.isNotEmpty(refundList)) {
            List<OrderRefundItemDTO> orderRefundItemDTOList = new ArrayList<>();
            // 拼接订单退款项DTO
            for (OrderItem orderItem : order.getOrderItems()) {
                if (orderItem.getCloseCount() > 0) {
                    OrderRefundItemDTO orderRefundItemDTO = new OrderRefundItemDTO();
                    orderRefundItemDTO.setOrderItem(orderItem);
                    orderRefundItemDTO.setRefundAmount(orderItem.getRefundAmount());
                    orderRefundItemDTO.setRefundQuantity(orderItem.getCloseCount());
                    orderRefundItemDTOList.add(orderRefundItemDTO);
                }
            }
            if (CollectionUtils.isEmpty(orderRefundItemDTOList)) {
                return;
            }
            // 总退款金额
            BigDecimal totalCloseAmount = refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            List<Statement> refundStatementList = new ArrayList<>();
            // 生成品牌结算单
            if (order.getBrandCost().compareTo(BigDecimal.ZERO) == 1) {
                refundStatementList.add(createRefundStatement(SubaccountType.BRAND_FEE, order, orderRefundItemDTOList, order.getBrandCompany()));
            }
            // 生成策划结算单
            if (order.getDeviseCost().compareTo(BigDecimal.ZERO) == 1) {
                refundStatementList.add(createRefundStatement(SubaccountType.DEVISE_FEE, order, orderRefundItemDTOList, order.getDeviseCompany()));
            }
            // 生成货款结算单
            if (order.getGoodsPayment().compareTo(BigDecimal.ZERO) == 1) {
                // 货款退款金额 = 退款金额 - 品牌费退款金额 - 策划费退款金额
                refundStatementList.add(createRefundStatement(SubaccountType.GOODS_COST, order, orderRefundItemDTOList, order.getSellerCompany()));
            }
            // 判断金额是否一致
            BigDecimal totalRefundAmount = refundStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (totalRefundAmount.add(totalCloseAmount).compareTo(BigDecimal.ZERO) != 0) {
                log.error("订单关闭生成退款结算单失败：退款金额不一致");
                return;
            }
            statementRepository.saveAll(refundStatementList);
        }


    }

    @Override
    public void handleGoodsCost(String subaccountNo, List<Long> orderItemIdList) {
        // 获取货款分帐单
        Subaccount subaccount = subaccountRepository.findBySubaccountNo(subaccountNo);
        if (subaccount == null) {
            throw new YnceErrorException("分帐单不存在");
        }
        if (!subaccount.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
            throw new YnceErrorException("分帐单类型不是货款");
        }
        if (subaccount.getOrders().getIsSeparateAccounts()) {
            throw new YnceErrorException("对应订单已分账");
        }
        // 查询订单
        Order order = orderRepository.findById(subaccount.getOrders().getId()).orElse(null);
        if (order == null) {
            throw new YnceErrorException(YnceError.YNCE_211004);
        }
        // 区分预存款和其他支付方式
        Receipt receipt = order.getReceipt().get(0);
        // 预存款支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) {
            // 货款差额 = 银联支付单金额-银联退款单金额-已分账金额
            // 获取银联支付单
            ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(order.getId(), SubaccountType.GOODS_COST);
            // 获取银联退款单
            List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
            BigDecimal chinaumsRefundAmount = CollectionUtils.isNotEmpty(chinaumsRefundList) ? chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO;
            BigDecimal balance = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount).subtract(subaccount.getSubaccountAmount());
            if (balance.compareTo(BigDecimal.ZERO) == 0) {
                throw new YnceErrorException("货款差额为0，无需补充");
            }
            // 拼接扩展字段：商品信息
            ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
            List<OrderItem> orderItemList = new ArrayList<>();
            BigDecimal orderAmount = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(orderItemIdList)) {
                for (OrderItem orderItem : order.getOrderItems()) {
                    if (orderItemIdList.contains(orderItem.getId())) {
                        orderItemList.add(orderItem);
                        orderAmount = orderAmount.add(orderItem.getAmount());
                    }
                }
            } else {
                orderItemList = order.getOrderItems();
                orderAmount = order.getAmount();
            }
            chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(orderItemList, order.getSn(), orderAmount, balance));
            // 拼接分账确认请求参数
            ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO
                    .builder()
                    .outOrderNo(subaccount.getSubaccountNo() + "-BALANCE")
                    .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId())
                    .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                    .amount(balance.multiply(new BigDecimal(100)).intValue())
                    .extra(chinaumsGuaranteePayExtraDTO)
                    .build();
            ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO;
            try {
                chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO);
            } catch (Exception exception) {
                throw new YnceErrorException("分账确认失败");
            }
            // 当为处理中时需要调用接口查询
            if (chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing")) {
                try {
                    long currentTimeMillis = System.currentTimeMillis();
                    while (true) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("combinedGuaranteeConfirmId", chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                        chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class);
                        // 当请求成功或者时间超时时，结束循环
                        if (!chinaumsGuaranteePayConfirmsVO.getStatus().equals("processing") || System.currentTimeMillis() - currentTimeMillis > 5000) {
                            break;
                        }
                    }
                } catch (Exception exception) {
                    log.error(exception.getMessage());
                    throw new YnceErrorException("循环查询合并消费担保确认失败");
                }
            }
            subaccount.setExternalId(subaccount.getExternalId() + "," + chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成差额分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()));
            // 修改分账净额
            subaccount.setSubaccountAmount(subaccount.getSubaccountAmount().add(balance));
            subaccountRepository.save(subaccount);
            // 处理预存款账户
            AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO
                    .builder()
                    .company(subaccount.getCompany())
                    .direction(ChangeDirection.ADD)
                    .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue()))
                    .amount(balance)
                    .sourceNo(chinaumsGuaranteePayConfirmsDTO.getOutOrderNo())
                    .sourceCompanyId(subaccount.getSourceCompany().getId())
                    .build();
            accountService.intoAccount(accountChangeCreateDTO);
            // 修改已确认金额
            chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(balance));
            chinaumsPaymentRepository.saveAndFlush(chinaumsPayment);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateRefundSubaccount(SubaccountRefund subaccountRefund) {
        Subaccount subaccount = new Subaccount();
        subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
        subaccount.setCompany(subaccountRefund.getRefundCompany());
        subaccount.setSubaccountCostRatio(subaccountRefund.getSubaccountCostRatio());
        subaccount.setSubaccountAmount(subaccountRefund.getAmount().negate());
        subaccount.setSubaccountTotalAmount(subaccountRefund.getAmount().negate());
        subaccount.setSubaccountType(subaccountRefund.getSubaccountType());
        subaccount.setOrders(subaccountRefund.getOrders());
        subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC);
        subaccount.setSeparateTime(subaccountRefund.getRefundTime());
        subaccount.setExternalId(subaccountRefund.getExternalId());
        subaccount.setExternalTime(subaccountRefund.getRefundTime());
        subaccount.setSourceCompany(subaccountRefund.getRefundCompany());
        subaccount.setExternalTime(subaccountRefund.getRefundTime());
        subaccountRepository.saveAndFlush(subaccount);

        // 对供应商流水进行处理
        AccountChangeCreateDTO supplierAccountChangeCreateDTO = AccountChangeCreateDTO
                .builder()
                .company(subaccount.getCompany())
                .direction(ChangeDirection.REDUCE)
                .type(AccountChangeType.REFUND)
                .amount(subaccountRefund.getAmount())
                .sourceCompanyId(subaccountRefund.getReceiptCompany().getId())
                .sourceNo(subaccountRefund.getRefundSn())
                .build();
        accountService.intoAccount(supplierAccountChangeCreateDTO);
        // 对经销商流水进行处理
        AccountChangeCreateDTO dealerAccountChangeCreateDTO = AccountChangeCreateDTO
                .builder()
                .company(subaccountRefund.getReceiptCompany())
                .direction(ChangeDirection.ADD)
                .type(AccountChangeType.REFUND)
                .amount(subaccountRefund.getAmount())
                .sourceCompanyId(subaccountRefund.getRefundCompany().getId())
                .sourceNo(subaccountRefund.getRefundSn())
                .build();
        accountService.intoAccount(dealerAccountChangeCreateDTO);
    }

    @Override
    public void generateSubaccountByShipping(Long shippingId) {
        Shipping shipping = shippingRepository.findById(shippingId).orElse(null);
        if (shipping == null) {
            throw new YnceErrorException(YnceError.YNCE_204010);
        }
        // 判断发货单是否售后中
        AfterSale afterSale = afterSaleRepository.findFirstByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.CREATED);
        if (afterSale != null) {
            writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，发货单在售后中。", shipping.getOrders().getSn(), shipping.getShippingSn()));
            return;
        }
        // 判断当前发货单是否已全部退货，若是则不参与分账
        Optional<ShippingItem> shippingItemOptional = shipping.getShippingItem().stream().filter(shippingItem -> !shippingItem.getReturnQuantity().equals(shippingItem.getShippingQuantity())).findAny();
        if (BooleanUtils.isFalse(shippingItemOptional.isPresent())) {
            // 此发货单下面的所有商品已全部退退货，不执行分账
            updateIsSeparateAccountsByShipping(shipping);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，不执行分账。", shipping.getOrders().getSn(), shipping.getShippingSn()));
            return;
        }

        // 根据支付方式进行分账
        Receipt receipt = shipping.getOrders().getReceipt().get(0);
        // 电子账簿支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.DEPOSIT)) {
            confirmsCombinedGuaranteeByShipping(shipping);
        }
        // POS、微信、支付宝、云闪付支付
        if (receipt.getPaymentMethod().equals(PaymentMethod.WECHAT)
                || receipt.getPaymentMethod().equals(PaymentMethod.ALIPAY)
                || receipt.getPaymentMethod().equals(PaymentMethod.CHINA_UNIONPAY_QUICK_PASS)
                || receipt.getPaymentMethod().equals(PaymentMethod.POS)
                || receipt.getPaymentMethod().equals(PaymentMethod.CREDIT_PAY)) {
            // 判断支付时间是否超过T+1
            createSubaccountByShipping(shipping, receipt.getPaymentMethod());
        }
    }

    /**
     * 生成平台服务费分账单
     *
     * @param subaccountCostRatio :分账比例
     * @param subaccountAmount    :分账金额
     * @param order               :订单
     * @param shipping            :发货单
     * @param sourceCompany       :来源企业
     * @return 分账单
     * @author huabiao
     * @create 2022/9/17  16:51
     */
    private Subaccount generatePlatformSubaccount(BigDecimal subaccountCostRatio, BigDecimal subaccountAmount, Order order, Shipping shipping, Company sourceCompany) {
        Subaccount subaccount = new Subaccount();
        subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
        subaccount.setSubaccountCostRatio(subaccountCostRatio);
        subaccount.setSubaccountAmount(subaccountAmount);
        subaccount.setSubaccountTotalAmount(subaccountAmount);
        subaccount.setSubaccountType(SubaccountType.SERVICE_FEE);
        subaccount.setOrders(order);
        subaccount.setShipping(shipping);
        subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
        subaccount.setSourceCompany(sourceCompany);
        return subaccount;
    }


    @Override
    public String createPayment(Order order, PaymentType paymentType, UnionpayAppOrderType unionpayAppOrderType, String unionpaySn, PosPaymentType posType, String hardwareSn) {
        if (!PaymentStatus.UN_PAID.equals(order.getPaymentStatus())) {
            throw new YnceErrorException(YnceError.YNCE_204004);
        }
        if (paymentType == null) {
            paymentType = PaymentType.ORDER;
        }
        // 校验订单支付单状态
        if (!PaymentType.RECHARGE.equals(paymentType)) {
            paymentService.checkPaymentStatus(order);
        }
        // 拼接支付单参数
        CreatePaymentDTO createPaymentDTO = new CreatePaymentDTO();
        createPaymentDTO.setPaymentMethod(PaymentMethod.valueOf(unionpayAppOrderType.getValue()));
        createPaymentDTO.setPayerId(order.getBuyerCompany().getId().toString());
        createPaymentDTO.setPayerName(order.getBuyerCompany().getName());
        createPaymentDTO.setPayeeId(order.getSellerCompany().getId().toString());
        createPaymentDTO.setPayeeName(order.getSellerCompany().getName());
        createPaymentDTO.setAmount(order.getAmount().subtract(order.getPayAmount()));
        createPaymentDTO.setPaymentType(paymentType);
        if (paymentType.equals(PaymentType.RECHARGE)) {
            createPaymentDTO.setTopUpOrderId(order.getId());
        } else {
            createPaymentDTO.setOrderId(order.getId().toString());
        }
        createPaymentDTO.setErpAccountSet(order.getErpAccountSet());
        if (UnionpayAppOrderType.POS.equals(unionpayAppOrderType)) {
            createPaymentDTO.setPosPaymentType(posType);
        }
        createPaymentDTO.setExternalId(unionpaySn);
        createPaymentDTO.setUnionpaySn(unionpaySn);
        createPaymentDTO.setHardwareSn(hardwareSn);
        return createPayment(createPaymentDTO);
    }

    /***
     * 支付单-创建
     *
     * @param createPaymentDTO:创建支付单DTO
     * @return 银联订单号/支付单号
     * @description
     * @author huabiao
     * @create 2022/9/1  16:46
     */
    @Transactional(rollbackFor = Exception.class)
    public String createPayment(CreatePaymentDTO createPaymentDTO) {
        Payment payment = new Payment();
        payment.setSn(sequenceUtil.getNextSequenceNumber("ZF"));
        payment.setPayStatus(PayStatus.READY);
        BeanUtils.copyProperties(createPaymentDTO, payment);
        paymentRepository.saveAndFlush(payment);
        return payment.getSn();
    }

    /**
     * 处理商品数据
     *
     * @param orderItemList:订单项
     * @param sn:订单号
     * @param orderAmount:订单金额
     * @param amount:分摊金额
     * @return 处理完的银联JSON数据
     * @author huabiao
     * @create 2022/12/15  14:08
     */
    private List<JSONObject> handleProductInfoByOrder(List<OrderItem> orderItemList, String sn, BigDecimal orderAmount, BigDecimal amount) {
        // 循环订单项
        List<JSONObject> productInfos = new ArrayList<>();
        BigDecimal allocatedAmount = BigDecimal.ZERO;
        for (int i = 0; i < orderItemList.size(); i++) {
            OrderItem orderItem = orderItemList.get(i);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("orderNo", sn + "-" + orderItem.getId());
            // 按比例计算,最后一项直接减完
            if (i == (orderItemList.size() - 1)) {
                jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue());
            } else {
                BigDecimal orderItemPlatformServiceFee = amount.multiply(orderItem.getAmount()).divide(orderAmount, 2, BigDecimal.ROUND_DOWN);
                // 当计算结果不大于0时，赋值0.01
                if (orderItemPlatformServiceFee.compareTo(BigDecimal.ZERO) != 1) {
                    orderItemPlatformServiceFee = new BigDecimal("0.01");
                }
                jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue());
                allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee);
            }
            jsonObject.put("productName", orderItem.getGoodsName() + orderItem.getSkuName());
            jsonObject.put("productCount", orderItem.getQuantity());
            productInfos.add(jsonObject);
        }
        return productInfos;
    }

    /**
     * 处理商品数据
     *
     * @param shippingItems:订单项
     * @param sn:订单号
     * @param shippingAmount:发货金额
     * @param amount:分摊金额
     * @return 处理完的银联JSON数据
     * @author huabiao
     * @create 2022/12/15  14:08
     */
    private List<JSONObject> handleProductInfoByShipping(List<ShippingItem> shippingItems, String sn, BigDecimal shippingAmount, BigDecimal amount) {
        // 循环订单项
        List<JSONObject> productInfos = new ArrayList<>();
        BigDecimal allocatedAmount = BigDecimal.ZERO;
        for (int i = 0; i < shippingItems.size(); i++) {
            ShippingItem shippingItem = shippingItems.get(i);
            JSONObject jsonObject = new JSONObject();
            // 找到对应的订单项
            OrderItem orderItem = orderItemRepository.findById(Long.valueOf(shippingItem.getOrderItemId())).orElse(null);
            jsonObject.put("orderNo", sn + "-" + orderItem.getId());
            // 按比例计算,最后一项直接减完
            if (i == (shippingItems.size() - 1)) {
                jsonObject.put("orderAmount", amount.subtract(allocatedAmount).multiply(new BigDecimal(100)).intValue());
            } else {
                BigDecimal orderItemPlatformServiceFee = amount.multiply(shippingItem.getAmount()).divide(shippingAmount, 2, BigDecimal.ROUND_DOWN);
                jsonObject.put("orderAmount", orderItemPlatformServiceFee.multiply(new BigDecimal(100)).intValue());
                allocatedAmount = allocatedAmount.add(orderItemPlatformServiceFee);
            }
            jsonObject.put("productName", shippingItem.getGoodsName() + shippingItem.getSkuName());
            jsonObject.put("productCount", shippingItem.getShippingQuantity());
            productInfos.add(jsonObject);
        }
        return productInfos;
    }

    /**
     * 判断是否分账
     *
     * @param subaccountList:分账记录数组
     * @param chinaumsPaymentList:银联支付单数组
     * @param isNoPlatformSubaccount:是否无平台分账
     * @return true:已分账;false:未分账;
     * @description
     * @author huabiao
     * @create 2022/12/16  17:55
     */
    private Boolean checkIsSubaccount(List<Subaccount> subaccountList, List<ChinaumsPayment> chinaumsPaymentList, Boolean isNoPlatformSubaccount) {
        // 判断分帐单是否已经生成：
        // 1.判断是否存在分账记录；
        // 2.判断分账记录跟银联支付单数量是否一致
        // 3.分账记录必须为成功
        if (subaccountList.stream().filter(subaccount -> !subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)).count() > 0) {
            return false;
        }
        if (CollectionUtils.isNotEmpty(subaccountList) && CollectionUtils.isNotEmpty(chinaumsPaymentList)) {
            // 非平台分账记录数量
            Integer noPlatformSubaccountSize = Math.toIntExact(subaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).count());
            // 平台分账记录数量：由于是一张银联支付单分成多张分账记录，所以这里只需要判断是否存在即可
            Integer platformSubaccountSize = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).findFirst().isPresent() ? 1 : (isNoPlatformSubaccount ? 1 : 0);
            if ((noPlatformSubaccountSize + platformSubaccountSize) == chinaumsPaymentList.size()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 校验是否分账
     *
     * @param subaccountList 分账记录
     * @return true:已分账;false:未分账;
     * @description 只需判断已分账的金额之和是否和订单金额是否一致
     * @author huabiao
     * @create 2023/2/11  14:49
     */
    private Boolean checkIsSubaccountOrder(List<Subaccount> subaccountList) {
        if (CollectionUtils.isEmpty(subaccountList)) {
            return false;
        }
        Order order = subaccountList.get(0).getOrders();
        BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC))
                .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (totalSubaccountAmount.compareTo(order.getPayAmount().subtract(order.getRefundAmount())) == 0) {
            return true;
        }
        log.error("分账金额不正确, orderId:" + order.getId() + ", orderPayAmount:" + order.getPayAmount() + ", totalSubaccountAmount:" + totalSubaccountAmount);
        return false;
    }

    /**
     * 校验是否分账
     *
     * @param subaccountList 分账记录
     * @return true:已分账;false:未分账;
     * @description 只需判断已分账的金额之和是否和发货单金额是否一致
     * @author huabiao
     * @create 2023/2/11  14:49
     */
    private Boolean checkIsSubaccountByShipping(List<Subaccount> subaccountList) {
        if (CollectionUtils.isEmpty(subaccountList)) {
            return false;
        }
        Shipping shipping = subaccountList.get(0).getShipping();
        BigDecimal totalSubaccountAmount = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC))
                .collect(Collectors.toList()).stream().map(Subaccount::getSubaccountAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (totalSubaccountAmount.compareTo(shipping.getPayAmount()) == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 处理分账状态
     *
     * @param subaccount      分账记录
     * @param isOnlinePayment 是否线上支付（区分不同分账形式）
     * @author huabiao
     * @description 线上支付为POS支付和B2C支付，非线上支付为电子账簿支付
     * @create 2022/12/21  14:46
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleSubaccountStatus(Subaccount subaccount, Boolean isOnlinePayment) {
        // 分账状态
        String subaccountStatus;
        // 分账时间
        String finishedAt;
        // 当分账成功则返回
        if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_SUCC)) {
            return;
        }
        if (isOnlinePayment) {
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("transferId", subaccount.getExternalId());
                ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = chinaumsUtil.execute(RouteUtil.ROUTE_WALLET_UPAPI_ALLOCATIONS_TRANSFERS_BY_SYS_NO, jsonObject, ChinaumsGuaranteePayConfirmsVO.class);
                subaccountStatus = chinaumsGuaranteePayConfirmsVO.getStatus();
                finishedAt = chinaumsGuaranteePayConfirmsVO.getFinishedAt();
            } catch (Exception exception) {
                return;
            }
        } else {
            if (StringUtils.isEmpty(subaccount.getExternalId())) {
                return;
            }
            JSONObject params = new JSONObject();
            params.put("settOrderNo", subaccount.getExternalId());
            JSONObject result = byxChinaumsUtil.execute(ByxRouteUtil.ROUTE_WALLET_COMBINED_GUARANTEE_PAYMENTS_CONFIRMS_QUERY, params, JSONObject.class);
            if (result == null || result.get("settStatus") == null || result.get("settDate") == null) {
                return;
            }
            subaccountStatus = result.get("settStatus").toString();
            finishedAt = result.get("settDate").toString();
            // subaccountStatus:　
            //00：未处理
            //01：处理中
            //02：结算成功
            //03：部分结算成功
            //04：结算失败
            switch (subaccountStatus) {
                case "02": subaccountStatus = "succeeded";break;
                case "04": subaccountStatus = "failed";break;
            }
        }
        handleSubaccountStatus(subaccount, subaccountStatus, finishedAt);
    }

    private void handleSubaccountStatus(Subaccount subaccount, String subaccountStatus, String finishedAt) {
        if (subaccountStatus.equals("succeeded")) {
            handleSubaccountStatusSuccess(subaccount, finishedAt);
        } else if (subaccountStatus.equals("failed")) {
            subaccount.setSubaccountState(SubaccountState.SEPARATE_FAIL);
        }
        subaccountRepository.saveAndFlush(subaccount);
    }

    private void handleSubaccountStatusSuccess(Subaccount subaccount, String finishedAt) {
        // 服务费
        if (subaccount.getSubaccountType().equals(SubaccountType.SERVICE_FEE)) {
            handleSubaccountTypeServiceFee(subaccount);
        }
        // 品牌授权费
        else if (subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)) {
            handleSubaccountTypeBrandAuthFee(subaccount);
        }
        // 货款、品牌费、策划费
        else {
            handleSubaccountTypeOtherFee(subaccount, finishedAt);
        }
        subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC);
        subaccount.setSeparateTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt));
        subaccount.setExternalTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt));
        // 查找对应的银联支付单
        ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType());
        if (chinaumsPayment != null) {
            // 处理已确认金额
            chinaumsPayment.setConfirmedAmount(chinaumsPayment.getConfirmedAmount().add(subaccount.getSubaccountAmount()));
            chinaumsPaymentRepository.saveAndFlush(chinaumsPayment);
        }
    }

    private void handleSubaccountTypeOtherFee(Subaccount subaccount, String finishedAt) {
        List<Statement> statementList;
        if (subaccount.getShipping() != null) {
            statementList = statementRepository.findAllByShippingIdAndSubaccountType(subaccount.getShipping().getId(), subaccount.getSubaccountType());
        } else {
            statementList = statementRepository.findAllByOrdersIdAndSubaccountType(subaccount.getOrders().getId(), subaccount.getSubaccountType());
        }
        // 处理预存款账户
        AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO
                .builder()
                .company(statementList.get(0).getCompany())
                .direction(ChangeDirection.ADD)
                .type(AccountChangeType.valueOf(statementList.get(0).getSubaccountType().getValue()))
                .amount(subaccount.getSubaccountAmount())
                .sourceNo(subaccount.getSubaccountNo())
                .sourceCompanyId(subaccount.getSourceCompany().getId())
                .build();
        accountService.intoAccount(accountChangeCreateDTO);
        for (Statement statement : statementList) {
            // 处理对应结算单
            statement.setStatementState(StatementState.RECORDED);
            statement.setSubaccountTime(DateTimeUtils.getLocalDateTimeByRFC3339(finishedAt));
            statementRepository.saveAndFlush(statement);
        }
    }

    private void handleSubaccountTypeBrandAuthFee(Subaccount subaccount) {
        // 处理预存款账户
        AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO
                .builder()
                .company(subaccount.getCompany())
                .direction(ChangeDirection.ADD)
                .type(AccountChangeType.valueOf(SubaccountType.BRAND_AUTH_FEE.getValue()))
                .amount(subaccount.getSubaccountAmount())
                .sourceNo(subaccount.getSubaccountNo())
                .sourceCompanyId(subaccount.getSourceCompany().getId())
                .build();
        accountService.intoAccount(accountChangeCreateDTO);
    }

    private void handleSubaccountTypeServiceFee(Subaccount subaccount) {
        // 通过平台的电子账簿获取企业
        Company company = companyRepository.findByWalletId(chinaumsUtil.getFeeBalanceAcctId());
        if (company != null) {
            AccountChangeCreateDTO accountChangeCreateDTO = AccountChangeCreateDTO
                    .builder()
                    .company(company)
                    .direction(ChangeDirection.ADD)
                    .type(AccountChangeType.valueOf(SubaccountType.SERVICE_FEE.getValue()))
                    .amount(subaccount.getSubaccountAmount())
                    .sourceNo(subaccount.getSubaccountNo())
                    .sourceCompanyId(subaccount.getSourceCompany().getId())
                    .build();
            accountService.intoAccount(accountChangeCreateDTO);
        }
    }


    /**
     * 计算平台分账记录
     *
     * @param statement     结算单
     * @param orderFeeRatio 订单费用比例
     * @param refundAmount  退款金额
     * @return 平台分账记录
     * @author huabiao
     * @create 2022/12/21  15:53
     */
    private Subaccount calculationPlatformServiceFee(Statement statement, OrderFeeRatio orderFeeRatio, BigDecimal refundAmount) {
        // 计算平台服务费
        BigDecimal platformServiceFee;
        // 根据分账类型从订单费用比例中获取
        BigDecimal platformServiceFeeRatio = BigDecimal.ZERO;
        if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
            platformServiceFeeRatio = orderFeeRatio.getSellerServiceCostRatio();
        } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) {
            platformServiceFeeRatio = orderFeeRatio.getBrandServiceCostRatio();
        } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) {
            platformServiceFeeRatio = orderFeeRatio.getDeviseServiceCostRatio();
        }
        if (platformServiceFeeRatio.compareTo(BigDecimal.ZERO) == 1) {
            // statementamount
            platformServiceFee = statement.getOrders().getAmount().add(refundAmount).multiply(platformServiceFeeRatio).setScale(2, BigDecimal.ROUND_UP);
            if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) {
                // 生成平台服务费分账单
                return generatePlatformSubaccount(platformServiceFeeRatio, platformServiceFee, statement.getOrders(), statement.getShipping(), statement.getCompany());
            }
        }
        return null;
    }

    private BigDecimal getCostRatio(Statement statement, OrderFeeRatio orderFeeRatio) {
        BigDecimal costRatio = BigDecimal.ZERO;
        if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
            costRatio = BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio());
        } else if (statement.getSubaccountType().equals(SubaccountType.BRAND_FEE)) {
            costRatio = orderFeeRatio.getBrandCostRatio();
        } else if (statement.getSubaccountType().equals(SubaccountType.DEVISE_FEE)) {
            costRatio = orderFeeRatio.getDeviseCostRatio();
        }
        return costRatio;
    }

    /**
     * 是否最后分账
     *
     * @param shipping 发货单
     * @return TRUE:是;FALSE:否
     * @author huabiao
     * @create 2023/1/5  10:55
     */
    private Boolean isFinallySubaccount(Shipping shipping) {
        Boolean isFinallySubaccount = true;
        Order orders = shipping.getOrders();
        for (Shipping ordersShipping : orders.getShippings()) {
            if (ordersShipping != shipping && BooleanUtils.isFalse(ordersShipping.getIsSeparateAccounts())) {
                isFinallySubaccount = false;
            }
        }
        return isFinallySubaccount;
    }

    /**
     * 根据发货单更新分账状态
     *
     * @param shipping 发货单
     * @description
     * @author huabiao
     * @create 2023/1/5  15:31
     */
    private void updateIsSeparateAccountsByShipping(Shipping shipping) {
        Order order = shipping.getOrders();
        // 更新发货单已分账
        shippingRepository.updateIsSeparateAccountsById(shipping.getId());
        // 判断该订单是否已分账结束
        long unSubaccountShipping = order.getShippings().stream().filter(filterShipping -> !filterShipping.getId().equals(shipping.getId()) && BooleanUtils.isFalse(filterShipping.getIsSeparateAccounts())).count();
        if ((!order.getShippingStatus().equals(ShippingStatus.UN_SHIPPED) || !order.getShippingStatus().equals(ShippingStatus.PARTIAL_SHIPPED)) && unSubaccountShipping == 0) {
            orderRepository.updateIsSeparateAccountsById(order.getId());
        }
    }

    /**
     * 创建分账
     *
     * @param order         订单
     * @param paymentMethod 支付方式
     * @description 调用银联创建分账接口分账
     * @author huabiao
     * @create 2023/2/6  17:16
     */
    @Transactional(rollbackFor = YnceErrorException.class)
    public void createSubaccountByOrder(Order order, PaymentMethod paymentMethod) {
        // 获取分账记录
        List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId());
        if (CollectionUtils.isNotEmpty(subaccountList)) {
            // 清除失败的分账记录
            subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL));
        }
        // 判断是否已分账
        if (checkIsSubaccountOrder(subaccountList)) {
            // 更新订单已分账
            finishOrderSubaccount(order);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，分账单已存在，更新订单为已分账", order.getSn()));
            return;
        }
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 获取所有结算单(包含正常订单和退货退款)
        List<Statement> allStatementList = getStatementList(order);
        if (allStatementList == null) return;
        List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>();
        // 正常订单结算单
        List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList());
        // 退货退款结算单
        List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList());
        // 平台服务费分账记录
        List<Subaccount> platformSubaccountList = new ArrayList<>();
        // 品牌授权费记录
        List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>();
        // 新创建分账记录
        List<Subaccount> newSubaccountList = new ArrayList<>();
        for (Statement statement : statementList) {
            // 退款金额
            BigDecimal refundAmount = BigDecimal.ZERO;
            // 退款品牌授权费
            BigDecimal refundBrandAuthFee = BigDecimal.ZERO;
            // 该结算单对应的退款结算单
            List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList());
            // 查询所有已完成售后单
            List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED);
            if (CollectionUtils.isNotEmpty(afterSaleList)) {
                if (CollectionUtils.isNotEmpty(afterSaleStatementList)) {
                    // 若存在退款结算单，需判断单据数量是否一致（注意:可能存在非售后途径退款）
                    if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) {
                        writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo()));
                        return;
                    }
                    for (Statement afterSaleStatement : afterSaleStatementList) {
                        refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount());
                        refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add));
                    }
                } else {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo()));
                    return;
                }
            } else {
                refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            }

            // 平台服务费
            BigDecimal platformServiceFee = BigDecimal.ZERO;
            // 拼接平台服务费分账
            Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee));
            if (platformSubaccount != null) {
                platformSubaccountList.add(platformSubaccount);
                platformServiceFee = platformSubaccount.getSubaccountAmount();
            }
            // 判断是否存在分账记录（根据分账企业和分账类型）
            Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null);
            if (subaccount != null) {
                // 若是未分账则调用银联接口
                if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                    handleSubaccountStatus(subaccount, true);
                }
                continue;
            }

            // 拼接分账记录数据
            subaccount = new Subaccount();
            subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
            subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null));
            // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
                // 品牌授权费
                BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add);
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee));
                if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                    subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio());
                }
                subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee));
                // 拼接品牌授权费
                for (StatementLine statementLine : statement.getStatementLine()) {
                    BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee();
                    // 获取对应的退款结算单项
                    for (Statement typeAfterSaleStatement : afterSaleStatementList) {
                        StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null);
                        if (typeAfterSaleStatementLine != null) {
                            lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee());
                        }
                    }
                    BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null);
                    if (brandAuthFeeDTO != null) {
                        brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee));
                    } else {
                        brandAuthFeeDTO = new BrandAuthFeeDTO();
                        brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId());
                        brandAuthFeeDTO.setAmount(lineBrandAuthFee);
                        brandAuthFeeDTOList.add(brandAuthFeeDTO);
                    }
                }
            }
            // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费
            else {
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee));
            }
            // 当分账金额小于等于0时跳过
            if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) {
                continue;
            }
            subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio));
            subaccount.setSubaccountType(statement.getSubaccountType());
            subaccount.setOrders(statement.getOrders());
            subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
            subaccount.setSourceCompany(order.getBuyerCompany());
            subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount));
            if (platformSubaccount != null) {
                subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
            }
            newSubaccountList.add(subaccount);
        }

        // 品牌授权费
        if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
            for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) {
                // 判断该品牌授权费是否存在分账记录(根据品牌ID+分账类型)
                Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null);
                if (subaccount != null) {
                    // 若是未分账则调用银联接口
                    if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                        handleSubaccountStatus(subaccount, true);
                    }
                    continue;
                }
                // 获取品牌
                Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null);
                // 平台服务费
                BigDecimal platformServiceFee = BigDecimal.ZERO;
                // 品牌授权费的平台服务费分账记录
                Subaccount platformSubaccount = null;
                // 获取订单项费用比例
                OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null);
                if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) {
                    // 计算平台服务费
                    platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP);
                    // 拼接平台服务费分账
                    if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) {
                        platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, brand.getCompany());
                        if (platformSubaccount != null) {
                            platformSubaccountList.add(platformSubaccount);
                            platformServiceFee = platformSubaccount.getSubaccountAmount();
                        }
                    }
                }

                BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee);
                if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) {
                    // 拼接分账记录
                    subaccount = new Subaccount();
                    subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
                    subaccount.setCompany(brand.getCompany());
                    subaccount.setSubaccountAmount(subaccountAmount);
                    subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount());
                    subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE);
                    subaccount.setOrders(order);
                    subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
                    subaccount.setSourceCompany(order.getBuyerCompany());
                    subaccount.setBrandId(brandAuthFeeDTO.getBrandId());
                    if (platformSubaccount != null) {
                        subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                        subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
                    }
                    newSubaccountList.add(subaccount);
                }
            }
        }

        // 获取已生成的平台服务费分账记录
        List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(platformSubaccounts)) {
            for (Subaccount platformSubaccount : platformSubaccounts) {
                handleSubaccountStatus(platformSubaccount, true);
            }
        } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) {
            newSubaccountList.addAll(platformSubaccountList);
        }
        // 对所有的分账单进行统计处理，同一企业的合并进行分账创建
        if (CollectionUtils.isNotEmpty(newSubaccountList)) {
            // 获取平台分账记录
            List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) {
                BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 商品扩展字段
                ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), noCompanySubaccountAmount));
                // 自定义参数
                JSONObject metadata = new JSONObject();
                metadata.put("companyId", null);
                metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ","));
                // 拼接分账参数
                ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO
                        .builder()
                        .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId())
                        .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue())
                        .remark(null)
                        .extra(chinaumsGuaranteePayExtraDTO)
                        .metadata(metadata)
                        .build();
                chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO);
            }
            // 获取非平台分账记录
            List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList());
            Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany));
            for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) {
                Company company = companyListEntry.getKey();
                List<Subaccount> companySubaccountList = companyListEntry.getValue();
                // 计算该企业总分账金额
                BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 商品扩展字段
                ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByOrder(order.getOrderItems(), order.getSn(), order.getAmount(), companySubaccountAmount));
                // 自定义参数
                JSONObject metadata = new JSONObject();
                metadata.put("companyId", company.getId());
                metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ","));
                // 判断该企业是否已认证
                if (StringUtils.isBlank(company.getWalletId())) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s]，[%s]暂未认证银联", order.getSn(), company.getName()));
                    return;
                }
                // 拼接分账参数
                ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO
                        .builder()
                        .recvBalanceAcctId(company.getWalletId())
                        .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue())
                        .remark(null)
                        .extra(chinaumsGuaranteePayExtraDTO)
                        .metadata(metadata)
                        .build();
                chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO);
            }
        }
        if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) {
            // 已分账金额
            BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 待分账金额
            BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 获取所有的退款金额
            List<Refund> refundList = refundRepository.findAllByOrdersId(order.getId());
            BigDecimal refundAmount = CollectionUtils.isNotEmpty(refundList) ? refundList.stream().map(Refund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO;
            // 判断分账总金额是否正确
            if ((allocatedAmount.add(totalSubaccountAmount)).compareTo((order.getPayAmount().subtract(refundAmount))) != 0) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，分账总金额与订单支付金额不一致", order.getSn()));
                return;
            }
            // 银联所属企业
            Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(order.getConsignmentCompany().getId()) : companyRepository.getOne(order.getSellerCompany().getId());
            // 根据支付方式获取对应分账电子账簿ID
            String chinaumsBalanceAcctId;
            if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) {
                chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId());
            } else {
                chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId());
            }
            if (StringUtils.isBlank(chinaumsBalanceAcctId)) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，[%s]分账电子账簿ID为空", order.getSn(), chinaumsCompany.getName()));
                return;
            }
            // 查询平台分账银联电子账簿是否金额充足
            BigDecimal balance;
            try {
                BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId);
                balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            } catch (Exception exception) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，[%s]分账电子账簿金额查询报错", order.getSn(), chinaumsCompany.getName()));
                return;
            }
            // 判断余额是否充足
            if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，[%s]分账电子账簿金额不足", order.getSn(), chinaumsCompany.getName()));
                return;
            }
            // 分账创建
            ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO
                    .builder()
                    .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ"))
                    .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                    .payBalanceAcctId(chinaumsBalanceAcctId)
                    .transferParams(chinaumsTransferParamsDTOList)
                    .remark(null)
                    .build();
            ChinaumsAllocationsVO chinaumsAllocationsVO;
            try {
                chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO);
            } catch (Exception exception) {
                // TODO 这里需要调用平台订单号查询是否调用成功
                log.error("订单创建分账异常，订单号" + order.getSn() + "，分账单号" + chinaumsAllocationsDTO.getOutOrderNo());
                return;
            }
            // 循环查询子订单分账是否成功
            for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) {
                // 先判断是否为平台电子账簿
                if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) {
                    // 企业为空时获取平台分账记录
                    List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList());
                    for (Subaccount subaccount : platformFeeSubaccountList) {
                        subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId());
                        subaccountRepository.saveAndFlush(subaccount);
                        handleSubaccountStatus(subaccount, true);
                    }
                } else {
                    // 根据收款电子账簿ID查询
                    Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId());
                    if (company == null) {
                        continue;
                    }
                    // 获取对应的企业分账记录
                    List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList());
                    for (Subaccount subaccount : companySubaccountList) {
                        subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId());
                        subaccountRepository.saveAndFlush(subaccount);
                        handleSubaccountStatus(subaccount, true);
                    }
                }
                writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsTransferResultsVO.getTransferId()));
            }
            subaccountList.addAll(newSubaccountList);
        }
        // 判断是否已分账
        if (checkIsSubaccountOrder(subaccountList)) {
            // 更新订单已分账
            finishOrderSubaccount(order);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，分账单已存在，更新订单为已分账", order.getSn()));
            return;
        }
    }

    /**
     * 创建分账
     *
     * @return
     * @description 相同收款方必须合并处理
     * @author huabiao
     * @create 2023/2/6  17:16
     */
    public void createSubaccountByShipping(Shipping shipping, PaymentMethod paymentMethod) {
        // 自定义参数
        JSONObject metadata = new JSONObject();
        metadata.put("shippingSn", shipping.getShippingSn());
        Order order = shipping.getOrders();
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 获取分账记录
        List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId());
        if (CollectionUtils.isNotEmpty(subaccountList)) {
            // 清除失败的分账记录
            subaccountList.removeIf(subaccount -> subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_FAIL));
        }
        // 判断发货单是否已分账
        if (checkIsSubaccountByShipping(subaccountList)) {
            // 更新发货单已分账
            updateIsSeparateAccountsByShipping(shipping);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，分账单已存在，更新发货单为已分账", order.getSn(), shipping.getShippingSn()));
            // 判断订单是否已分账
            if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) {
                orderRepository.updateIsSeparateAccountsById(order.getId());
            }
            return;
        }
        List<ChinaumsTransferParamsDTO> chinaumsTransferParamsDTOList = new ArrayList<>();
        // 获取结算单
        List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER);
        // 获取退款结算单
        List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES);
        // 平台服务费分账记录
        List<Subaccount> platformSubaccountList = new ArrayList<>();
        // 品牌授权费记录
        List<BrandAuthFeeDTO> brandAuthFeeDTOList = new ArrayList<>();
        // 新创建分账记录
        List<Subaccount> newSubaccountList = new ArrayList<>();
        for (Statement statement : statementList) {
            // 获取结算单对应的退款结算单
            List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList());
            // 退款金额
            BigDecimal refundAmount = BigDecimal.ZERO;
            // 退款品牌授权费
            BigDecimal refundBrandAuthFee = BigDecimal.ZERO;
            // 获取售后单
            List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED);
            if (CollectionUtils.isNotEmpty(afterSaleStatementList)) {
                if (afterSaleList.size() != afterSaleStatementList.size()) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo()));
                    return;
                }
                for (Statement afterSaleStatement : afterSaleStatementList) {
                    refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount());
                    refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add));
                }
            } else {
                // 当不存在退款结算单时，需判断是否还未生成
                if (CollectionUtils.isNotEmpty(afterSaleList)) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo()));
                    return;
                }
            }

            // 平台服务费
            BigDecimal platformServiceFee = BigDecimal.ZERO;
            // 拼接平台服务费分账
            Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee));
            if (platformSubaccount != null) {
                platformSubaccountList.add(platformSubaccount);
                platformServiceFee = platformSubaccount.getSubaccountAmount();
            }

            // 判断是否存在分账记录（根据分账企业和分账类型）
            Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null);
            if (subaccount != null) {
                // 若是未分账则调用银联接口
                if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                    handleSubaccountStatus(subaccount, false);
                }
                continue;
            }
            subaccount = new Subaccount();
            subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
            subaccount.setCompany(statement.getCompany());
            subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio));

            // 保存品牌授权费
            BigDecimal brandAuthFee = BigDecimal.ZERO;
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add);
                subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio());
                subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee));
            }
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
                // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 +  退款品牌授权费
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee));
                // 拼接品牌授权费
                for (StatementLine statementLine : statement.getStatementLine()) {
                    BigDecimal lineBrandAuthFee = statementLine.getBrandAuthFee();
                    // 获取对应的退款结算单项
                    for (Statement typeAfterSaleStatement : afterSaleStatementList) {
                        StatementLine typeAfterSaleStatementLine = typeAfterSaleStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getOrderItem().getId().equals(statementLine.getOrderItem().getId())).findFirst().orElse(null);
                        if (typeAfterSaleStatementLine != null) {
                            lineBrandAuthFee = lineBrandAuthFee.add(typeAfterSaleStatementLine.getBrandAuthFee());
                        }
                    }
                    BrandAuthFeeDTO brandAuthFeeDTO = brandAuthFeeDTOList.stream().filter(filterBrandAuthFeeDTO -> filterBrandAuthFeeDTO.getBrandId().equals(statementLine.getOrderItem().getBrandId())).findFirst().orElse(null);
                    if (brandAuthFeeDTO != null) {
                        brandAuthFeeDTO.setAmount(brandAuthFeeDTO.getAmount().add(lineBrandAuthFee));
                    } else {
                        brandAuthFeeDTO = new BrandAuthFeeDTO();
                        brandAuthFeeDTO.setBrandId(statementLine.getOrderItem().getBrandId());
                        brandAuthFeeDTO.setAmount(lineBrandAuthFee);
                        brandAuthFeeDTOList.add(brandAuthFeeDTO);
                    }
                }
            } else {
                // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee));
            }
            // 当分账金额小于等于0时跳过
            if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) {
                continue;
            }
            subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount));
            if (platformSubaccount != null) {
                subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
            }
            subaccount.setSubaccountType(statement.getSubaccountType());
            subaccount.setOrders(statement.getOrders());
            subaccount.setShipping(statement.getShipping());
            subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
            subaccount.setSourceCompany(order.getBuyerCompany());
            newSubaccountList.add(subaccount);

        }

        // 品牌授权费
        if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
            for (BrandAuthFeeDTO brandAuthFeeDTO : brandAuthFeeDTOList) {
                // 判断该品牌授权费是否存在分账记录(根据品牌ID和分账类型)
                Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId() != null && filterSubaccount.getBrandId().equals(brandAuthFeeDTO.getBrandId()) && filterSubaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).findFirst().orElse(null);
                if (subaccount != null) {
                    // 若是未分账则调用银联接口
                    if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                        handleSubaccountStatus(subaccount, true);
                    }
                    continue;
                }
                // 获取品牌
                Brand brand = brandRepository.findById(brandAuthFeeDTO.getBrandId()).orElse(null);
                // 平台服务费
                BigDecimal platformServiceFee = BigDecimal.ZERO;
                // 平台服务费比例
                BigDecimal platformServiceCostRatio = BigDecimal.ZERO;
                // 获取订单项费用比例
                OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(brandAuthFeeDTO.getBrandId())).findFirst().orElse(null);
                if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) {
                    // 计算平台服务费
                    platformServiceFee = brandAuthFeeDTO.getAmount().multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP);
                    platformServiceCostRatio = orderItemFeeRatio.getBrandAuthCostServiceCostRatio();
                    // 拼接平台服务费分账
                    if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) {
                        Subaccount platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, brand.getCompany());
                        if (platformSubaccount != null) {
                            platformSubaccountList.add(platformSubaccount);
                        }
                    }
                }

                BigDecimal subaccountAmount = brandAuthFeeDTO.getAmount().subtract(platformServiceFee);
                if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) {
                    // 拼接分账记录
                    subaccount = new Subaccount();
                    subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
                    subaccount.setCompany(brand.getCompany());
                    subaccount.setSubaccountAmount(subaccountAmount);
                    subaccount.setSubaccountTotalAmount(brandAuthFeeDTO.getAmount());
                    subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE);
                    subaccount.setOrders(order);
                    subaccount.setShipping(shipping);
                    subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
                    subaccount.setSourceCompany(order.getBuyerCompany());
                    subaccount.setBrandId(brandAuthFeeDTO.getBrandId());
                    if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) {
                        subaccount.setPlatformServiceCostRatio(platformServiceCostRatio);
                        subaccount.setPlatformServiceFee(platformServiceFee);
                    }
                    newSubaccountList.add(subaccount);
                }
            }
        }

        // 获取已生成的平台服务费分账记录
        List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(platformSubaccounts)) {
            for (Subaccount platformSubaccount : platformSubaccounts) {
                handleSubaccountStatus(platformSubaccount, true);
            }
        } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) {
            newSubaccountList.addAll(platformSubaccountList);
        }

        // 对所有的分账单进行统计处理，同一企业的合并进行分账创建
        if (CollectionUtils.isNotEmpty(newSubaccountList)) {
            // 获取平台分账记录
            List<Subaccount> noCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(noCompanySubaccountList)) {
                BigDecimal noCompanySubaccountAmount = noCompanySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 商品扩展字段
                ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), noCompanySubaccountAmount));
                // 自定义参数
                metadata.put("companyId", null);
                metadata.put("subaccountNo", StringUtils.join(noCompanySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ","));
                // 拼接分账参数
                ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO
                        .builder()
                        .recvBalanceAcctId(chinaumsUtil.getFeeBalanceAcctId())
                        .amount(noCompanySubaccountAmount.multiply(new BigDecimal(100)).intValue())
                        .remark(null)
                        .extra(chinaumsGuaranteePayExtraDTO)
                        .metadata(metadata)
                        .build();
                chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO);
            }
            // 获取非平台分账记录
            List<Subaccount> allCompanySubaccountList = newSubaccountList.stream().filter(subaccount -> subaccount.getCompany() != null).collect(Collectors.toList());
            Map<Company, List<Subaccount>> companySubaccountListMap = allCompanySubaccountList.stream().collect(Collectors.groupingBy(Subaccount::getCompany));
            for (Map.Entry<Company, List<Subaccount>> companyListEntry : companySubaccountListMap.entrySet()) {
                Company company = companyListEntry.getKey();
                List<Subaccount> companySubaccountList = companyListEntry.getValue();
                // 计算该企业总分账金额
                BigDecimal companySubaccountAmount = companySubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 商品扩展字段
                ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), companySubaccountAmount));
                // 自定义参数
                metadata.put("companyId", company.getId());
                metadata.put("subaccountNo", StringUtils.join(companySubaccountList.stream().map(Subaccount::getSubaccountNo).collect(Collectors.toList()), ","));
                // 判断该企业是否已认证
                if (StringUtils.isBlank(company.getWalletId())) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，[%s]暂未认证银联", order.getSn(), shipping.getShippingSn(), company.getName()));
                    return;
                }
                // 拼接分账参数
                ChinaumsTransferParamsDTO chinaumsTransferParamsDTO = ChinaumsTransferParamsDTO
                        .builder()
                        .recvBalanceAcctId(company.getWalletId())
                        .amount(companySubaccountAmount.multiply(new BigDecimal(100)).intValue())
                        .remark(null)
                        .extra(chinaumsGuaranteePayExtraDTO)
                        .metadata(metadata)
                        .build();
                chinaumsTransferParamsDTOList.add(chinaumsTransferParamsDTO);
            }
        }
        if (CollectionUtils.isNotEmpty(chinaumsTransferParamsDTOList)) {
            // 已分账金额
            BigDecimal allocatedAmount = subaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 待分账金额
            BigDecimal totalSubaccountAmount = newSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 判断(已分账金额+待分账金额)和发货单金额是否一致
            if ((allocatedAmount.add(totalSubaccountAmount)).compareTo(shipping.getPayAmount()) != 0) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，分账总金额与发货单支付金额不一致", order.getSn(), shipping.getShippingSn()));
                return;
            }
            // 银联所属企业
            Company chinaumsCompany = order.getConsignmentCompany() != null ? companyRepository.getOne(shipping.getOrders().getConsignmentCompany().getId()) : companyRepository.getOne(shipping.getOrders().getSellerCompany().getId());
            // 根据支付方式获取对应分账电子账簿ID
            String chinaumsBalanceAcctId;
            if (paymentMethod.equals(PaymentMethod.CREDIT_PAY)) {
                chinaumsBalanceAcctId = chinaumsUtil.getChinaumsCreditBalanceAcctId(chinaumsCompany.getId());
            } else {
                chinaumsBalanceAcctId = chinaumsUtil.getBalanceAcctId(chinaumsCompany.getId());
            }
            if (StringUtils.isBlank(chinaumsBalanceAcctId)) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，[%s]分账电子账簿ID为空", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName()));
                return;
            }
            // 查询平台分账银联电子账簿是否金额充足
            BigDecimal balance;
            try {
                BalanceAcctsVO balanceAcctsVO = walletService.balanceAcctsQryByAcctId(chinaumsBalanceAcctId);
                balance = new BigDecimal(balanceAcctsVO.getSettledAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            } catch (Exception exception) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，[%s]分账电子账簿金额查询报错", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName()));
                return;
            }
            // 判断余额是否充足
            if (balance.compareTo(BigDecimal.ZERO) < 1 || balance.compareTo(totalSubaccountAmount) == -1) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，[%s]分账电子账簿金额不足", order.getSn(), shipping.getShippingSn(), chinaumsCompany.getName()));
                return;
            }
            // 分账创建
            ChinaumsAllocationsDTO chinaumsAllocationsDTO = ChinaumsAllocationsDTO
                    .builder()
                    .outOrderNo(sequenceUtil.getNextSequenceNumber("FZ"))
                    .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                    .payBalanceAcctId(chinaumsBalanceAcctId)
                    .transferParams(chinaumsTransferParamsDTOList)
                    .remark(null)
                    .build();
            ChinaumsAllocationsVO chinaumsAllocationsVO;
            try {
                chinaumsAllocationsVO = walletService.createSubaccount(chinaumsAllocationsDTO);
            } catch (Exception exception) {
                // 当请求返回异常时，直接跳过
                return;
            }
            // 循环查询子订单分账是否成功
            for (ChinaumsTransferResultsVO chinaumsTransferResultsVO : chinaumsAllocationsVO.getTransferResults()) {
                // 先判断是否为平台电子账簿
                if (chinaumsTransferResultsVO.getRecvBalanceAcctId().equals(chinaumsUtil.getFeeBalanceAcctId())) {
                    // 企业为空时获取平台分账记录
                    List<Subaccount> platformFeeSubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() == null).collect(Collectors.toList());
                    for (Subaccount subaccount : platformFeeSubaccountList) {
                        subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId());
                        subaccountRepository.saveAndFlush(subaccount);
                        handleSubaccountStatus(subaccount, true);
                    }
                } else {
                    // 根据收款电子账簿ID查询
                    Company company = companyRepository.findByWalletId(chinaumsTransferResultsVO.getRecvBalanceAcctId());
                    if (company == null) {
                        continue;
                    }
                    // 获取对应的企业分账记录
                    List<Subaccount> companySubaccountList = newSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(company)).collect(Collectors.toList());
                    for (Subaccount subaccount : companySubaccountList) {
                        subaccount.setExternalId(chinaumsTransferResultsVO.getTransferId());
                        subaccountRepository.saveAndFlush(subaccount);
                        handleSubaccountStatus(subaccount, true);
                    }
                }
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), shipping.getShippingSn(), chinaumsTransferResultsVO.getTransferId()));
            }
        }
        // 判断是否分账结束
        if (checkIsSubaccountByShipping(subaccountList)) {
            updateIsSeparateAccountsByShipping(shipping);
            // 判断订单是否已分账
            if (checkIsSubaccountOrder(subaccountRepository.findAllByOrdersId(order.getId()))) {
                orderRepository.updateIsSeparateAccountsById(order.getId());
            }
        }
    }

    /**
     * 合并消费担保确认
     *
     * @return
     * @description
     * @author huabiao
     * @create 2023/2/6  17:17
     */
    @Transactional(rollbackFor = YnceErrorException.class)
    public void confirmsCombinedGuaranteeByOrder(Order order) {
        // 获取银联支付单
        List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order);
        // 获取分账记录
        List<Subaccount> subaccountList = getSubaccountListAndCheck(order);
        if (subaccountList == null) {
            return;
        }
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 获取所有结算单(包含正常订单和退货退款)
        List<Statement> allStatementList = getStatementList(order);
        if (allStatementList == null) {
            return;
        }
        // 正常订单结算单
        List<Statement> statementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.NORMALORDER)).collect(Collectors.toList());
        // 退货退款结算单
        List<Statement> allAfterSaleStatementList = allStatementList.stream().filter(statement -> statement.getStatementType().equals(StatementType.AFTERSALES)).collect(Collectors.toList());
        // 平台服务费分账记录
        List<Subaccount> platformSubaccountList = getSubaccountListAndCheck(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList);
        if (platformSubaccountList == null) {
            return;
        }

        // 品牌授权费
        setBrandInfoToSubAccountList(order, chinaumsPaymentList, subaccountList, orderFeeRatio, statementList, allAfterSaleStatementList, platformSubaccountList);

        // 获取已生成的平台服务费分账记录
        List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(platformSubaccounts)) {
            log.error("分账的公司信息为空.");
//            for (Subaccount platformSubaccount : platformSubaccounts) {
//                handleSubaccountStatus(platformSubaccount, false);
//            }
        } //else
        if (CollectionUtils.isNotEmpty(platformSubaccountList)) {
            // 获取平台电子账簿ID
            String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId();
            // 获取平台服务费对应的银联支付单
            ChinaumsPayment chinaumsPayment = chinaumsPaymentRepository.findFirstByOrdersIdAndRecvBalanceAcctId(order.getId(), balanceAcctId);
            if (chinaumsPayment != null) {
                // 平台服务费退款金额
                BigDecimal platformServiceFeeRefundAmount = BigDecimal.ZERO;
                // 获取银联退款单
                List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
                if (CollectionUtils.isNotEmpty(chinaumsRefundList)) {
                    platformServiceFeeRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                // 分账记录总平台服务费
                BigDecimal totalPlatformServiceFee = platformSubaccountList.stream().map(subaccount -> subaccount.getSubaccountAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 银联单据计算平台服务费
                BigDecimal platformServiceFee = chinaumsPayment.getAmount().subtract(platformServiceFeeRefundAmount);
                // 只有当分账记录的金额和银联支付单金额一致才进行分账
                if (totalPlatformServiceFee.compareTo(platformServiceFee) == 0) {

//                    Company platformCompany = companyRepository.findByWalletId(balanceAcctId);
                    BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(order.getSellerCompany());
                    List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>();
                    ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO
                            .builder()
                            .profitSharingWalletId(balanceAcctId)
                            .profitSharingAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue())
                            .build();
                    confirmsDetailDTOList.add(confirmsDetailDTO);
                    ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO
                            .builder()
                            .mctOrderNo(platformSubaccountList.get(0).getSubaccountNo())
                            .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId())
                            .platformWalletId(balanceAcctId)
                            .settAmt(platformServiceFee.multiply(new BigDecimal(100)).longValue())
                            .isFinished("Y")
                            .bizType("030001") //担保支付 030001
                            .profitSharingRuleId(businessRelations.getChinaumsRuleId())
                            .profitSharingList(confirmsDetailDTOList)
                            .build();

                    try {
                        String externalId = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO);
                        writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), externalId));
                        if (StringUtils.isEmpty(externalId)) {
                            log.error("银联结算接口调用失败.");
                            throw new YnceErrorException("银联结算接口调用失败");
                        }
                        for (Subaccount subaccount : platformSubaccountList) {
                            subaccount.setExternalId(externalId);
                            subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC);
                            subaccountRepository.saveAndFlush(subaccount);
//                            handleSubaccountStatus(subaccount, false);
                        }
                        subaccountList.addAll(platformSubaccountList);
                    } catch (Exception e) {
                        // TODO 当请求返回异常时，直接跳过
                        log.error(e.getMessage());
                    }
                } else {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单失败,分账金额与银联支付单剩余金额不一致。", order.getSn()));
                }
            }
        }
        // 判断是否分账结束
        if (checkIsSubaccountOrder(subaccountList)) {
            // 更新订单已分账
            finishOrderSubaccount(order);
        }
    }

    private void setBrandInfoToSubAccountList(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList, OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList, List<Subaccount> platformSubaccountList) {
        if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
            // 获取品牌授权费银联支付单
            List<ChinaumsPayment> brandAuthFeeChinaumsPaymentList = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList());
            // 获取品牌授权费的分账记录
            List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList());
            for (ChinaumsPayment chinaumsPayment : brandAuthFeeChinaumsPaymentList) {
                // 获取货款结算单，并根据品牌ID获取对应的品牌授权费
                Statement statement = statementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null);
                // 品牌授权费
                BigDecimal brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 品牌授权费退款金额
                BigDecimal brandAuthFeeRefundAmount = BigDecimal.ZERO;
                // 获取退款货款结算单，并根据品牌ID获取对应的退款品牌授权费
                List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(afterSaleStatementList)) {
                    for (Statement afterSaleStatement : afterSaleStatementList) {
                        brandAuthFeeRefundAmount = brandAuthFeeRefundAmount.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add));
                    }
                }
                // 获取分账企业
                Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId());
                // 平台服务费
                BigDecimal platformServiceFee;
                // 平台服务费分账记录
                Subaccount platformSubaccount = null;
                // 获取订单项费用比例
                OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null);
                if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) {
                    // 计算平台服务费
                    platformServiceFee = brandAuthFee.subtract(brandAuthFeeRefundAmount).multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP);
                    // 拼接平台服务费分账
                    if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1) {
                        platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, null, company);
                        if (platformSubaccount != null) {
                            platformSubaccountList.add(platformSubaccount);
                        }
                    }
                }

                // 判断该品牌授权费是否存在分账记录(根据品牌ID)
                Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null);
                if (subaccount != null) {
                    // 若是未分账则调用银联接口
                    if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                        handleSubaccountStatus(subaccount, false);
                    }
                    continue;
                }
                // 分账金额 = 银联支付单金额 - 银联退款单金额
                BigDecimal subaccountAmount = chinaumsPayment.getAmount();
                // 获取银联退款单
                List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
                if (CollectionUtils.isNotEmpty(chinaumsRefundList)) {
                    for (ChinaumsRefund chinaumsRefund : chinaumsRefundList) {
                        subaccountAmount = subaccountAmount.subtract(chinaumsRefund.getAmount());
                    }
                }
                if (subaccountAmount.compareTo(BigDecimal.ZERO) == 1) {
                    // 拼接分账记录
                    subaccount = new Subaccount();
                    subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
                    subaccount.setCompany(company);
                    subaccount.setSubaccountAmount(subaccountAmount);
                    subaccount.setSubaccountTotalAmount(subaccount.getSubaccountAmount());
                    subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE);
                    subaccount.setOrders(order);
                    subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
                    subaccount.setSourceCompany(order.getBuyerCompany());
                    subaccount.setBrandId(chinaumsPayment.getBrandId());
                    if (platformSubaccount != null) {
                        subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                        subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
                    }

                    // 获取平台电子账簿ID
                    String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId();
//                    Company platformCompany = companyRepository.findByWalletId(balanceAcctId);
                    BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(order.getSellerCompany());
                    List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>();
                    ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO
                            .builder()
                            .profitSharingWalletId(businessRelations.getSourceCompany().getWalletId())
                            .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue())
                            .build();
                    confirmsDetailDTOList.add(confirmsDetailDTO);
                    ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO
                            .builder()
                            .mctOrderNo(subaccount.getSubaccountNo())
                            .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId())
                            .platformWalletId(balanceAcctId)
                            .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue())
                            .isFinished("N")
                            .bizType("030001") //担保支付 030001
                            .profitSharingRuleId(businessRelations.getChinaumsRuleId())
                            .profitSharingList(confirmsDetailDTOList)
                            .build();


                    String settOrderNo;
                    try {
                        settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO);
                    } catch (Exception exception) {
                        // 当请求返回异常时，直接跳过
                        continue;
                    }
                    subaccount.setExternalId(settOrderNo);
                    subaccountRepository.saveAndFlush(subaccount);
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo));
                    handleSubaccountStatus(subaccount, false);
                    brandAuthFeeSubaccountList.add(subaccount);
                }
            }
            subaccountList.addAll(brandAuthFeeSubaccountList);
        }
    }

    private Map<String, BigDecimal> calRefundFee(Order order, List<Statement> allAfterSaleStatementList, Statement statement) {
        Map<String, BigDecimal> refundFeeMap = new HashMap<>();
        // 退款金额
        BigDecimal refundAmount = BigDecimal.ZERO;
        // 退款品牌授权费
        BigDecimal refundBrandAuthFee = BigDecimal.ZERO;
        // 该结算单对应的退款结算单
        List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList());
        // 查询所有已完成售后单
        List<AfterSale> afterSaleList = afterSaleRepository.findAllByOrdersIdAndAfterSaleStatus(order.getId(), AfterSaleStatus.COMPLETED);
        if (CollectionUtils.isNotEmpty(afterSaleList)) {
            if (CollectionUtils.isEmpty(afterSaleStatementList)) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo()));
                return null;
            }
            // 若存在退款结算单，需判断单据数量是否一致（注意，可能存在非售后途径退款）
            if (afterSaleList.size() != afterSaleStatementList.stream().filter(filterStatement -> filterStatement.getAfterSale() != null).count()) {
                writeSeparateLog(String.format("[分账][生成][普通订单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), statement.getStatementNo()));
                return null;
            }
            for (Statement afterSaleStatement : afterSaleStatementList) {
                refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount());
                refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            }
        } else {
            refundAmount = afterSaleStatementList.stream().map(Statement::getStatementAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        refundFeeMap.put("refundAmount", refundAmount);
        refundFeeMap.put("refundBrandAuthFee", refundBrandAuthFee);
        return refundFeeMap;
    }

    private List<Subaccount> getSubaccountListAndCheck(Order order, List<ChinaumsPayment> chinaumsPaymentList, List<Subaccount> subaccountList,
                                                       OrderFeeRatio orderFeeRatio, List<Statement> statementList, List<Statement> allAfterSaleStatementList) {
        List<Subaccount> platformSubaccountList = new ArrayList<>();
        for (Statement statement : statementList) {
            // 计算 退款金额  和   退款品牌授权费
            Map<String, BigDecimal> refundFeeMap = this.calRefundFee(order, allAfterSaleStatementList, statement);
            if (refundFeeMap == null) {
                return null;
            }
            // 退款金额
            BigDecimal refundAmount = refundFeeMap.get("refundAmount");
            // 退款品牌授权费
            BigDecimal refundBrandAuthFee = refundFeeMap.get("refundBrandAuthFee");

            // 平台服务费
            BigDecimal platformServiceFee = BigDecimal.ZERO;
            // 拼接平台服务费分账
            Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount.add(refundBrandAuthFee));
            if (platformSubaccount != null) {
                platformSubaccountList.add(platformSubaccount);
                platformServiceFee = platformSubaccount.getSubaccountAmount();
            }
            // 判断是否存在分账记录（根据分账企业和分账类型）
            Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null);
            if (subaccount != null) {
                // 若是未分账则调用银联接口
                if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                    handleSubaccountStatus(subaccount, false);
                }
                if (platformSubaccount != null && platformSubaccount.getSubaccountAmount().compareTo(subaccount.getPlatformServiceFee()) != 0) {
                    platformSubaccount.setSubaccountAmount(subaccount.getPlatformServiceFee());
                    platformSubaccount.setSubaccountTotalAmount(subaccount.getPlatformServiceFee());
                }
                continue;
            }
            // 获取银联支付单
            ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null);
            if (chinaumsPayment == null) {
                continue;
            }
            subaccount = new Subaccount();
            subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
            subaccount.setCompany(companyRepository.findById(statement.getCompany().getId()).orElse(null));

            // 以订单进行分账，则分账金额 = 银联支付单金额
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
                // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 + 退款品牌授权费
                BigDecimal brandAuthFee = statement.getStatementLine().stream().map(statementLine -> statementLine.getBrandAuthFee()).reduce(BigDecimal.ZERO, BigDecimal::add);
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee));
                if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                    subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio());
                }
                subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee));
            } else {
                // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费
                subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee));
            }

            // 根据银联支付单和银联退款单计算最终分账金额
            List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
            BigDecimal chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal finallySubaccountAmount = chinaumsPayment.getAmount().subtract(chinaumsRefundAmount);
            if (finallySubaccountAmount.compareTo(subaccount.getSubaccountAmount()) != 0) {
                BigDecimal balance = subaccount.getSubaccountAmount().subtract(finallySubaccountAmount);
                subaccount.setSubaccountAmount(finallySubaccountAmount);
                // 计算实际服务费
                BigDecimal finallyPlatformSubaccountAmount = BigDecimal.ZERO;
                if (platformSubaccount == null) {
                    finallyPlatformSubaccountAmount.add(balance);
                } else {
                    finallyPlatformSubaccountAmount = platformSubaccount.getSubaccountAmount().add(balance);
                    platformSubaccount.setSubaccountAmount(finallyPlatformSubaccountAmount);
                    platformSubaccount.setSubaccountTotalAmount(finallyPlatformSubaccountAmount);
                }
            }

            subaccount.getSubaccountAmount();
            subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio));
            subaccount.setSubaccountType(statement.getSubaccountType());
            subaccount.setOrders(statement.getOrders());
            subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
            subaccount.setSourceCompany(order.getBuyerCompany());
            subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount));
            if (platformSubaccount != null) {
                subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
            }

            // 获取平台电子账簿ID
            String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId();
//            Company platformCompany = companyRepository.findByWalletId(balanceAcctId);
            BusinessRelations businessRelations = businessRelationsRepository.findFirstBySourceCompany(order.getSellerCompany());
            List<ByxChinaumsGuaranteePayConfirmsDetailDTO> confirmsDetailDTOList = new ArrayList<>();
            ByxChinaumsGuaranteePayConfirmsDetailDTO confirmsDetailDTO = ByxChinaumsGuaranteePayConfirmsDetailDTO
                    .builder()
                    .profitSharingWalletId(businessRelations.getSourceCompany().getWalletId())
                    .profitSharingAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue())
                    .build();
            confirmsDetailDTOList.add(confirmsDetailDTO);
            ByxChinaumsGuaranteePayConfirmsDTO byxChinaumsGuaranteePayConfirmsDTO = ByxChinaumsGuaranteePayConfirmsDTO
                    .builder()
                    .mctOrderNo(subaccount.getSubaccountNo())
                    .oriTransOrderNo(chinaumsPayment.getGuaranteePaymentId())
                    .platformWalletId(balanceAcctId)
                    .settAmt(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).longValue())
                    .isFinished("N")
                    .bizType("030001") //担保支付 030001
                    .profitSharingRuleId(businessRelations.getChinaumsRuleId())
                    .profitSharingList(confirmsDetailDTOList)
                    .build();

            String settOrderNo;
            try {
                settOrderNo = walletService.paySettlementConfirms(byxChinaumsGuaranteePayConfirmsDTO);
            } catch (Exception exception) {
                // 当请求返回异常时，直接跳过
                platformSubaccountList.remove(platformSubaccount);
                continue;
            }
            if (StringUtils.isEmpty(settOrderNo)) {
                continue;
            }
            subaccount.setSubaccountState(SubaccountState.SEPARATE_SUCC);
            subaccount.setExternalId(settOrderNo);
            subaccountRepository.saveAndFlush(subaccount);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), settOrderNo));
//            handleSubaccountStatus(subaccount, false);
            subaccountList.add(subaccount);
        }
        return platformSubaccountList;
    }

    private List<Statement> getStatementList(Order order) {
        List<Statement> allStatementList = statementRepository.findAllByOrdersId(order.getId());
        if (CollectionUtils.isEmpty(allStatementList)) {
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，未存在结算单。", order.getSn()));
            return null;
        }
        return allStatementList;
    }

    private List<ChinaumsPayment> getChinaumsPaymentList(Order order) {
        List<ChinaumsPayment> chinaumsPaymentList = chinaumsPaymentRepository.findAllByOrdersId(order.getId());
        if (CollectionUtils.isEmpty(chinaumsPaymentList)) {
            chinaumsPaymentList = walletService.handleChinaumsPayment(order);
        }
        return chinaumsPaymentList;
    }

    private List<Subaccount> getSubaccountListAndCheck(Order order) {
        List<Subaccount> subaccountList = subaccountRepository.findAllByOrdersId(order.getId());
        if (subaccountList == null) {
            return new ArrayList<>();
        }
        if (checkIsSubaccountOrder(subaccountList)) {
            // 更新订单已分账
            finishOrderSubaccount(order);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，分账单已存在，更新订单为已分账", order.getSn()));
            return null;
        }
        return subaccountList;
    }

    /**
     * 合并消费担保确认
     *
     * @return
     * @description
     * @author huabiao
     * @create 2023/2/6  17:17
     */
    public void confirmsCombinedGuaranteeByShipping(Shipping shipping) {
        // 自定义参数
        JSONObject metadata = new JSONObject();
        metadata.put("shippingSn", shipping.getShippingSn());
        Order order = shipping.getOrders();
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 获取银联支付单
        List<ChinaumsPayment> chinaumsPaymentList = getChinaumsPaymentList(order);
        // 待确认平台服务费金额
        BigDecimal toBeConfirmedServiceFeeAmount = BigDecimal.ZERO;
        // 查询平台服务费对应银联支付单
        ChinaumsPayment serviceFeeChinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(SubaccountType.SERVICE_FEE)).findFirst().orElse(null);
        if (serviceFeeChinaumsPayment != null) {
            toBeConfirmedServiceFeeAmount = serviceFeeChinaumsPayment.getAmount().subtract(serviceFeeChinaumsPayment.getConfirmedAmount());
            // 获取平台服务费银联退款单
            List<ChinaumsRefund> serviceFeeChinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(serviceFeeChinaumsPayment.getGuaranteePaymentId());
            if (CollectionUtils.isNotEmpty(serviceFeeChinaumsRefundList)) {
                toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(serviceFeeChinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            }
        }
        // 获取分账记录
        List<Subaccount> subaccountList = subaccountRepository.findAllByShippingId(shipping.getId());
        if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) {
            // 更新发货单已分账
            updateIsSeparateAccountsByShipping(shipping);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s]，分账单已存在，更新发货单为已分账", order.getSn(), shipping.getShippingSn()));
            return;
        }

        // 判断是否最后分账
        Boolean isFinallySubaccount = isFinallySubaccount(shipping);
        // 获取结算单
        List<Statement> statementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.NORMALORDER);
        // 获取退款结算单
        List<Statement> allAfterSaleStatementList = statementRepository.findAllByShippingIdAndStatementType(shipping.getId(), StatementType.AFTERSALES);
        // 平台服务费分账记录
        List<Subaccount> platformSubaccountList = new ArrayList<>();
        for (Statement statement : statementList) {
            // 获取对应分账类型的退款结算单
            List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(statement.getSubaccountType())).collect(Collectors.toList());
            // 退款金额
            BigDecimal refundAmount = BigDecimal.ZERO;
            // 退款品牌授权费
            BigDecimal refundBrandAuthFee = BigDecimal.ZERO;
            // 获取售后单
            List<AfterSale> afterSaleList = afterSaleRepository.findAllByShippingIdAndAfterSaleStatus(shipping.getId(), AfterSaleStatus.COMPLETED);
            if (CollectionUtils.isNotEmpty(afterSaleStatementList)) {
                if (afterSaleList.size() != afterSaleStatementList.size()) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo()));
                    return;
                }
                for (Statement afterSaleStatement : afterSaleStatementList) {
                    refundAmount = refundAmount.add(afterSaleStatement.getStatementAmount());
                    refundBrandAuthFee = refundBrandAuthFee.add(afterSaleStatement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add));
                }
            } else {
                // 当不存在退款结算单时，需判断是否还未生成
                if (CollectionUtils.isNotEmpty(afterSaleList)) {
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s][发货单][%s][结算单][%s]，该分账单存在退款结算单未生成", order.getSn(), shipping.getShippingSn(), statement.getStatementNo()));
                    return;
                }
            }
            // 平台服务费
            BigDecimal platformServiceFee = BigDecimal.ZERO;
            // 拼接平台服务费分账
            Subaccount platformSubaccount = calculationPlatformServiceFee(statement, orderFeeRatio, refundAmount);
            if (platformSubaccount != null) {
                // 当待确认平台服务费大于平台服务费分账金额时
                if (toBeConfirmedServiceFeeAmount.compareTo(platformSubaccount.getSubaccountAmount()) != -1) {
                    platformSubaccountList.add(platformSubaccount);
                    platformServiceFee = platformSubaccount.getSubaccountAmount();
                } else {
                    platformSubaccount = null;
                }
            }

            // 判断是否存在分账记录（根据分账企业和分账类型）
            Subaccount subaccount = subaccountList.stream().filter(filterSubaccount -> filterSubaccount.getSubaccountType().equals(statement.getSubaccountType()) && filterSubaccount.getCompany() != null && filterSubaccount.getCompany().equals(statement.getCompany())).findFirst().orElse(null);
            if (subaccount != null) {
                // 若是未分账则调用银联接口
                if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                    handleSubaccountStatus(subaccount, false);
                }
                continue;
            }
            subaccount = new Subaccount();
            subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
            subaccount.setCompany(statement.getCompany());
            subaccount.setSubaccountCostRatio(getCostRatio(statement, orderFeeRatio));
            if (platformSubaccount != null) {
                subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
            }

            subaccount.setSubaccountTotalAmount(statement.getStatementAmount().add(refundAmount));
            // 保存品牌授权费
            BigDecimal brandAuthFee = BigDecimal.ZERO;
            if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                brandAuthFee = statement.getStatementLine().stream().map(StatementLine::getBrandAuthFee).reduce(BigDecimal.ZERO, BigDecimal::add);
                subaccount.setBrandAuthCostRatio(orderFeeRatio.getOrderItemFeeRatio().get(0).getBrandAuthCostRatio());
                subaccount.setBrandAuthFee(brandAuthFee.add(refundBrandAuthFee));
            }
            if (isFinallySubaccount) {
                // 获取银联支付单
                ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType()) && filterChinaumsPayment.getOrders().equals(order)).findFirst().orElse(null);
                // 获取银联退款单
                List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
                BigDecimal chinaumsRefundAmount = BigDecimal.ZERO;
                if (CollectionUtils.isNotEmpty(chinaumsRefundList)) {
                    chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额
                subaccount.setSubaccountAmount(chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount));
            } else {
                if (statement.getSubaccountType().equals(SubaccountType.GOODS_COST)) {
                    // 货款分账金额 = 结算金额 + 退款金额 - 平台服务费 - 品牌授权费 +  退款品牌授权费
                    subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee).subtract(brandAuthFee).add(refundBrandAuthFee));
                } else {
                    // 其他分账金额 = 结算金额 - 退款金额 - 平台服务费
                    subaccount.setSubaccountAmount(statement.getStatementAmount().add(refundAmount).subtract(platformServiceFee));
                }
            }
            // 当分账金额小于等于0时跳过
            if (subaccount.getSubaccountAmount().compareTo(BigDecimal.ZERO) != 1) {
                continue;
            }
            subaccount.setSubaccountType(statement.getSubaccountType());
            subaccount.setOrders(statement.getOrders());
            subaccount.setShipping(statement.getShipping());
            subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
            subaccount.setSourceCompany(order.getBuyerCompany());

            // 获取银联支付单
            ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(statement.getCompany().getWalletId()) && filterChinaumsPayment.getSubaccountType().equals(statement.getSubaccountType())).findFirst().orElse(null);
            // 拼接扩展字段：商品信息
            ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
            chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), subaccount.getSubaccountAmount()));
            // 拼接分账确认请求参数
            ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO
                    .builder()
                    .outOrderNo(subaccount.getSubaccountNo())
                    .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId())
                    .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                    .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue())
                    .extra(chinaumsGuaranteePayExtraDTO)
                    .metadata(metadata)
                    .build();
            ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO;
            try {
                chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO);
            } catch (Exception exception) {
                // 当请求返回异常时，直接跳过
                continue;
            }
            subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
            subaccountRepository.saveAndFlush(subaccount);
            writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()));
            handleSubaccountStatus(subaccount, false);
            subaccountList.add(subaccount);
            // 存在平台服务费时，需要在待确认金额中减去
            if (platformSubaccount != null) {
                toBeConfirmedServiceFeeAmount = toBeConfirmedServiceFeeAmount.subtract(platformServiceFee);
            }
        }

        // 品牌授权费
        if (CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
            // 找出品牌授权费的发货项
            Map<Long, List<ShippingItem>> brandIdShippingItemListMap = new HashMap<>();
            for (OrderItemFeeRatio orderItemFeeRatio : orderFeeRatio.getOrderItemFeeRatio()) {
                ShippingItem shippingItem = shipping.getShippingItem().stream().filter(filterShippingItem -> filterShippingItem.getOrderItemId().equals(orderItemFeeRatio.getOrderItem().getId().toString())).findFirst().orElse(null);
                if (shippingItem != null) {
                    Long brandId = orderItemFeeRatio.getOrderItem().getBrandId();
                    if (brandIdShippingItemListMap.containsKey(brandId)) {
                        List<ShippingItem> shippingItemList = new ArrayList<>(brandIdShippingItemListMap.get(brandId));
                        shippingItemList.add(shippingItem);
                        brandIdShippingItemListMap.put(brandId, shippingItemList);
                    } else {
                        brandIdShippingItemListMap.put(orderItemFeeRatio.getOrderItem().getBrandId(), Arrays.asList(shippingItem));
                    }
                }
            }
            if (!brandIdShippingItemListMap.isEmpty()) {
                // 获取品牌授权费的分账记录
                List<Subaccount> brandAuthFeeSubaccountList = subaccountList.stream().filter(subaccount -> subaccount.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)).collect(Collectors.toList());
                // 平台服务费分账记录
                Subaccount platformSubaccount = new Subaccount();
                for (Map.Entry<Long, List<ShippingItem>> brandIdShippingItemListEntry : brandIdShippingItemListMap.entrySet()) {
                    Long brandId = brandIdShippingItemListEntry.getKey();
                    List<ShippingItem> shippingItemList = brandIdShippingItemListEntry.getValue();
                    // 通过品牌ID获取银联支付单号
                    ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment ->
                            filterChinaumsPayment.getSubaccountType().equals(SubaccountType.BRAND_AUTH_FEE)
                                    && filterChinaumsPayment.getBrandId() != null
                                    && filterChinaumsPayment.getBrandId().equals(brandId)).findFirst().orElse(null);
                    // 判断该银联支付单是否已分账
                    if (chinaumsPayment != null) {
                        // 判断该品牌授权费是否存在分账记录(根据品牌ID)
                        Subaccount subaccount = brandAuthFeeSubaccountList.stream().filter(filterSubaccount -> filterSubaccount.getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null);
                        if (subaccount != null) {
                            // 若是未分账则调用银联接口
                            if (subaccount.getSubaccountState().equals(SubaccountState.SEPARATE_NOT)) {
                                handleSubaccountStatus(subaccount, false);
                            }
                            continue;
                        }

                        // 获取货款结算单
                        Statement goodsCostStatement = statementList.stream().filter(statement -> statement.getSubaccountType().equals(SubaccountType.GOODS_COST)).findFirst().orElse(null);
                        // 获取货款退款结算单
                        List<Statement> afterSaleStatementList = allAfterSaleStatementList.stream().filter(filterStatement -> filterStatement.getSubaccountType().equals(SubaccountType.GOODS_COST)).collect(Collectors.toList());

                        // 计算发货总金额
                        BigDecimal shippingAmount = BigDecimal.ZERO;
                        // 计算品牌授权费
                        BigDecimal brandAuthFee = BigDecimal.ZERO;
                        for (ShippingItem shippingItem : shippingItemList) {
                            shippingAmount = shippingAmount.add(shippingItem.getAmount());
                            // 找到符合条件的对应结算单项
                            StatementLine statementLine = goodsCostStatement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null);
                            if (statementLine != null) {
                                brandAuthFee = brandAuthFee.add(statementLine.getBrandAuthFee());
                            }
                            // 找到符合条件的货款退款结算单
                            if (CollectionUtils.isNotEmpty(afterSaleStatementList)) {
                                for (Statement statement : afterSaleStatementList) {
                                    StatementLine afterSaleStatementLine = statement.getStatementLine().stream().filter(filterStatementLine -> filterStatementLine.getShippingItem().equals(shippingItem)).findFirst().orElse(null);
                                    if (afterSaleStatementLine != null) {
                                        brandAuthFee = brandAuthFee.subtract(afterSaleStatementLine.getBrandAuthFee());
                                    }
                                }
                            }
                        }

                        Company company = companyRepository.findByWalletId(chinaumsPayment.getRecvBalanceAcctId());
                        // 计算平台服务费
                        BigDecimal platformServiceFee = BigDecimal.ZERO;
                        // 获取订单项费用比例
                        OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getBrandId().equals(chinaumsPayment.getBrandId())).findFirst().orElse(null);
                        if (orderItemFeeRatio != null && orderItemFeeRatio.getBrandAuthCostServiceCostRatio().compareTo(BigDecimal.ZERO) == 1) {
                            // 计算平台服务费
                            platformServiceFee = brandAuthFee.multiply(orderItemFeeRatio.getBrandAuthCostServiceCostRatio()).setScale(2, BigDecimal.ROUND_UP);
                            // 拼接平台服务费分账
                            if (platformServiceFee.compareTo(BigDecimal.ZERO) == 1 && toBeConfirmedServiceFeeAmount.compareTo(platformServiceFee) != -1) {
                                platformSubaccount = generatePlatformSubaccount(orderItemFeeRatio.getBrandAuthCostServiceCostRatio(), platformServiceFee, order, shipping, company);
                                if (platformSubaccount != null) {
                                    platformSubaccountList.add(platformSubaccount);
                                    brandAuthFee = brandAuthFee.subtract(platformServiceFee);
                                }
                            } else {
                                platformServiceFee = BigDecimal.ZERO;
                            }
                        }
                        // 分账总金额
                        BigDecimal subaccountTotalAmount = brandAuthFee.add(platformServiceFee);
                        // 最后一笔
                        if (isFinallySubaccount && brandIdShippingItemListMap.size() == (brandAuthFeeSubaccountList.size() + 1)) {
                            // 获取银联退款单
                            List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
                            BigDecimal chinaumsRefundAmount = BigDecimal.ZERO;
                            if (CollectionUtils.isNotEmpty(chinaumsRefundList)) {
                                chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                            }
                            // 分账金额 = 银联支付金额 - 银联确认金额 - 银联退款金额
                            brandAuthFee = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount);
                        }
                        // 判断品牌授权费金额是否大于0
                        if (brandAuthFee.compareTo(BigDecimal.ZERO) != 1) {
                            continue;
                        }
                        // 拼接分账记录
                        subaccount = new Subaccount();
                        subaccount.setSubaccountNo(sequenceUtil.getNextSequenceNumber("FZ"));
                        subaccount.setCompany(company);
                        subaccount.setSubaccountTotalAmount(subaccountTotalAmount);
                        subaccount.setSubaccountAmount(brandAuthFee);
                        subaccount.setSubaccountType(SubaccountType.BRAND_AUTH_FEE);
                        subaccount.setOrders(order);
                        subaccount.setShipping(shipping);
                        subaccount.setSubaccountState(SubaccountState.SEPARATE_NOT);
                        subaccount.setSourceCompany(order.getSellerCompany());
                        subaccount.setBrandId(brandId);
                        if (platformSubaccount != null) {
                            subaccount.setPlatformServiceCostRatio(platformSubaccount.getSubaccountCostRatio());
                            subaccount.setPlatformServiceFee(platformSubaccount.getSubaccountAmount());
                        }

                        // 拼接扩展字段：商品信息
                        ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                        chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shippingItemList, order.getSn(), shippingAmount, subaccount.getSubaccountAmount()));
                        // 拼接分账确认请求参数
                        ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO
                                .builder()
                                .outOrderNo(subaccount.getSubaccountNo())
                                .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId())
                                .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                                .amount(subaccount.getSubaccountAmount().multiply(new BigDecimal(100)).intValue())
                                .extra(chinaumsGuaranteePayExtraDTO)
                                .metadata(metadata)
                                .build();
                        ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO;
                        try {
                            chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO);
                        } catch (Exception exception) {
                            // TODO 当请求返回异常时，直接跳过
                            continue;
                        }
                        subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                        subaccountRepository.saveAndFlush(subaccount);
                        writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()));
                        handleSubaccountStatus(subaccount, false);
                        brandAuthFeeSubaccountList.add(subaccount);
                    }
                    subaccountList.addAll(brandAuthFeeSubaccountList);
                }
            }
        }

        // 获取已生成的平台服务费分账记录
        List<Subaccount> platformSubaccounts = subaccountList.stream().filter(subaccount -> subaccount.getCompany() == null).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(platformSubaccounts)) {
            for (Subaccount platformSubaccount : platformSubaccounts) {
                handleSubaccountStatus(platformSubaccount, false);
            }
        } else if (CollectionUtils.isNotEmpty(platformSubaccountList)) {
            // 获取平台电子账簿ID
            String balanceAcctId = chinaumsUtil.getFeeBalanceAcctId();
            // 获取平台服务费对应的银联支付单
            ChinaumsPayment chinaumsPayment = chinaumsPaymentList.stream().filter(filterChinaumsPayment -> filterChinaumsPayment.getRecvBalanceAcctId().equals(balanceAcctId)).findFirst().orElse(null);
            if (chinaumsPayment != null) {
                // 获取银联退款单
                List<ChinaumsRefund> chinaumsRefundList = chinaumsRefundRepository.findAllByOrigTradeId(chinaumsPayment.getGuaranteePaymentId());
                BigDecimal chinaumsRefundAmount = BigDecimal.ZERO;
                if (CollectionUtils.isNotEmpty(chinaumsRefundList)) {
                    chinaumsRefundAmount = chinaumsRefundList.stream().map(ChinaumsRefund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                // 待确认金额 = 银联支付金额 - 确认金额 - 银联退款金额
                BigDecimal toBeConfirmedAmount = chinaumsPayment.getAmount().subtract(chinaumsPayment.getConfirmedAmount()).subtract(chinaumsRefundAmount);
                BigDecimal platformServiceFee = platformSubaccountList.stream().map(Subaccount::getSubaccountAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 当待确认金额小于平台服务费时，以待确认金额为主
                if (toBeConfirmedAmount.compareTo(platformServiceFee) == -1) {
                    platformServiceFee = toBeConfirmedAmount;
                }
                // 拼接扩展字段：商品信息
                ChinaumsGuaranteePayExtraDTO chinaumsGuaranteePayExtraDTO = new ChinaumsGuaranteePayExtraDTO();
                chinaumsGuaranteePayExtraDTO.setProductInfos(this.handleProductInfoByShipping(shipping.getShippingItem(), order.getSn(), shipping.getAmount(), platformServiceFee));
                // 拼接分账确认请求参数
                ChinaumsGuaranteePayConfirmsDTO chinaumsGuaranteePayConfirmsDTO = ChinaumsGuaranteePayConfirmsDTO
                        .builder()
                        .outOrderNo(platformSubaccountList.get(0).getSubaccountNo())
                        .guaranteePaymentId(chinaumsPayment.getGuaranteePaymentId())
                        .sentAt(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()))
                        .amount(platformServiceFee.multiply(new BigDecimal(100)).intValue())
                        .extra(chinaumsGuaranteePayExtraDTO)
                        .metadata(metadata)
                        .build();
                try {
                    ChinaumsGuaranteePayConfirmsVO chinaumsGuaranteePayConfirmsVO = walletService.paySettlement(chinaumsGuaranteePayConfirmsDTO);
                    // 已分配金额
                    BigDecimal allocatedAmount = BigDecimal.ZERO;
                    for (Subaccount subaccount : platformSubaccountList) {
                        // 待分配金额
                        BigDecimal toBeAllocatedAmount = platformServiceFee.subtract(allocatedAmount);
                        // 当待分配金额大于分账金额时
                        if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 1) {
                            subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                            subaccountRepository.saveAndFlush(subaccount);
                            handleSubaccountStatus(subaccount, false);
                        } else if (toBeAllocatedAmount.compareTo(subaccount.getSubaccountAmount()) == 0) {
                            // 当待分配金额等于分账金额，跳出循环
                            subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                            subaccountRepository.saveAndFlush(subaccount);
                            handleSubaccountStatus(subaccount, false);
                            break;
                        } else {
                            // 当待分配金额小于分账金额，修改分账金额
                            subaccount.setSubaccountAmount(toBeAllocatedAmount);
                            subaccount.setExternalId(chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId());
                            subaccountRepository.saveAndFlush(subaccount);
                            handleSubaccountStatus(subaccount, false);
                        }
                        allocatedAmount = allocatedAmount.add(subaccount.getSubaccountAmount());
                    }
                    writeSeparateLog(String.format("[分账][生成][普通订单][%s]，生成分账单成功,银联结算单号[%s]。", order.getSn(), chinaumsGuaranteePayConfirmsVO.getCombinedGuaranteeConfirmId()));
                    subaccountList.addAll(platformSubaccountList);
                } catch (Exception exception) {
                    // TODO 当请求返回异常时，直接跳过
                }
            }
        }
        // 判断是否分账结束
        if (checkIsSubaccount(subaccountList, chinaumsPaymentList, toBeConfirmedServiceFeeAmount.compareTo(BigDecimal.ZERO) == 0)) {
            updateIsSeparateAccountsByShipping(shipping);
        }
    }

    /**
     * 退款结算单-生成
     *
     * @param subaccountType         分账类型
     * @param order                  订单
     * @param orderRefundItemDTOList 订单关闭项数组
     * @param company                分账企业
     * @return 退款结算单
     * @author huabiao
     * @create 2023/1/4  11:04
     */
    private Statement createRefundStatement(SubaccountType subaccountType, Order order, List<OrderRefundItemDTO> orderRefundItemDTOList, Company company) {
        // 获取订单费用比例
        OrderFeeRatio orderFeeRatio = orderFeeRatioRepository.findByOrdersId(order.getId());
        // 拼接退款结算单
        Statement refundStatement = new Statement();
        refundStatement.setOrders(order);
        refundStatement.setStatementNo(sequenceUtil.getNextSequenceNumber("FEE"));
        refundStatement.setStatementType(StatementType.AFTERSALES);
        refundStatement.setSubaccountType(subaccountType);
        refundStatement.setStatementState(StatementState.NOTRECORDED);
        // 退款总金额
        BigDecimal subaccountAmount = BigDecimal.ZERO;
        // 拼接退款结算单行
        List<StatementLine> refundStatementLineList = new ArrayList<>();
        for (OrderRefundItemDTO orderRefundItemDTO : orderRefundItemDTOList) {
            StatementLine refundStatementLine = new StatementLine();
            refundStatementLine.setStatement(refundStatement);
            refundStatementLine.setCompany(company);
            refundStatementLine.setOrderItem(orderRefundItemDTO.getOrderItem());
            // 计算每个订单项的退款金额
            BigDecimal subaccountLineAmount = BigDecimal.ZERO;
            switch (subaccountType) {
                case GOODS_COST:
                    refundStatementLine.setSubaccountRatio(BigDecimal.ONE.subtract(orderFeeRatio.getBrandCostRatio()).subtract(orderFeeRatio.getDeviseCostRatio()));
                    subaccountLineAmount = orderRefundItemDTO.getRefundAmount().subtract(orderRefundItemDTO.getHandleRefundAmount());
                    break;
                case BRAND_FEE:
                    refundStatementLine.setSubaccountRatio(orderFeeRatio.getBrandCostRatio());
                    subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getBrandCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount));
                    break;
                case DEVISE_FEE:
                    refundStatementLine.setSubaccountRatio(orderFeeRatio.getDeviseCostRatio());
                    subaccountLineAmount = orderRefundItemDTO.getRefundAmount().multiply(orderFeeRatio.getDeviseCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    orderRefundItemDTO.setHandleRefundAmount(orderRefundItemDTO.getHandleRefundAmount().add(subaccountLineAmount));
                    break;
            }
            subaccountAmount = subaccountAmount.add(subaccountLineAmount);
            refundStatementLine.setSubaccountAmount(subaccountLineAmount.negate());
            // 计算品牌授权费
            if (subaccountType.equals(SubaccountType.GOODS_COST) && CollectionUtils.isNotEmpty(orderFeeRatio.getOrderItemFeeRatio())) {
                OrderItemFeeRatio orderItemFeeRatio = orderFeeRatio.getOrderItemFeeRatio().stream().filter(filterOrderItemFeeRatio -> filterOrderItemFeeRatio.getOrderItem().getId().equals(orderRefundItemDTO.getOrderItem().getId())).findFirst().orElse(null);
                if (orderItemFeeRatio != null) {
                    refundStatementLine.setBrandAuthFee(subaccountLineAmount.multiply(orderItemFeeRatio.getBrandAuthCostRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            }
            refundStatementLine.setQuantity(orderRefundItemDTO.getRefundQuantity());
            refundStatementLineList.add(refundStatementLine);
        }
        refundStatement.setStatementLine(refundStatementLineList);
        refundStatement.setCompany(company);
        refundStatement.setStatementAmount(subaccountAmount.negate());
        return refundStatement;
    }

    @Transactional(rollbackFor = Exception.class)
    public void finishOrderSubaccount(Order order) {
        order.setSubaccountTime(LocalDateTime.now());
        order.setIsSeparateAccounts(true);
        orderRepository.save(order);
    }

    /**
     * 停止订单分账
     *
     * @param orderId 订单ID
     * @author huabiao
     * @create 2023/8/24  9:49
     */
    private void stopOrderSubaccount(Long orderId){
        // 获取该订单所有的结算单
        List<Statement> statementList = statementRepository.findAllByOrdersId(orderId);
        // 将结算单改为已退回
        statementList.stream().forEach(statement ->  statement.setStatementState(StatementState.RETURNED));
        statementRepository.saveAll(statementList);
    }
}
