package com.sckw.payment.service;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
import com.sckw.core.model.enums.LogisticsOrderEnum;
import com.sckw.core.model.page.PageRes;
import com.sckw.core.utils.IdWorker;
import com.sckw.core.utils.OrderUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.UpdateOrderStatusParam;
import com.sckw.payment.api.model.constant.ChannelEnum;
import com.sckw.payment.api.model.dto.WalletDto;
import com.sckw.payment.api.model.dto.WalletVo;
import com.sckw.payment.api.model.dto.common.R;
import com.sckw.payment.dao.KwpLedgerLogisticsMapper;
import com.sckw.payment.dao.KwpSettlementLogisticsMapper;
import com.sckw.payment.dao.KwpSettlementLogisticsTrackMapper;
import com.sckw.payment.dao.KwpSettlementWalletMapper;
import com.sckw.payment.model.*;
import com.sckw.payment.model.constant.*;
import com.sckw.payment.model.dto.LedgerUnitDto;
import com.sckw.payment.model.dto.SettlementLogisticsDto;
import com.sckw.payment.model.dto.SettlementTradeDto;
import com.sckw.payment.model.dto.SettlementWalletDto;
import com.sckw.payment.model.dto.common.BusinessNo;
import com.sckw.payment.model.vo.SettlementVo;
import com.sckw.payment.model.vo.req.OfflinePaymentReq;
import com.sckw.payment.model.vo.req.SettlementWalletReq;
import com.sckw.payment.model.vo.req.WalletPayReq;
import com.sckw.payment.model.vo.res.SettlementWalletVo;
import com.sckw.redis.config.RedisLockUtil;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportRemoteService;
import com.sckw.transport.api.model.param.LogisticsOrderParam;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Aick Spt
 * @date 2023-07-20 14:55
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class KwpSettlementWalletService {
    private final KwpSettlementWalletMapper settlementWalletMapper;
    private final KwpLedgerLogisticsMapper kwpLedgerLogisticsMapper;
    private final KwpSettlementLogisticsMapper kwpSettlementLogisticsMapper;

    private final KwpLedgerTradeOrderService tradeOrderService;
    private final KwpLedgerLogisticsOrderService kwpLedgerLogisticsOrderService;
    private final WalletBusinessService walletBusinessService;
    @Resource
    private KwpSettlementTradeService kwpSettlementTradeService;
    @Resource
    private KwpSettlementLogisticsService kwpSettlementLogisticsService;
    private final PayCenterService payCenterService;
    private final KwpWalletRelationService walletRelationService;
    private final RedisLockUtil redisLockUtil;
    private final KwpSettlementTradeTrackService settlementTradeTrackService;
    private final MessageSender messageSender;
    private final KwpLedgerTradeUnitService tradeUnitService;
    private final KwpLedgerLogisticsUnitService logisticsUnitService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TradeOrderInfoService tradeOrderInfoService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportRemoteService transportRemoteService;
    private final KwpSettlementLogisticsTrackMapper kwpSettlementLogisticsTrackMapper;
    @Resource
    private KwpLedgerTradeService kwpLedgerTradeService;


    /**
     * 物流-电子钱包付款（货到付款）结算记录-列表
     *
     * @author Aick Spt
     * @date 2023-07-26 16:43
     */
    public PageRes<SettlementWalletVo> pageListLogisticsPayment(SettlementWalletReq settlementWalletReq) {
//        //加上当前登录者顶级企业id用于过滤数据
//        settlementWalletReq.setEntId(LoginUserHolder.getEntId());
        //添加默认分页数据
        PageHelper.startPage(settlementWalletReq.getPage(), settlementWalletReq.getPageSize());
        List<SettlementWalletDto> settlementWalletLogisticsList = settlementWalletMapper.pageList(settlementWalletReq);
        PageInfo<SettlementWalletDto> pageInfo = new PageInfo<>(settlementWalletLogisticsList);
        if (CollectionUtils.isEmpty(settlementWalletLogisticsList)) {
            return new PageRes<>();
        }
        //增加对应创建人和更新人名称
        for (SettlementWalletDto entity : settlementWalletLogisticsList) {
            entity.setCreateByText("未知创建人");
            entity.setUpdateByText("未知更新人");
        }
        DecimalFormat df = new DecimalFormat("0.00");

        Map<Long, UserCacheResDto> map = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        //指定返回值
        List<SettlementWalletVo> collect = settlementWalletLogisticsList.stream().map(a -> {
            SettlementWalletVo settlementWalletVo = new SettlementWalletVo();
            BeanUtils.copyProperties(a, settlementWalletVo);
            Long createBy = a.getCreateBy();
            Long updateBy = a.getUpdateBy();
            UserCacheResDto userCacheResDto = map.get(createBy);
            if (Objects.isNull(userCacheResDto)) {
                userCacheResDto = remoteSystemService.queryUserCacheById(createBy);
                map.put(createBy, userCacheResDto);
            }
            if (Objects.nonNull(userCacheResDto)) {
                settlementWalletVo.setCreateByText(userCacheResDto.getName());
            }
            userCacheResDto = map.get(updateBy);
            if (Objects.isNull(userCacheResDto)) {
                userCacheResDto = remoteSystemService.queryUserCacheById(updateBy);
                map.put(updateBy, userCacheResDto);
            }
            if (Objects.nonNull(userCacheResDto)) {
                settlementWalletVo.setUpdateByText(userCacheResDto.getName());
            }
            settlementWalletVo.setPayPrice(df.format(Objects.isNull(a.getPayPrice()) ? new BigDecimal("0.0") : a.getPayPrice()));
            settlementWalletVo.setTopayPrice(df.format(Objects.isNull(a.getTopayPrice()) ? new BigDecimal("0.0") : a.getTopayPrice()));
            return settlementWalletVo;
        }).collect(Collectors.toList());

        return PageRes.build(pageInfo, collect);
    }


    /**
     * 物流-电子钱包付款（货到付款）结算记录-新增
     *
     * @return InsertId
     * @author Aick Spt
     * @date 2023-07-20 14:23
     * <p>
     * Transactional// isolation:事务的隔离级别，此处使用后端数据库的默认隔离级别, propagation: 如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中(常见)。(rollbackFor = Exception.class, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
     */
    @GlobalTransactional(rollbackFor = Exception.class, name = "default_tx_group")
    public Integer confirmLogisticsPayment(OfflinePaymentReq offlinePaymentReq) {
        Long id = offlinePaymentReq.getIdLong();
        BigDecimal price = offlinePaymentReq.getPrice();
        if (id == 0) {
            throw new BusinessException("结算参数ID必填");
        }
        if (price == null || price.compareTo(BigDecimal.ZERO) == 0) {
            throw new BusinessException("结算参数金额必填");
        }
        //先查询出结算单情况
        SettlementLogisticsDto settlementLogisticsDto = kwpSettlementLogisticsService.detailPayment(id);
        //检查结算单状态和所差金额
        if (settlementLogisticsDto == null) {
            log.error("非法请求，查无数据：" + id);
            throw new BusinessException("非法请求运费结算参数ID");
        }
        if (settlementLogisticsDto.getStatus() == SettlementEnum.ALL_PAYMENT.getStatus()) {
            log.error("非法请求，该订单已结算完成：" + id);
            throw new BusinessException("该订单已结算完成，无法操作");
        }
        BigDecimal remainingReceivables = settlementLogisticsDto.getTotalPrice();
        //剩余金额
        if (settlementLogisticsDto.getActualPrice() != null) {
            remainingReceivables = settlementLogisticsDto.getTotalPrice().subtract(settlementLogisticsDto.getActualPrice());
        }

        //-1表示小于,0是等于,1是大于
        if (remainingReceivables.compareTo(price) < 0) {
            log.error("本次结算输入金额比剩余付款金额大：ID：" + id + " 剩余金额：" + remainingReceivables + " 本次输入金额：" + price);
            throw new BusinessException("参数错误：输入金额过大 " + price + " 剩余金额最大值：" + remainingReceivables);
        }
        //托运方
        KwpLedgerLogisticsUnit logisticsUnit = logisticsUnitService.queryCustomerEnt(settlementLogisticsDto.getLLedgerId(), LogisticsUnitType.SHIPPER);
        //承运方(对账发起方，收钱方)
        KwpLedgerLogisticsUnit logisticsUnit2 = logisticsUnitService.queryCustomerEnt(settlementLogisticsDto.getLLedgerId(), LogisticsUnitType.CARRIER);
        String uid = walletRelationService.getRelation(logisticsUnit.getTopEntId());
        if (StringUtils.isBlank(uid)) {
            throw new BusinessException("我方单位暂未开通电子钱包");
        }
        String filter = walletRelationService.getRelation(logisticsUnit2.getTopEntId());
        if (StringUtils.isBlank(filter)) {
            throw new BusinessException("客户单位暂未开通电子钱包");
        }
        String trading = settlementLogisticsDto.getTrading();
        ChannelEnum channelEnum = ChannelEnum.getByTrading(trading);
        if (Objects.isNull(channelEnum)) {
            throw new BusinessException("交易方式不存在");
        }
        //加锁
        String key = String.format(RedisConstant.SETTLEMENT_KEY, offlinePaymentReq.getId());
        if (redisLockUtil.tryLock(key)) {
            try {
                //钱包余额校验
                walletBusinessService.checkMoney(uid, filter, channelEnum, price);
                //累加入库结算单
                KwpSettlementLogistics settlementLogistics = new KwpSettlementLogistics();
                settlementLogistics.setId(settlementLogisticsDto.getId());
                settlementLogistics.setUpdateTime(LocalDateTime.now());
                //全部结算
                if (remainingReceivables.compareTo(price) == 0) {
                    settlementLogistics.setStatus(SettlementEnum.ALL_PAYMENT.getStatus());
                }
                //部分结算
                if (remainingReceivables.compareTo(price) > 0) {
                    settlementLogistics.setStatus(SettlementEnum.PARTIAL_PAYMENT.getStatus());
                }
                BigDecimal actualPrice = settlementLogisticsDto.getActualPrice();
                settlementLogistics.setActualPrice((actualPrice == null) ? price : actualPrice.add(price));
                int upInt = kwpSettlementLogisticsMapper.updateById(settlementLogistics);
                if (upInt > 0) {
                    //新增一条修改记录
                    String remark = LoginUserHolder.getUserName() + "[" + LoginUserHolder.getUserId() + "]" + "结算[" + settlementLogistics.getId() + "]" + settlementLogistics.getActualPrice() + "(" + SettlementEnum.getStatusDesc(settlementLogistics.getStatus()) + ")";
                    KwpSettlementLogisticsTrack kwpSettlementLogisticsTrack = new KwpSettlementLogisticsTrack();
                    kwpSettlementLogisticsTrack.setId(new IdWorker(1).nextId());
                    kwpSettlementLogisticsTrack.setLSettlementId(settlementLogistics.getId());
                    kwpSettlementLogisticsTrack.setRemark(remark);
                    kwpSettlementLogisticsTrack.setStatus(settlementLogistics.getStatus());
                    kwpSettlementLogisticsTrack.setCreateBy(LoginUserHolder.getUserId());
                    kwpSettlementLogisticsTrack.setCreateTime(LocalDateTime.now());
                    kwpSettlementLogisticsTrack.setUpdateBy(LoginUserHolder.getUserId());
                    kwpSettlementLogisticsTrack.setUpdateTime(LocalDateTime.now());
                    kwpSettlementLogisticsTrack.setDelFlag(0);
                    kwpSettlementLogisticsTrackMapper.insert(kwpSettlementLogisticsTrack);

                    //新增一条电子钱包结算记录
                    String orderNo = OrderUtils.generateOrderNo("SL");
                    remainingReceivables = remainingReceivables.subtract(price);
                    KwpSettlementWallet kwpSettlementWallet = new KwpSettlementWallet();
                    kwpSettlementWallet.setId(new IdWorker(1).nextId());
                    kwpSettlementWallet.setEntId(settlementLogisticsDto.getEntId());
                    kwpSettlementWallet.setOrderNo(orderNo);
                    kwpSettlementWallet.setSettlementId(settlementLogisticsDto.getId());
                    kwpSettlementWallet.setOrderType(SettlementOrderTypeEnum.LOGISTICS.getStatus());
                    //先用数字默认定义为1
                    kwpSettlementWallet.setChannel(WalletChannelEnum.getValue(settlementLogisticsDto.getTrading()));
                    kwpSettlementWallet.setPayTime(LocalDateTime.now());
                    kwpSettlementWallet.setPayPrice(price);
                    kwpSettlementWallet.setTopayPrice(remainingReceivables);
                    kwpSettlementWallet.setType(SettlementPayTypeEnum.CASH_ON_DELIVERY.getStatus());
                    kwpSettlementWallet.setRemark(Global.EMPTY_STRING);
                    kwpSettlementWallet.setStatus(1);
                    kwpSettlementWallet.setCreateBy(LoginUserHolder.getUserId());
                    kwpSettlementWallet.setCreateTime(LocalDateTime.now());
                    kwpSettlementWallet.setUpdateBy(LoginUserHolder.getUserId());
                    kwpSettlementWallet.setUpdateTime(LocalDateTime.now());
                    kwpSettlementWallet.setDelFlag(0);
                    Integer insertKwpSettlementWallet = settlementWalletMapper.insert(kwpSettlementWallet);
                    log.info("新增一条电子钱包结算记录：" + insertKwpSettlementWallet);
                    //需要将金额同步到对应的对账表中
                    KwpLedgerLogistics kwpLedgerLogistics = new KwpLedgerLogistics();
                    kwpLedgerLogistics.setId(settlementLogisticsDto.getLLedgerId());
                    kwpLedgerLogistics.setActualPrice(settlementLogistics.getActualPrice());
                    kwpLedgerLogisticsMapper.updateById(kwpLedgerLogistics);
                    //dubbo修改物流订单状态
                    List<KwpLedgerLogisticsOrder> kwpLedgerLogisticsOrders = kwpLedgerLogisticsOrderService.queryList(settlementLogisticsDto.getLLedgerId());
                    for (KwpLedgerLogisticsOrder kwpLedgerLogisticsOrder : kwpLedgerLogisticsOrders) {
                        LogisticsOrderParam logisticsOrderParam = new LogisticsOrderParam();
                        logisticsOrderParam.setLOrderId(kwpLedgerLogisticsOrder.getLOrderId());
                        logisticsOrderParam.setStatus(LogisticsOrderEnum.HAVE_ALREADY_SETTLED.getStatus());
                        logisticsOrderParam.setUpdateBy(LoginUserHolder.getUserId());
                        logisticsOrderParam.setUpdateTime(new Date());
                        HttpResult httpResult = transportRemoteService.checkLogisticsOrderStatusById(logisticsOrderParam);
                        if (httpResult.getCode() != HttpStatus.SUCCESS_CODE) {
                            log.error("更新物流订单状态异常：{}", JSONObject.toJSONString(logisticsOrderParam));
                            throw new BusinessException(httpResult.getMsg());
                        }
                    }
                    // 调用电子钱包进行清分操作
                    walletBusinessService.splitMoney(orderNo, uid, filter, channelEnum, price, "2");
                    //推送双方系统管理员
                    messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                        put("company", logisticsUnit.getFirmName());
                        put("number", settlementLogisticsDto.getSlOrderNo());
                    }}, logisticsUnit2.getEntId(), MessageEnum.SETTLEMENT_START_CARRIER);
                    messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                        put("company", logisticsUnit2.getFirmName());
                        put("number", settlementLogisticsDto.getSlOrderNo());
                    }}, logisticsUnit.getEntId(), MessageEnum.SETTLEMENT_START_SHIPPER);
                    return insertKwpSettlementWallet;
                }
            } finally {
                redisLockUtil.unlock(key);
            }
        }
        return null;
    }


    /**
     * 采购-付款确认-货到付款
     *
     * @author xucaiqin
     * @date 2023-07-27 16:13
     */
    @GlobalTransactional(name = "default_tx_group", rollbackFor = Exception.class)
    public String confirmTradePayment(WalletPayReq walletPayReq) {
        log.info("采购-付款确认-货到付款:{}", JSONObject.toJSONString(walletPayReq));
        String key = String.format(RedisConstant.SETTLEMENT_KEY, walletPayReq.getId());
        SettlementTradeDto byId = kwpSettlementTradeService.getById(walletPayReq.getIdLong(), TradeUnitType.SELL);
        if (Objects.isNull(byId)) {
            throw new BusinessException("结算单不存在");
        }
        if (StringUtils.isNotBlank(byId.getTrading()) && !byId.getTrading().startsWith(TradingEnum.RECEIVE_PAY.getValue())) {
            throw new BusinessException("只支持货货到付款方式订单进行当前操作");
        }
        KwpLedgerTradeUnit kwpLedgerTradeUnit = tradeUnitService.queryCustomerEnt(byId.getLedgerId(), TradeUnitType.PURCHASE);
        KwpLedgerTradeUnit kwpLedgerTradeUnit2 = tradeUnitService.queryCustomerEnt(byId.getLedgerId(), TradeUnitType.SELL);
        String uid = walletRelationService.getRelation(kwpLedgerTradeUnit.getTopEntId());
        String filter = walletRelationService.getRelation(kwpLedgerTradeUnit2.getTopEntId());
        if (StringUtils.isBlank(uid)) {
            throw new BusinessException("我方企业暂未开通电子钱包");
        }
        if (StringUtils.isBlank(filter)) {
            throw new BusinessException("客户企业暂未开通电子钱包");
        }
        ChannelEnum channelEnum = ChannelEnum.getByTrading(byId.getTrading());
        if (Objects.isNull(channelEnum)) {
            throw new BusinessException("交易方式不存在");
        }
        //付款金额
        BigDecimal price = walletPayReq.getPrice();
        if (redisLockUtil.tryLock(key)) {
            try {
                //电子钱包余额校验
                walletBusinessService.checkMoney(uid, filter, channelEnum, price);
                //待付款金额-本次付款金额= 剩余待付款金额
                BigDecimal subtract = byId.getWaitPrice().subtract(walletPayReq.getPrice());
                if (subtract.compareTo(new BigDecimal("0.0")) < NumberConstant.ZERO) {
                    throw new BusinessException("付款金额不能大于待付款金额");
                }
                /*新增记录*/
                //新增电子钱包结算记录
                String orderNo = OrderUtils.generateOrderNo("ST");
                KwpSettlementWallet kwpSettlementWallet = new KwpSettlementWallet();
                kwpSettlementWallet.setId(new IdWorker(NumberConstant.ONE).nextId());
                kwpSettlementWallet.setEntId(LoginUserHolder.getEntId());
                kwpSettlementWallet.setOrderNo(orderNo);
                kwpSettlementWallet.setSettlementId(walletPayReq.getIdLong());
                kwpSettlementWallet.setOrderType(SettlementOrderTypeEnum.TRADE.getStatus());
                kwpSettlementWallet.setChannel(WalletChannelEnum.getValue(byId.getTrading()));
                kwpSettlementWallet.setPayTime(LocalDateTime.now());
                kwpSettlementWallet.setPayPrice(walletPayReq.getPrice());
                kwpSettlementWallet.setTopayPrice(subtract);
                kwpSettlementWallet.setType(SettlementWalletPayTypeEnum.CASH_ON_DELIVERY.getStatus());
                kwpSettlementWallet.setRemark(Global.EMPTY_STRING);
                kwpSettlementWallet.setStatus(NumberConstant.ZERO);
                kwpSettlementWallet.setCreateBy(LoginUserHolder.getUserId());
                kwpSettlementWallet.setCreateTime(LocalDateTime.now());
                kwpSettlementWallet.setUpdateBy(LoginUserHolder.getUserId());
                kwpSettlementWallet.setUpdateTime(LocalDateTime.now());
                kwpSettlementWallet.setDelFlag(Global.UN_DELETED);
                settlementWalletMapper.insert(kwpSettlementWallet);
                //货到付款-更新对账单已付金额
                kwpLedgerTradeService.updateActualPrice(byId.getLedgerId(), price);
                //更新交易结算单状态和金额
                KwpSettlementTrade kwpSettlementTrade = new KwpSettlementTrade();
                kwpSettlementTrade.setId(byId.getId());
                kwpSettlementTrade.setActualPrice(byId.getActualPrice().add(price));
                int status = subtract.compareTo(new BigDecimal("0.0")) == NumberConstant.ZERO ? SettlementEnum.ALL_PAYMENT.getStatus() : SettlementEnum.PARTIAL_PAYMENT.getStatus();
                kwpSettlementTrade.setStatus(status);
                kwpSettlementTrade.setUpdateBy(LoginUserHolder.getUserId());
                kwpSettlementTrade.setUpdateTime(LocalDateTime.now());
                kwpSettlementTradeService.updateById(kwpSettlementTrade);

                settlementTradeTrackService.save(KwpSettlementTradeTrack.build(byId.getId(), SettlementTrackEnum.RECEIVE_PAY.getStatus()));
                //更新贸易订单状态
                if (status == SettlementEnum.ALL_PAYMENT.getStatus()) {
                    //查询对账单关联的订单
                    List<KwpLedgerTradeOrder> kwpLedgerTradeOrders = tradeOrderService.queryList(byId.getLedgerId());
                    if (CollectionUtils.isEmpty(kwpLedgerTradeOrders)) {
                        throw new BusinessException("未找到关联的贸易订单");
                    }
                    List<Long> list = kwpLedgerTradeOrders.stream().map(KwpLedgerTradeOrder::getTOrderId).toList();
                    for (Long aLong : list) {
                        UpdateOrderStatusParam updateOrderStatusParam = new UpdateOrderStatusParam();
                        updateOrderStatusParam.setTOrderId(aLong);
                        updateOrderStatusParam.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_7.getValue()));
                        updateOrderStatusParam.setUpdateBy(LoginUserHolder.getUserId());
                        updateOrderStatusParam.setUpdateByName(LoginUserHolder.getUserName());
                        tradeOrderInfoService.updateOrderStatus(updateOrderStatusParam);
                    }
                }
                //电子钱包清分接口
                walletBusinessService.splitMoney(orderNo, uid, filter, channelEnum, price, "2");

                //推送双方系统管理员
                messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                    put("company", kwpLedgerTradeUnit.getFirmName());
                    put("number", byId.getStOrderNo());
                }}, kwpLedgerTradeUnit2.getEntId(), MessageEnum.SETTLEMENT_START_SELL);
                messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                    put("company", kwpLedgerTradeUnit2.getFirmName());
                    put("number", byId.getStOrderNo());
                }}, kwpLedgerTradeUnit.getEntId(), MessageEnum.SETTLEMENT_START_PURCHASE);
                return "付款确认成功";
            } finally {
                redisLockUtil.unlock(key);
            }
        }
        return "请勿重复提交!";
    }

    /**
     * 预付款、货到付款记录
     * 前端接口分开
     *
     * @param settlementWalletReq 请求参数
     * @return
     */
    public PageRes<SettlementWalletVo> pageList(SettlementWalletReq settlementWalletReq) {
        PageHelper.startPage(settlementWalletReq.getPage(), settlementWalletReq.getPageSize());
        List<SettlementWalletDto> settlementWalletDto = settlementWalletMapper.pageList(settlementWalletReq);

        if (CollectionUtils.isEmpty(settlementWalletDto)) {
            return new PageRes<>();
        }
        //增加对应创建人和更新人名称
        Map<Long, UserCacheResDto> map = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        PageInfo<SettlementWalletDto> pageInfo = new PageInfo<>(settlementWalletDto);
        DecimalFormat df = new DecimalFormat("0.00");
        //指定返回值
        List<SettlementWalletVo> collect = settlementWalletDto.stream().map(a -> {
            SettlementWalletVo settlementWalletVo = new SettlementWalletVo();
            BeanUtils.copyProperties(a, settlementWalletVo);
            Long createBy = a.getCreateBy();
            Long updateBy = a.getUpdateBy();
            UserCacheResDto userCacheResDto = map.get(createBy);
            if (Objects.isNull(userCacheResDto)) {
                userCacheResDto = remoteSystemService.queryUserCacheById(createBy);
                map.put(createBy, userCacheResDto);
            }
            if (Objects.nonNull(userCacheResDto)) {
                settlementWalletVo.setCreateByText(userCacheResDto.getName());
            }
            userCacheResDto = map.get(updateBy);
            if (Objects.isNull(userCacheResDto)) {
                userCacheResDto = remoteSystemService.queryUserCacheById(updateBy);
                map.put(updateBy, userCacheResDto);
            }
            if (Objects.nonNull(userCacheResDto)) {
                settlementWalletVo.setUpdateByText(userCacheResDto.getName());
            }
            settlementWalletVo.setPayPrice(df.format(Objects.isNull(a.getPayPrice()) ? new BigDecimal("0.0") : a.getPayPrice()));
            settlementWalletVo.setTopayPrice(df.format(Objects.isNull(a.getTopayPrice()) ? new BigDecimal("0.0") : a.getTopayPrice()));
            return settlementWalletVo;
        }).collect(Collectors.toList());
        return PageRes.build(pageInfo, collect);
    }


    /**
     * 销售-预付款
     * 贸易订单下单时，冻结资金
     * 预付款结算时，解冻资金。在进行清分。
     *
     * @param id 结算单id
     * @return
     */
    @GlobalTransactional(name = "default_tx_group", rollbackFor = Exception.class)
    public String confirmTradeCollection(Long id) {
        log.info("销售预付款确认,结算单id：{}", id);
        String key = String.format(RedisConstant.SETTLEMENT_KEY, id);
        SettlementTradeDto byId = kwpSettlementTradeService.getById(id, TradeUnitType.PURCHASE);
        if (Objects.isNull(byId)) {
            throw new BusinessException("结算单不存在");
        }
        if (StringUtils.isNotBlank(byId.getTrading()) && !byId.getTrading().startsWith(TradingEnum.PRE_PAY.getValue())) {
            throw new BusinessException("只支持预付款交易方式进行预付款确认操作");
        }
        //冻结编号非空校验
        List<KwpLedgerTradeOrder> kwpLedgerTradeOrders = tradeOrderService.queryList(byId.getLedgerId());
        if (CollectionUtils.isEmpty(kwpLedgerTradeOrders)) {
            throw new BusinessException("未找到关联的贸易订单");
        }
        for (KwpLedgerTradeOrder kwpLedgerTradeOrder : kwpLedgerTradeOrders) {
            if (StringUtils.isBlank(kwpLedgerTradeOrder.getOrderNo())) {
                throw new BusinessException(String.format("为找到贸易订单id[%s]的冻结单号", kwpLedgerTradeOrder.getTOrderId()));
            }
        }
        KwpLedgerTradeUnit kwpLedgerTradeUnit = tradeUnitService.queryCustomerEnt(byId.getLedgerId(), TradeUnitType.PURCHASE);
        KwpLedgerTradeUnit kwpLedgerTradeUnit2 = tradeUnitService.queryCustomerEnt(byId.getLedgerId(), TradeUnitType.SELL);
        String uid = walletRelationService.getRelation(kwpLedgerTradeUnit.getTopEntId());
        if (StringUtils.isBlank(uid)) {
            throw new BusinessException("客户单位暂未开通电子钱包");
        }
        String filter = walletRelationService.getRelation(kwpLedgerTradeUnit2.getTopEntId());
        if (StringUtils.isBlank(filter)) {
            throw new BusinessException("我方单位暂未开通电子钱包");
        }
        ChannelEnum channelEnum = ChannelEnum.getByTrading(byId.getTrading());
        if (Objects.isNull(channelEnum)) {
            throw new BusinessException("交易方式不存在");
        }
        if (redisLockUtil.tryLock(key)) {
            try {
                //更新交易结算单状态和金额
                KwpSettlementTrade kwpSettlementTrade = new KwpSettlementTrade();
                kwpSettlementTrade.setId(byId.getId());
                kwpSettlementTrade.setActualPrice(byId.getTotalPrice());
                kwpSettlementTrade.setStatus(SettlementEnum.ALL_PAYMENT.getStatus());
                kwpSettlementTrade.setUpdateBy(LoginUserHolder.getUserId());
                kwpSettlementTrade.setUpdateTime(LocalDateTime.now());
                kwpSettlementTradeService.updateById(kwpSettlementTrade);
                //预付款-更新对账单已付金额
                kwpLedgerTradeService.updateActualPrice(byId.gettLedgerId(), byId.getTotalPrice());
                //新增电子钱包结算记录
                //清分单号
                String orderNo = OrderUtils.generateOrderNo("ST");
                KwpSettlementWallet kwpSettlementWallet = new KwpSettlementWallet();
                kwpSettlementWallet.setId(new IdWorker(1).nextId());
                kwpSettlementWallet.setEntId(LoginUserHolder.getEntId());
                kwpSettlementWallet.setOrderNo(orderNo);
                kwpSettlementWallet.setSettlementId(byId.getId());
                kwpSettlementWallet.setOrderType(SettlementOrderTypeEnum.TRADE.getStatus());
                kwpSettlementWallet.setChannel(WalletChannelEnum.getValue(byId.getTrading()));
                kwpSettlementWallet.setPayTime(LocalDateTime.now());
                kwpSettlementWallet.setPayPrice(byId.getTotalPrice());
                kwpSettlementWallet.setTopayPrice(new BigDecimal("0.0"));
                kwpSettlementWallet.setType(SettlementWalletPayTypeEnum.ADVANCE_PAYMENT.getStatus());
                kwpSettlementWallet.setRemark(Global.EMPTY_STRING);
                kwpSettlementWallet.setStatus(NumberConstant.ZERO);
                kwpSettlementWallet.setCreateBy(LoginUserHolder.getUserId());
                kwpSettlementWallet.setCreateTime(LocalDateTime.now());
                kwpSettlementWallet.setUpdateBy(LoginUserHolder.getUserId());
                kwpSettlementWallet.setUpdateTime(LocalDateTime.now());
                kwpSettlementWallet.setDelFlag(Global.UN_DELETED);
                settlementWalletMapper.insert(kwpSettlementWallet);
                settlementTradeTrackService.save(KwpSettlementTradeTrack.build(byId.getId(), SettlementTrackEnum.PRE_PAY.getStatus()));
                //dubbo更新销售订单状态为-已结算
                for (KwpLedgerTradeOrder kwpLedgerTradeOrder : kwpLedgerTradeOrders) {
                    UpdateOrderStatusParam updateOrderStatusParam = new UpdateOrderStatusParam();
                    updateOrderStatusParam.setTOrderId(kwpLedgerTradeOrder.getTOrderId());
                    updateOrderStatusParam.setStatus(Integer.valueOf(DictEnum.TORDER_STATUS_7.getValue()));
                    updateOrderStatusParam.setUpdateBy(LoginUserHolder.getUserId());
                    updateOrderStatusParam.setUpdateByName(LoginUserHolder.getUserName());
                    tradeOrderInfoService.updateOrderStatus(updateOrderStatusParam);
                }


                /*电子钱包相关业务*/
                //批量获取对账单关联的贸易订单 再获取冻结编号，批量解冻
                for (KwpLedgerTradeOrder kwpLedgerTradeOrder : kwpLedgerTradeOrders) {
                    R<BusinessNo> businessNoR = payCenterService.walletUnFreeze(kwpLedgerTradeOrder.getOrderNo());
                    if (!businessNoR.getStatus()) {
                        throw new BusinessException(businessNoR.getMsg());
                    }
                }
                //对结算单中的总计金额进行清分
                walletBusinessService.splitMoney(orderNo, uid, filter, channelEnum, byId.getTotalPrice(), "1");
                //推送双方系统管理员
                messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                    put("company", kwpLedgerTradeUnit.getFirmName());
                    put("number", byId.getStOrderNo());
                }}, kwpLedgerTradeUnit2.getEntId(), MessageEnum.SETTLEMENT_CONFIRM_SELL);
                messageSender.sendManager(LoginUserHolder.getUserId(), new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                    put("company", kwpLedgerTradeUnit2.getFirmName());
                    put("number", byId.getStOrderNo());
                }}, kwpLedgerTradeUnit.getEntId(), MessageEnum.SETTLEMENT_CONFIRM_PURCHASE);

                //todo-xcq 调用中台接口


                return "确认回款成功";
            } finally {
                redisLockUtil.unlock(key);
            }
        }
        return "请勿重复提交！";
    }

    /**
     * 物流，货到付款（付钱方） 查询电子钱余额
     *
     * @param id
     * @return
     */
    public Object getConfirmLogisticsPayment(Long id) {
        SettlementLogisticsDto byId = kwpSettlementLogisticsService.detail(id, LogisticsUnitType.CARRIER, LogisticsUnitType.SHIPPER);
        if (Objects.isNull(byId)) {
            throw new BusinessException("结算单不存在");
        }
        if (StringUtils.isNotBlank(byId.getTrading()) && !byId.getTrading().startsWith(TradingEnum.RECEIVE_PAY.getValue())) {
            throw new BusinessException("只支持货货到付款方式订单进行当前操作");
        }
        List<LedgerUnitDto> listById = kwpSettlementLogisticsService.getListById(id);
        if (CollectionUtils.isEmpty(listById) || listById.size() != NumberConstant.TWO) {
            throw new BusinessException("对账单交易企业双方不存在或缺少");
        }
        return getWalletBalance(listById, byId.getTrading());
    }


    /**
     * 货到付款-查询钱包余额
     *
     * @param id 结算单id
     * @return
     */
    public Object getConfirmTradePayment(Long id) {
        SettlementTradeDto byId = kwpSettlementTradeService.getById(id, TradeUnitType.SELL);
        if (Objects.isNull(byId)) {
            throw new BusinessException("结算单不存在");
        }
        if (StringUtils.isNotBlank(byId.getTrading()) && !byId.getTrading().startsWith(TradingEnum.RECEIVE_PAY.getValue())) {
            throw new BusinessException("只支持货到付款方式订单进行当前操作");
        }
        List<LedgerUnitDto> listById = kwpSettlementTradeService.getListById(id);
        if (CollectionUtils.isEmpty(listById) || listById.size() != NumberConstant.TWO) {
            throw new BusinessException("对账单交易企业双方不存在或缺少");
        }
        return getWalletBalance(listById, byId.getTrading());
    }

    /**
     * 查询交易双方的电子钱包
     *
     * @param listById 双发企业
     * @param trading  交易方式
     * @return
     */
    private WalletVo getWalletBalance(List<LedgerUnitDto> listById, String trading) {
        Long uid = null;
        Long filter = null;
        for (LedgerUnitDto ledgerUnitDto : listById) {
            Integer unitType = ledgerUnitDto.getUnitType();
            if (TradeUnitType.PURCHASE.equals(unitType)) {
                uid = ledgerUnitDto.getTopEntId();
                continue;
            }
            if (TradeUnitType.SELL.equals(unitType)) {
                filter = ledgerUnitDto.getTopEntId();
            }
        }
        String relation = walletRelationService.getRelation(uid);
        String filterUser = walletRelationService.getRelation(filter);
        if (StringUtils.isBlank(relation) || StringUtils.isBlank(filterUser)) {
            throw new BusinessException("顶级企业未开通电子钱包");
        }
        R<List<WalletDto>> wallet = payCenterService.wallet(relation, ChannelEnum.getByTrading(trading), filterUser);
        if (CollectionUtils.isEmpty(wallet.getData())) {
            throw new BusinessException("交易双方暂未开通电子钱包");
        }
        List<WalletDto> data = wallet.getData();
        WalletDto walletDto = data.get(NumberConstant.ZERO);
        if (Objects.isNull(walletDto)) {
            return null;
        }
        WalletVo walletVo = BeanUtil.toBean(walletDto, WalletVo.class);
        walletVo.setFreeze(Objects.nonNull(walletDto.getFreeze()) ? BigDecimal.valueOf(walletDto.getFreeze() / 100D) : new BigDecimal("0"));
        walletVo.setApMoney(Objects.nonNull(walletDto.getApMoney()) ? BigDecimal.valueOf(walletDto.getApMoney() / 100D) : new BigDecimal("0"));
        walletVo.setTotalMoney(Objects.nonNull(walletDto.getTotalMoney()) ? BigDecimal.valueOf(walletDto.getTotalMoney() / 100D) : new BigDecimal("0"));
        walletVo.setMoney(Objects.nonNull(walletDto.getMoney()) ? BigDecimal.valueOf(walletDto.getMoney() / 100D) : new BigDecimal("0"));
        walletVo.setChargingMoney(Objects.nonNull(walletDto.getChargingMoney()) ? BigDecimal.valueOf(walletDto.getChargingMoney() / 100D) : new BigDecimal("0"));
        walletVo.setWithdrawingMoney(Objects.nonNull(walletDto.getWithdrawingMoney()) ? BigDecimal.valueOf(walletDto.getWithdrawingMoney() / 100D) : new BigDecimal("0"));
        return walletVo;
    }

    /**
     * 查询结算记录
     *
     * @param id      结算单id
     * @param status  订单类型 1-物流 2-贸易
     * @param payType 支付方式 1-预付款、2-货到付款
     */
    public List<SettlementVo> queryList(Long id, int status, Integer payType) {
        SettlementWalletReq settlementWalletReq = new SettlementWalletReq();
        settlementWalletReq.setPayType(payType);
        settlementWalletReq.setOrderType(status);
        settlementWalletReq.setId(String.valueOf(id));
        return settlementWalletMapper.appList(settlementWalletReq);
    }
}

