package com.yonge.cooleshow.biz.dal.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.microsvc.toolkit.common.response.paging.QueryInfo;
import com.microsvc.toolkit.common.tools.ThreadPool;
import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
import com.microsvc.toolkit.middleware.payment.common.api.BasePaymentService;
import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
import com.microsvc.toolkit.middleware.payment.common.api.entity.*;
import com.microsvc.toolkit.middleware.payment.common.api.enums.DivideBackStatus;
import com.microsvc.toolkit.middleware.payment.common.api.enums.PaymentStatus;
import com.microsvc.toolkit.middleware.payment.enums.EPaymentVendor;
import com.yonge.cooleshow.biz.dal.dao.UserOrderDetailDao;
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
import com.yonge.cooleshow.biz.dal.entity.*;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.enums.coupon.CouponUseStateEnum;
import com.yonge.cooleshow.biz.dal.mapper.CouponInfoMapper;
import com.yonge.cooleshow.biz.dal.queryInfo.CouponInfoQuery;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
import com.yonge.cooleshow.biz.dal.wrapper.coupon.CouponOrderWrapper;
import com.yonge.cooleshow.common.enums.*;
import com.yonge.cooleshow.common.enums.payment.EPaymentChannel;
import com.yonge.cooleshow.common.enums.payment.EPaymentStatus;
import com.yonge.cooleshow.common.enums.payment.EPaymentType;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.payment.base.enums.TradeStatusEnum;
import com.yonge.toolset.payment.util.DistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.yonge.cooleshow.common.enums.payment.EPaymentStatus.PAID;

/**
 * 用户支付订单服务
 * Created by Eric.Shang on 2022/12/22.
 */
@Slf4j
@Service
public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private PaymentServiceContext paymentServiceContext;

    @Autowired
    private RedisCacheService redisCacheService;

    @Autowired
    private SysUserContractRecordService sysUserContractRecordService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private UserPaymentOrderService userPaymentOrderService;

    @Autowired
    private UserOrderDetailService userOrderDetailService;

    @Autowired
    private UserOrderService userOrderService;

    @Autowired
    private MemberPriceSettingsService memberPriceSettingsService;

    @Autowired
    private CourseGroupService courseGroupService;
    @Autowired
    private CourseScheduleService scheduleService;
    @Autowired
    private VideoLessonPurchaseRecordService recordService;
    @Autowired
    private MusicSheetService musicSheetService;
    @Autowired
    private PianoRoomBuyRecordService pianoRoomBuyRecordService;


    @Autowired
    private ActivityPlanService activityPlanService;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private CouponInfoMapper couponInfoMapper;


    @Autowired
    private TenantAlbumService tenantAlbumService;

    @Autowired
    private PaymentDivMemberRecordService paymentDivMemberRecordService;

    @Autowired
    private TenantAlbumMusicService tenantAlbumMusicService;


    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    private VideoLessonGroupService videoLessonGroupService;

    @Autowired
    private TeacherService teacherService;

    @Autowired
    private PaymentMerchantConfigService paymentMerchantConfigService;

    @Autowired
    private UserOrderRefundService userOrderRefundService;

    @Autowired
    private UserOrderRefundBillService userOrderRefundBillService;

    @Autowired
    private UserOrderDetailDao userOrderDetailDao;

    @Autowired
    private TenantMemberService tenantMemberService;

    @Autowired
    private DivBackRecordService divBackRecordService;


    // 订单商品参数校验，获取订单支付金额
    private static final Map<GoodTypeEnum, Consumer<UserPaymentOrderWrapper.OrderGoodsInfo>> orderGoodsCreate = Maps.newHashMap();


    // 支付创建前，数据库存
    private static final Map<EPaymentType, Consumer<UserPaymentOrderWrapper.UserPaymentOrder>> orderSuccessBefore = Maps.newHashMap();

    // 订单支付后
    private static final Map<GoodTypeEnum, Consumer<UserPaymentOrderWrapper.OrderGoodsInfo>> orderSuccessAfter = Maps.newHashMap();


    // 订单完成后执行
    private static final Map<GoodTypeEnum, Consumer<UserOrderDetailVo>> paymentSuccess = Maps.newHashMap();
    @Autowired
    private StudentService studentService;


    @PostConstruct
    private void init() {

        /**********订单生成前 商品校验******************/

        /* 订单前数据处理*/
        //vip开通缴费
        orderGoodsCreate.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderCreate);
        orderGoodsCreate.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderCreate);
        orderGoodsCreate.put(GoodTypeEnum.DISCOUNT, memberPriceSettingsService::discountCreate);
        //直播课程购买
        orderGoodsCreate.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourse);
        //趣纠课购买
        orderGoodsCreate.put(GoodTypeEnum.PRACTICE, scheduleService::buyPracticeCourse);
        //视频课购买
        orderGoodsCreate.put(GoodTypeEnum.VIDEO, recordService::buyVideoCourse);
        //曲目购买
        orderGoodsCreate.put(GoodTypeEnum.MUSIC, musicSheetService::buyMusicSheetCheck);
        // 专辑购买
        orderGoodsCreate.put(GoodTypeEnum.ALBUM, musicSheetService::buyMusicSheetCheck);
        //琴房时长
        orderGoodsCreate.put(GoodTypeEnum.PIANO_ROOM, pianoRoomBuyRecordService::orderCreate);
        //活动报名
        orderGoodsCreate.put(GoodTypeEnum.ACTI_REGIST, activityPlanService::orderCreate);

        // 机构专辑
        orderGoodsCreate.put(GoodTypeEnum.TENANT_ALBUM, tenantAlbumService::orderCreate);
        orderGoodsCreate.put(GoodTypeEnum.VIP_COURSE, scheduleService::buyPracticeCourse);

        /**********订单生成后 数据处理******************/
        //曲目购买
        orderSuccessAfter.put(GoodTypeEnum.MUSIC, musicSheetService::orderAfterSheet);
        // 专辑购买
        orderSuccessAfter.put(GoodTypeEnum.ALBUM, musicSheetService::orderAfterSheet);
        // 机构专辑
        orderSuccessAfter.put(GoodTypeEnum.TENANT_ALBUM, tenantAlbumService::orderAfterSheet);


        //直播课程购买
        orderSuccessAfter.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourseAfter);
        //趣纠课购买
        orderSuccessAfter.put(GoodTypeEnum.PRACTICE, scheduleService::buyPracticeCourseAfter);
        orderSuccessAfter.put(GoodTypeEnum.VIP_COURSE, scheduleService::buyPracticeCourseAfter);
        //视频课购买
        orderSuccessAfter.put(GoodTypeEnum.VIDEO, recordService::buyVideoCourseAfter);

        /**********订单完成后 数据处理******************/
        // 沿用以前的流程

        // 分账处理 写入分账记录
        paymentSuccess.put(GoodTypeEnum.TENANT_ALBUM, paymentDivMemberRecordService::tenantAlbum);
        paymentSuccess.put(GoodTypeEnum.MUSIC, paymentDivMemberRecordService::musicSheet);
        paymentSuccess.put(GoodTypeEnum.PRACTICE, paymentDivMemberRecordService::practiceCourse);
        paymentSuccess.put(GoodTypeEnum.VIP_COURSE, paymentDivMemberRecordService::practiceCourse);
        paymentSuccess.put(GoodTypeEnum.LIVE, paymentDivMemberRecordService::liveCourse);
        paymentSuccess.put(GoodTypeEnum.VIDEO, paymentDivMemberRecordService::videoCourse);
        paymentSuccess.put(GoodTypeEnum.ALBUM, paymentDivMemberRecordService::musicSheet);
        paymentSuccess.put(GoodTypeEnum.VIP, paymentDivMemberRecordService::vip);
        paymentSuccess.put(GoodTypeEnum.SVIP, paymentDivMemberRecordService::vip);
        paymentSuccess.put(GoodTypeEnum.DISCOUNT, paymentDivMemberRecordService::discount);
        paymentSuccess.put(GoodTypeEnum.ACTI_REGIST, paymentDivMemberRecordService::activity);
        paymentSuccess.put(GoodTypeEnum.PIANO_ROOM, paymentDivMemberRecordService::pianoRoom);

        /**********订单取消后******************/
        // 沿用以前的流程


        log.info("---> orderCreate.Keys={}", orderGoodsCreate.keySet());
        log.info("---> paymentSuccess.Keys={}", paymentSuccess.keySet());
        log.info("---> orderSuccessBefore.Keys={}", orderSuccessBefore.keySet());
    }


    /**
     * 支付回调消息
     *
     * @param paymentResp PaymentResp
     *
     */
    @Transactional
    @Override
    public void executePaymentCallback(PaymentResp paymentResp) {

        String lockName = redisCacheService.getPaymentCacheKey(paymentResp.getMerOrderNo());
        // 订单分布式锁状态
        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

            // 获取订单信息
            UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo( paymentResp.getMerOrderNo());
            if (Objects.isNull(paymentOrder)) {
                log.error("executePaymentCallback 无效的支付订单, paymentResp={}", JSON.toJSONString(paymentResp));
                throw new BizException("无效的支付订单");
            }

            // 订单状态为待支付、支付中时，更新订单状态；
            if (EPaymentStatus.WAIT_PAY == paymentOrder.getStatus() || EPaymentStatus.PAYING == paymentOrder.getStatus() || PAID == paymentOrder.getStatus()) {

                // 支付成功
                if (PaymentStatus.SUCCESSED == paymentResp.getPaymentStatus()) {
                    // 根据支付回调消息，更新订单状态
                    executePaymentSuccess(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(paymentOrder)), paymentResp);
                }

                // 支付失败
                if (PaymentStatus.FAILED == paymentResp.getPaymentStatus() || PaymentStatus.CLOSED == paymentResp.getPaymentStatus()) {

                    // 支付失败，取消订单且更新订单状态
                    UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder
                        .builder()
                        .transNo(paymentResp.getTransNo())
                        .id(paymentOrder.getId())
                        .status(PaymentStatus.FAILED == paymentResp.getPaymentStatus() ? EPaymentStatus.FAIL: EPaymentStatus.CLOSED)
                        .updateTime(DateTime.now().toDate())
                        .build();
                    userPaymentOrderService.updateById(order);

                    // 订单关闭后的数据处理流程
                    userOrderService.payCancel(userOrderService.detail(order.getId()));
                }

                log.info("executePaymentCallback WAIT_PAY, status={}, paymentResp={}", paymentOrder.getStatus(),
                    JSON.toJSONString(paymentResp));
            } else {

                // 支付成功
                if (PaymentStatus.SUCCESSED == paymentResp.getPaymentStatus()) {
                    // 根据支付回调消息，更新订单状态
                    refundOnly("订单已超时，金额原路退回", paymentOrder.getOrderNo());
                }
            }

        }, 60L, TimeUnit.SECONDS);

        log.info("executePaymentCallback paymentResp={}", JSON.toJSONString(paymentResp));
    }

    /**
     * 支付成功处理流程
     *
     * @param paymentOrder UserPaymentOrderWrapper.UserPaymentOrder
     * @param paymentResp  PaymentResp
     */
    @Transactional
    @Override
    public void executePaymentSuccess(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentResp paymentResp) {

        // 订单已完成，直接忽略后续流程
        if (EPaymentStatus.WAIT_PAY != paymentOrder.getStatus() && EPaymentStatus.PAYING != paymentOrder.getStatus()) {
            return;
        }

        // 支付回调消息，修改订单状态
        Date date = DateTime.now().toDate();

        UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder
            .builder()
            .id(paymentOrder.getId())
            .status(PAID)
            .payTime(date)
            .updateTime(date)
            .build();

        // 三方支付费用
        if (Objects.nonNull(paymentResp)) {

            // 更新交易时间和服务费用
            order.payTime(Optional.ofNullable(paymentResp.getTriggerTime()).orElse(order.getPayTime()))
                .paymentChannelFee(paymentResp.getServiceCharge())
                .setTransNo(paymentResp.getTransNo());
        }
        userPaymentOrderService.updateById(order);

        // 分账处理

        // 机构学生订单支付成功，处理分账
        paySuccess(userOrderService.detail(order.getId()));

        // 生成协议
        try {
            sysUserContractRecordService.sign(ContractTemplateTypeEnum.BUY_ORDER, SysUserType.valueOf(paymentOrder.getPaymentClient().name()),
                    sysUserService.findUserById(paymentOrder.getUserId()));
        } catch (Exception e) {
            log.error("executePaymentSuccess 生成协议失败, userId={}, orderNo={}", paymentOrder.getUserId(), paymentOrder.getOrderNo());
        }

        log.info("executePaymentSuccess userId={}, biz={}, orderNo={}", paymentOrder.getUserId(), paymentOrder.getBizId(), paymentOrder.getOrderNo());
    }



    /**
     * 支付成功后续处理
     *
     * @param detail
     */
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(UserOrderVo detail) {
        //调用业务
        List<UserOrderDetailVo> orderDetailList = userOrderDetailService.getOrderDetilListByOrderNo(detail.getOrderNo());

        for (UserOrderDetailVo orderDetailVo : orderDetailList) {
            orderDetailVo.setUserId(detail.getUserId());
            orderDetailVo.setOrderId(detail.getId());
            orderDetailVo.setRecomUserId(detail.getRecomUserId());
            orderDetailVo.setActivityId(detail.getActivityId());
            orderDetailVo.setRewardId(detail.getRewardId());
            orderDetailVo.setOrderType(detail.getOrderType());
            orderDetailVo.setOrderClient(detail.getOrderClient());
            orderDetailVo.setPaymentVendor(detail.getPaymentVendor());

            //调用业务
            Consumer<UserOrderDetailVo> userOrderVoConsumer = paymentSuccess.get(orderDetailVo.getGoodType());
            if (!Objects.isNull(userOrderVoConsumer)) {
                userOrderVoConsumer.accept(orderDetailVo);

            }
            //清除商家统计缓存
            Long merchId = orderDetailVo.getMerchId();
            if (merchId != null && merchId != 0) {
                redissonClient.getBucket(CacheNameEnum.TEACHER_TOTAL.getRedisKey(merchId)).delete();
            }
        }

        // 记录活动参与
        userOrderService.saveActivityRecord(detail);
        //清除买家统计缓存
        if (ClientEnum.STUDENT.getCode().equals(detail.getPaymentClient())) {
            redissonClient.getBucket(CacheNameEnum.STUDENT_TOTAL.getRedisKey(detail.getUserId())).delete();
        } else if (ClientEnum.TEACHER.getCode().equals(detail.getPaymentClient())) {
            redissonClient.getBucket(CacheNameEnum.TEACHER_TOTAL.getRedisKey(detail.getUserId())).delete();
        }
    }

    /**
     * 取消订单支付
     *
     * @param paymentOrder UserPaymentOrderWrapper.UserPaymentOrder
     * @param paymentResp  PaymentResp
     */
    @Transactional
    @Override
    public void cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentResp paymentResp) {

        // 同步三方订单支付状态
        String lockName = redisCacheService.getPaymentCacheKey(paymentOrder.getOrderNo());

        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

            // 订单支付已完成
            if (PaymentStatus.SUCCESSED == paymentResp.getPaymentStatus()) {

                // 关闭当前事务，提交订单支付完成流程
                ThreadPool.getExecutor().submit(() -> {
                    // 完成订单支付流程
                    executePaymentSuccess(paymentOrder, paymentResp);
                });

                // 提示订单支付已完成
                throw new BizException("订单支付已完成");
            } else

            // 三方订单关闭
            if ((PaymentStatus.CLOSED == paymentResp.getPaymentStatus() || PaymentStatus.FAILED == paymentResp.getPaymentStatus())
                && EPaymentStatus.CLOSED != paymentOrder.getStatus()) {

                // 更新订单状态为已关闭
                closeWaitOrder(paymentOrder);
            } else

            // 订单未支付，后续直接更新订单状态为已关闭
            if (PaymentStatus.PENDDING == paymentResp.getPaymentStatus()) {

                UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder
                    .builder()
                    .id(paymentOrder.getId())
                    .status(EPaymentStatus.CLOSED)
//                    .errorMsg(errorMessage)
                    .updateTime(DateTime.now().toDate())
                    .build();


                String errorMessage = null;
                try {
                    // 关闭三方支付订单状态
                    PaymentClose paymentClose = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
                        .close(paymentOrder.getTransNo(), "用户取消支付", paymentOrder.getOrderNo());

                    if (Objects.nonNull(paymentClose)) {
                        errorMessage = paymentClose.getMsg();

                        // 订单取消，三方返回异常信息
                        if (StringUtils.isNotEmpty(errorMessage)) {
                            log.warn("cancelPayment orderNo={}, ex={}", paymentOrder.getOrderNo(), errorMessage);
                            // 记录异常消息
                            ThreadPool.getExecutor().submit(() -> {
                                order.setErrorMsg(paymentClose.getMsg());

                                // 更新订单退款异常信息
                                userPaymentOrderService.updateById(order);

                            });
                            throw new BizException("查询交易中，请耐心等待!");
                        }
                    }
                } catch (Exception e) {
                    log.error("cancelPayment orderNo={}", paymentOrder.getOrderNo(), e);
                    throw new BizException("查询交易中，请耐心等待!");
                }

                // 更新订单状态为已关闭
                paymentOrder.setErrorMsg(errorMessage);
                closeWaitOrder(paymentOrder);

            }

        }, 10L, TimeUnit.SECONDS);
    }

    /**
     * 用户下单请求
     *
     * @param orderReq UserPaymentOrderWrapper.UserPaymentOrder
     */
    @Override
    @Transactional
    public UserPaymentOrderWrapper.PaymentConfig executeOrderCreate(UserPaymentOrderWrapper.UserPaymentOrder orderReq) {

        try {

            // 商品校验 orderCreate

            // 用户下单请求锁
            // 生成用户支付订单
            return DistributedLock.of(redissonClient).runIfLockToFunction(CacheNameEnum.LOCK_EXECUTE_ORDER.getRedisKey(orderReq.getUserId()),
                    this::executeOrder, orderReq, 10L);

        } catch (BizException e) {
            log.error("executeOrder BizException, orderReq={}",  orderReq.jsonString(), e);

            throw e;
        } catch (Exception e) {
            log.error("executeOrder 下单失败,  orderReq={}", orderReq.jsonString(), e);

            throw new BizException("下单失败");
        }
    }

    /**
     * 用户下单请求
     *
     * @param orderReq UserPaymentOrderWrapper.UserPaymentOrder
     */
    @Transactional
    @Override
    public UserPaymentOrderWrapper.PaymentConfig executeOrder(UserPaymentOrderWrapper.UserPaymentOrder orderReq) {

        // 填充订单基本信息
        String defaultService = paymentServiceContext.defaultService();
        if (EPayerType.ORIGINAL.getCode().toLowerCase().equals(defaultService)) {
            // 原生支付需要传入支付三方渠道
            if (StringUtils.isEmpty(orderReq.getPaymentType())) {
                throw new BizException("支付三方渠道不能为空");
            }
        }
        orderReq
            .orderNo(IdWorker.getIdStr())
            .paymentVender(Optional.ofNullable(orderReq.getPaymentType()).orElse(defaultService))
            .paymentChannel("")
            .status(EPaymentStatus.WAIT_PAY)
            .originalPrice(BigDecimal.ZERO);

        List<UserOrderDetail> orderDetails = new ArrayList<>();

        // 检查是否有畅学卡
        if (orderReq.getPaymentClient() == ClientEnum.STUDENT) {
            // 检查畅学卡
            checkDiscountCard(orderReq);
        }

        // 检查活动，如果是会员买赠活动，检查商品和赠送商品是否匹配
        if (orderReq.getActivityId() !=null ) {
            checkActivity(orderReq);
        }

        // 购买商品信息
        for (UserPaymentOrderWrapper.OrderGoodsInfo item : orderReq.getGoodsInfos()) {

            // 数据赋值
            item.setOrderNo(orderReq.getOrderNo());
            item.setSubOrderNo(IdWorker.getIdStr());
            item.setActivityId(orderReq.getActivityId());
            item.setUserId(orderReq.getUserId());
            item.setPaymentClient(orderReq.getPaymentClient());
            item.setRecomUserId(orderReq.getRecomUserId());

            // 商品基本信息
            if (orderGoodsCreate.containsKey(item.getGoodType())) {
                // 填充商品基础信息，校验参数合法以性
                orderGoodsCreate.get(item.getGoodType()).accept(item);
                UserOrderDetail userOrderDetail = item.getUserOrderDetail();
                userOrderDetail.setGiftFlag(item.getGiftFlag());
                orderDetails.add(userOrderDetail);
            }

            // 计算畅学卡
            userOrderService.discountCard(item);

        }

        // 是否使用优惠券
        if (StringUtils.isNotEmpty(orderReq.getCouponIds())) {
            checkCoupon(orderReq);

        }

        // 计算原始价格
        BigDecimal originalPrice = orderDetails.stream()
            .map(UserOrderDetail::getOriginalPrice)
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 支付金额
        BigDecimal currentPrice = orderDetails.stream()
            .map(UserOrderDetail::getExpectPrice)
            .reduce(BigDecimal.ZERO, BigDecimal::add);


        // 优惠金额
        BigDecimal couponAmount = orderDetails.stream()
                .map(UserOrderDetail::getCouponAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 实际支付金额
        BigDecimal cashAmount = orderDetails.stream()
            .map(UserOrderDetail::getActualPrice)
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (couponAmount.compareTo(currentPrice) >0) {
            couponAmount = currentPrice;
        }


        orderReq.originalPrice(originalPrice.setScale(2, RoundingMode.HALF_UP))
            .currentPrice(currentPrice.setScale(2, RoundingMode.HALF_UP))
            .paymentCouponAmount(couponAmount)
            .actualPrice(cashAmount.setScale(2, RoundingMode.HALF_UP));

        // 验证支付金额是否匹配
        if (orderReq.getActualPrice().compareTo(orderReq.getPaymentCashAmount()) != 0) {
            log.info("executeOrder actualPrice={}", orderReq.getActualPrice());
            throw new BizException(999,"支付金额不匹配");
        }

        // 订单入库前处理流程
        if (orderSuccessBefore.containsKey(orderReq.getOrderType())) {
            orderSuccessBefore.get(orderReq.getOrderType()).accept(orderReq);
        }

        // 验证成功后，订单入库

        // 查询支付三方配置
        BasePaymentService paymentService = paymentServiceContext.getPaymentService(orderReq.getPaymentVendor());
        if (Objects.nonNull(paymentService)) {
            // 设置支付三方AppId
            orderReq.setPaymentAppId(paymentService.getPaymentConfig().getAppId());
        }
        userPaymentOrderService.save(orderReq);

        userOrderDetailService.saveBatch(orderDetails);

        // 入库后处理流程
        for (UserPaymentOrderWrapper.OrderGoodsInfo item : orderReq.getGoodsInfos()) {
            item.setRecomUserId(orderReq.getRecomUserId());
            if (orderSuccessAfter.containsKey(item.getGoodType())) {
                orderSuccessAfter.get(item.getGoodType()).accept(item);
            }
        }

        // 更新用户订单优惠券使用状态
        if (StringUtils.isNotEmpty(orderReq.getCouponIds())) {

            couponInfoService.useCoupon(Long.parseLong(orderReq.getCouponIds()),orderReq.getOrderNo());
        }

        String subject = orderDetails.stream()
            .map(UserOrderDetail::getGoodName).collect(Collectors.joining(","));
        // 返回订单支付配置参数
        UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig = UserPaymentOrderWrapper.PaymentOrderReqConfig
            .builder()
            .merOrderNo(orderReq.getOrderNo())
            .subject(subject)
            .body(subject)
            .price(orderReq.getPaymentCashAmount().setScale(2, RoundingMode.HALF_UP))
            .expirationTime(DateTime.now().plusMinutes(120).toDate())
            .wxAppId(paymentServiceContext.getPaymentService(orderReq.getPaymentVendor()).getPaymentConfig().getWxAppId())
            .alipayAppId(paymentServiceContext.getPaymentService(orderReq.getPaymentVendor()).getPaymentConfig().getAlipayAppId())
            .userId(String.valueOf(orderReq.getUserId()))
            .build();

        // 缓存用户下单配置
        redisCacheService.saveUserOrderConfig(String.valueOf(orderReq.getUserId()), reqConfig.getMerOrderNo(), reqConfig.jsonString());

        UserPaymentOrderWrapper.PaymentConfig build = UserPaymentOrderWrapper.PaymentConfig.builder()
                .orderNo(orderReq.getOrderNo())
                .paymentConfig(reqConfig)
                .status(EPaymentStatus.WAIT_PAY.getCode())
                .paymentType(paymentServiceContext.getPaymentService(orderReq.getPaymentVendor()).venderName())
                .build();

        // 若订单无需支付，直接完成订单,VIP购买
        if (BigDecimal.ZERO.compareTo(orderReq.getPaymentCashAmount()) == 0) {
            executePaymentSuccess(orderReq, null);
            build.setStatus(PAID.getCode());
        }
        return build;
    }

    private void checkDiscountCard(UserPaymentOrderWrapper.UserPaymentOrder orderReq) {

        // 检查畅学卡
        if (orderReq.getPaymentClient() == ClientEnum.STUDENT) {

            Student student = studentService.getById(orderReq.getUserId());
            if (student == null) {
                throw new BizException("用户不存在");
            }
            boolean discountFlag = false;
            if (student.getDiscountEndTime()!=null && student.getDiscountEndTime().after(new Date())) {
                discountFlag = true;
            }
            // 没有畅学卡 ，循环商品检查是否有畅学卡
            if (!discountFlag) {
                for (UserPaymentOrderWrapper.OrderGoodsInfo item : orderReq.getGoodsInfos()) {
                    if (item.getGoodType() == GoodTypeEnum.DISCOUNT && Boolean.FALSE.equals(item.getGiftFlag())) {
                        discountFlag = true;
                        break;
                    }
                }
            }
            MemberPriceSettings one = null;
            if (discountFlag) {
                one = memberPriceSettingsService.lambdaQuery()
                        .eq(MemberPriceSettings::getVipType, EVipType.DISCOUNT)
                        .eq(MemberPriceSettings::getStatus, true)
                        .last("limit 1")
                        .one();
                if (one == null) {
                    discountFlag  =false;
                }

            }

            // 设置商品上的畅学卡标识
            for (UserPaymentOrderWrapper.OrderGoodsInfo item : orderReq.getGoodsInfos()) {
                item.setDiscountFlag(discountFlag);
                item.setDiscountInfo(one);
            }
        }

    }

    private CouponOrderWrapper.CouponInfo checkCoupon(UserPaymentOrderWrapper.UserPaymentOrder orderReq) {
        // 根据优惠券支持的商品类型，按比例分配优惠金额到各商品
        // 查询用户订单优惠券信息
        List<CouponOrderWrapper.CouponInfo> couponInfos = couponInfoMapper.selectUserOrderCouponInfo(orderReq.getUserId(),
                CouponInfoQuery.CouponOrderQuery.builder()
                    .clientType(orderReq.getPaymentClient())
                    .useState(CouponUseStateEnum.USABLE)
                    .timestamp(DateTime.now().getMillis())
                    .build()
                    .issueIds(orderReq.getCouponIds()));
        if (CollectionUtils.isEmpty(couponInfos)) {
            throw new BizException("优惠券不可用");
        }


        // 优惠券只支持使用一张
        CouponOrderWrapper.CouponInfo couponInfo = couponInfos.get(0);
        BigDecimal amount = BigDecimal.ZERO;
        List<UserPaymentOrderWrapper.OrderGoodsInfo> goodsInfos = orderReq.getGoodsInfos();
        Map<Integer,BigDecimal> couponAmountMap = new HashMap<>();
        for (int i = 0; i < goodsInfos.size(); i++) {
            UserPaymentOrderWrapper.OrderGoodsInfo goodsInfo = goodsInfos.get(i);

            goodsInfo.setActivityId(orderReq.getActivityId());
            /*

UNIVERSAL("全场通用", "UNIVERSAL"),
VIP("小酷Ai", "VIP"),
SVIP("小酷Ai SVIP ", "SVIP"),
PIANO("云酷琴房", "PIANO_ROOM"),
MALL("商场购物券", "MALL"),
MUSIC("单曲点播券", "MUSIC"),
ALBUM("专辑优惠券", "ALBUM"),
SPARRING("趣纠课购买券", "PRACTICE"),
LIVE("直播课购买券", "LIVE"),
VIDEO("视频课购买券", "VIDEO"),
VIP_COURSE("VIP定制课购买券", "VIP_COURSE"),
DISCOUNT("畅学卡","DISCOUNT"),

    VIP("开通会员"),
SVIP("开通会员 SVIP"),
PRACTICE("趣纠课购买"),
LIVE("直播课购买"),
VIDEO("视频课购买"),
MUSIC("单曲点播"),
ALBUM("专辑购买"),
TENANT_ALBUM("机构专辑"),
PIANO_ROOM("琴房时长"),
ACTI_REGIST("活动报名"),
DISCOUNT("畅学卡")
             */
            BigDecimal actualPrice = BigDecimal.ZERO;
            switch (couponInfo.getCategory()) {
                case UNIVERSAL:
                    actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    break;
                case VIP:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.VIP)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case SVIP:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.SVIP)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case PIANO:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.PIANO_ROOM)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case MUSIC:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.MUSIC)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case ALBUM:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.ALBUM)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case SPARRING:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.PRACTICE)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case LIVE:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.LIVE)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case VIDEO:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.VIDEO)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case VIP_COURSE:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.VIP_COURSE)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                case DISCOUNT:
                    if (goodsInfo.getGoodType().equals(GoodTypeEnum.DISCOUNT)) {
                        actualPrice = goodsInfo.getUserOrderDetail().getActualPrice();
                    }
                    break;
                default:
                    break;
            }
            if (actualPrice.compareTo(BigDecimal.ZERO)>0) {
                amount = amount.add(actualPrice);
                couponAmountMap.put(i,actualPrice);
            }

        }
        // 判断满减
        if (couponInfo.getUseLimit() != null && amount.compareTo(BigDecimal
                .valueOf(couponInfo.getUseLimit()).setScale(2, BigDecimal.ROUND_HALF_UP)) < 0) {
            throw new BizException("优惠券不可用");
        }

        // 总金额扣除优惠金额
        BigDecimal actual = amount.subtract(BigDecimal.valueOf(couponInfo.getDiscountPrice()));

        // 根据商品金额比例分摊优惠金额
        // 剩余金额
        BigDecimal remainAmount = BigDecimal.valueOf(couponInfo.getDiscountPrice());
        for (Map.Entry<Integer, BigDecimal> entry : couponAmountMap.entrySet()) {
            UserPaymentOrderWrapper.OrderGoodsInfo goodsInfo = goodsInfos.get(entry.getKey());
            UserOrderDetail userOrderDetail = goodsInfo.getUserOrderDetail();
            BigDecimal actualPrice = entry.getValue();
            BigDecimal couponAmount;

            if (actual.compareTo(BigDecimal.ZERO) >0) {
                couponAmount = BigDecimal.valueOf(couponInfo.getDiscountPrice())
                        .multiply(userOrderDetail.getActualPrice()).divide(amount, 2, RoundingMode.HALF_DOWN);
            } else {
                couponAmount = userOrderDetail.getActualPrice();
            }
            remainAmount = remainAmount.subtract(couponAmount);
            userOrderDetail.setCouponAmount(couponAmount.add(userOrderDetail.getCouponAmount()));

            userOrderDetail.setDiscountJson(userOrderService.discountJson(EDiscountType.COUPON,
                    couponAmount,userOrderDetail.getDiscountJson()));
            userOrderDetail.setActualPrice(actualPrice.subtract(couponAmount));
        }
        if (remainAmount.compareTo(BigDecimal.ZERO) > 0 && actual.compareTo(BigDecimal.ZERO) >0) {
            UserOrderDetail userOrderDetail = goodsInfos.get(couponAmountMap.keySet().stream().findFirst().get()).getUserOrderDetail();
            userOrderDetail.setActualPrice(userOrderDetail.getActualPrice().subtract(remainAmount));

            userOrderDetail.setDiscountJson(userOrderService.discountJson(EDiscountType.COUPON,
                    remainAmount,userOrderDetail.getDiscountJson()));
        }
        return couponInfo;

    }

    private void checkActivity(UserPaymentOrderWrapper.UserPaymentOrder orderReq) {
        ActivityPlanVo activityPlan = activityPlanService.detail(orderReq.getActivityId());
        Date now = new Date();
        if (activityPlan != null && activityPlan.getActivityState() == 1) {
            if (activityPlan.getActivityStart().after(now)) {
                throw new BizException("活动未开始");
            } else if (activityPlan.getActivityEnd().before(now)) {
                throw new BizException("活动已结束");
            }
            if (ActivityTypeEnum.MEMBER == activityPlan.getActivityType()) {

                List<UserPaymentOrderWrapper.OrderGoodsInfo> collect = orderReq.getGoodsInfos().stream().filter(o -> !o.getGiftFlag()).collect(Collectors.toList());
                if (collect.size() != 1) {
                    throw new BizException("活动商品不符合要求");
                }

                checkActivityTimes(orderReq.getUserId(),orderReq.getPaymentClient(), activityPlan.getId(),collect.get(0).getGoodNum());

                // 会员买赠活动 判断购买商品是否符合活动要求
                Map<String, List<Long>> map = orderReq.getGoodsInfos().stream()
                        .filter(o -> o.getGiftFlag() != null && o.getGiftFlag())
                        .collect(Collectors.groupingBy(o -> o.getGoodType().getCode(),
                                Collectors.mapping(o->Long.valueOf(o.getBizContent().toString()), Collectors.toList())));
                for (ActivityPlanRewardDto activityPlanRewardDto : activityPlan.getActivityRewardList()) {
                    RewardTypeEnum rewardType = activityPlanRewardDto.getActivityReward().getRewardType();
                    if (map.containsKey(rewardType.toString())) {
                        List<Long> bizIds = map.get(rewardType.toString());
                        if (!bizIds.contains(activityPlanRewardDto.getActivityReward().getVipCardId())) {
                            throw new BizException("活动商品不符合要求");
                        } else {
                            bizIds.remove(activityPlanRewardDto.getActivityReward().getVipCardId());
                        }
                    }
                }
                // 购买的商品判断
                map = orderReq.getGoodsInfos().stream()
                        .filter(o -> o.getGiftFlag() == null || !o.getGiftFlag())
                        .collect(Collectors.groupingBy(o -> o.getGoodType().getCode(),
                                Collectors.mapping(o->Long.valueOf(o.getBizContent().toString()), Collectors.toList())));
                if (map.containsKey(GoodTypeEnum.VIP.name()) || map.containsKey(GoodTypeEnum.SVIP.name())) {
                    MemberPriceSettings settings = memberPriceSettingsService.getById(activityPlan.getVipCardId());
                    if (settings == null) {
                        throw new BizException("活动商品不符合要求");
                    }
                    List<Long> list = map.get(settings.getVipType().name());
                    if (list == null || !list.contains(settings.getId())) {
                        throw new BizException("活动商品不符合要求");
                    }
                } else {
                    throw new BizException("活动商品不符合要求");
                }
            }
        } else {
            throw new BizException("活动已结束");
        }
    }


    /**
     * 检查活动购买次数
     *
     * @param userId     用户ID
     * @param client     客户端
     * @param activityId 活动ID
     * @param goodNum
     */
    private void checkActivityTimes(Long userId, ClientEnum client, Long activityId, Integer goodNum) {
        ActivityPlan activityPlan = activityPlanService.getById(activityId);
        if (activityPlan == null) {
            throw new BizException("活动不存在");
        }

        //  检查购买次数是否符合要求 待支付，支付中，支付完成的订单小于次数才可以继续购买
        if (activityPlan.getBuyCount() !=null && activityPlan.getBuyCount() >0) {
            int count = getActivityCount(userId, client, activityId);
            if (count + goodNum > activityPlan.getBuyCount()) {
                throw new BizException("超出活动最大参与次数");
            }
        }

    }

    /**
     * 查询活动参与次数
     *
     * @param userId 用户ID
     * @param client 客户端
     * @param activityId 活动ID
     * @return int 活动参与次数
     */
    @Override
    public int getActivityCount(Long userId, ClientEnum client, Long activityId) {
        return userOrderDetailDao.getActivityGoodsCount(userId, client.getCode(), activityId);
    }

    /**
     * 用户支付请求
     *
     * @param reqConfig UserPaymentOrderWrapper.PaymentOrderReqConfig
     * @return UserPaymentOrderWrapper.PaymentReq
     */
    @Transactional
    @Override
    public UserPaymentOrderWrapper.PaymentReq executePayment(JwtUserInfo<?> userInfo,
                                                             UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig) {

        // 设置支付用户
        reqConfig.setUserId(userInfo.getUserId());

        // 用户下单请求锁
        String lockName = redisCacheService.getExecuteOrderCacheKey(userInfo.getUserId());

        // 分布式锁，用户支付请求
        return DistributedLock.of(redissonClient).runIfLockToFunction(lockName, this::executePayment, reqConfig, 10L);
    }

    /**
     * 更新用户支付订单状态
     * @param userId 支付用户Id
     * @param userPaymentOrder UserPaymentOrder
     * @param paymentResp PaymentResp
     */
    public void updateUserPaymentOrderStatus(String userId, UserPaymentOrderWrapper.UserPaymentOrder userPaymentOrder, PaymentResp paymentResp) {

        // 若三方支付已完，本地订单状态未同步
        if (PaymentStatus.SUCCESSED == paymentResp.getPaymentStatus() && PAID != userPaymentOrder.getStatus()) {

            if (EPaymentStatus.WAIT_PAY == userPaymentOrder.getStatus() || EPaymentStatus.PAYING == userPaymentOrder.getStatus()) {

                // 订单完成后续流程
                applicationContext.getBean(UserPaymentCoreService.class)
                    .executePaymentSuccess(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(userPaymentOrder)), paymentResp);
            }

            // 删除支付配置
            redisCacheService.deleteUserPaymentConfig(userId, userPaymentOrder.getOrderNo());

            // 删除下单配置
            redisCacheService.deleteUserOrderConfig(userId, userPaymentOrder.getOrderNo());
        }

        // 三方支付失败
        if (PaymentStatus.FAILED == paymentResp.getPaymentStatus() && EPaymentStatus.FAIL != userPaymentOrder.getStatus()) {

            // 更新订单状态
            UserPaymentOrderWrapper.UserPaymentOrder update = UserPaymentOrderWrapper.UserPaymentOrder
                .builder()
                .id(userPaymentOrder.getId())
                .status(EPaymentStatus.FAIL)
                .build();
            userPaymentOrderService.updateById(update);

            // 订单关闭流程
            applicationContext.getBean(UserPaymentCoreService.class)
                .cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(userPaymentOrder)), paymentResp);

            // 删除本地缓存
            redisCacheService.deleteUserPaymentConfig(userId, userPaymentOrder.getOrderNo());
        }

        // 三方订单关闭状态
        if (PaymentStatus.CLOSED == paymentResp.getPaymentStatus() && EPaymentStatus.CLOSED != userPaymentOrder.getStatus()) {

            // 订单关闭流程
            applicationContext.getBean(UserPaymentCoreService.class)
                .cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(userPaymentOrder)), paymentResp);

            // 删除本地缓存
            redisCacheService.deleteUserPaymentConfig(userId, userPaymentOrder.getOrderNo());

            // 删除下单配置
            redisCacheService.deleteUserOrderConfig(userId, userPaymentOrder.getOrderNo());

        }
    }

    /**
     * 用户支付请求
     *
     * @param reqConfig UserPaymentOrderWrapper.PaymentOrderReqConfig
     * @return UserPaymentOrderWrapper.PaymentReq
     */
    @Transactional
    @Override
    public UserPaymentOrderWrapper.PaymentReq executePayment(UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig) {

        // 查询订单状态
        UserPaymentOrderWrapper.UserPaymentOrder userPaymentOrder = userPaymentOrderService.getUserPaymentOrderByUserId(Long.parseLong(reqConfig.getUserId()),
            reqConfig.getMerOrderNo());

        // 默认支付三方
        if (StringUtils.isNotEmpty(reqConfig.getPaymentVendor())
                && !reqConfig.getPaymentVendor().equals(userPaymentOrder.getPaymentVendor())) {
            // 原生支付拉起支付时，可以切换支付渠道
            UserPaymentOrderWrapper.UserPaymentOrder update = UserPaymentOrderWrapper.UserPaymentOrder
                .builder()
                .id(userPaymentOrder.getId())
                .paymentVendor(reqConfig.getPaymentVendor())
                .build();
            userPaymentOrderService.updatePaymentVendorById(update);

            // 重置支付三方渠道
            userPaymentOrder.setPaymentVendor(reqConfig.getPaymentVendor());
        }

        if (Objects.isNull(userPaymentOrder)) {
            throw new BizException("订单不存在");
        }

//         订单支付已完成
        switch (userPaymentOrder.getStatus()) {
            case PAID:
                throw new BizException("订单已支付");
            case CLOSED:
                throw new BizException("订单已关闭");
            case TIMEOUT:
                throw new BizException("订单已超时");
            case FAIL:
                throw new BizException("订单支付失败");
            default:
                break;
        }

//         订单支付状态异常
        if (EPaymentStatus.WAIT_PAY != userPaymentOrder.getStatus() && EPaymentStatus.PAYING != userPaymentOrder.getStatus()) {
            throw new BizException("订单支付状态异常");
        }

        // 微信支付，需要校验code值是否为空
        if ((EPaymentChannel.WX_PUB.getCode().equals(reqConfig.getPaymentChannel())
                ||EPaymentChannel.WX_LITE.getCode().equals(reqConfig.getPaymentChannel()))
            && StringUtils.isBlank(reqConfig.getCode())) {
            throw new BizException("微信支付code值为空");
        }

        // 生成订单支付参数,三方返返回异常，直接关闭订单
        try {

            // 已产生三方交易流水号，先判断三方订单支付状态若在支付中，则重复返回相同支付配置参数;避免用户重复支付
            if (StringUtils.isNotBlank(userPaymentOrder.getTransNo())) {

                // 获取缓存配置信息
                String paymentConfig = redisCacheService.getUserPaymentConfig(reqConfig.getUserId(), userPaymentOrder.getOrderNo());
                if (StringUtils.isBlank(paymentConfig)) {

                    // 支付配置已失效，待支付订单状态调整为已关闭，提醒用户重新购买
                    PaymentClose paymentClose = paymentServiceContext.getPaymentService(userPaymentOrder.getPaymentVendor())
                        .close(userPaymentOrder.getTransNo(), "订单支付已超时", userPaymentOrder.getOrderNo());

                    // 更新订单状态为已超时
                    UserPaymentOrderWrapper.UserPaymentOrder update = UserPaymentOrderWrapper.UserPaymentOrder
                        .builder()
                        .id(userPaymentOrder.getId())
                        .status(EPaymentStatus.CLOSED)
                        .errorMsg(paymentClose.getMsg())
                        .build();
                    userPaymentOrderService.updateById(update);

                    // 订单关闭后的数据处理流程
                    userOrderService.payCancel(userOrderService.detail(reqConfig.getMerOrderNo(),null));
                    throw  new BizException("支付超时");
                }

                // 返回支付配置信息
                return UserPaymentOrderWrapper.PaymentReq.from(paymentConfig);
            }

            // 查询用户下单配置
            String ret = redisCacheService.getUserOrderConfig(reqConfig.getUserId(), userPaymentOrder.getOrderNo());
            if (StringUtils.isEmpty(ret)) {
                throw new BizException("支付超时");
            }
            UserPaymentOrderWrapper.PaymentOrderReqConfig config = UserPaymentOrderWrapper.PaymentOrderReqConfig
                .from(ret)
                .paymentChannel(reqConfig.getPaymentChannel())
                .merOrderNo(reqConfig.getMerOrderNo())
                .code(reqConfig.getCode());

            config.setIp(reqConfig.getIp());
            // 重新格式化设置价格
            config.setPrice(config.getPrice().setScale(2, RoundingMode.HALF_UP));
            log.info("executePayment reqConfig={}", config.jsonString());

            PaymentOrder paymentOrder = JSON.parseObject(config.jsonString(), PaymentOrder.class);
            PaymentReq paymentReq = paymentServiceContext.getPaymentService(userPaymentOrder.getPaymentVendor()).pay(paymentOrder);
            if (Objects.isNull(paymentReq)) {
                throw new BizException("生成支付参数异常");
            }

            // 更新订单流水号
            UserPaymentOrderWrapper.UserPaymentOrder update = UserPaymentOrderWrapper.UserPaymentOrder
                .builder()
                .id(userPaymentOrder.getId())
                .transNo(paymentReq.getTransNo())
                .paymentChannel(reqConfig.getPaymentChannel())
                .transPayTime(DateTime.now().toDate())
                .status(EPaymentStatus.PAYING)
                .build();
            userPaymentOrderService.updateById(update);

            // 缓存用户下单配置
            redisCacheService.saveUserOrderConfig(String.valueOf(reqConfig.getUserId()), reqConfig.getMerOrderNo(), config.jsonString());
            // 缓存用户支付配置信息
            redisCacheService.saveUserPaymentConfig(reqConfig.getUserId(), userPaymentOrder.getOrderNo(),
                JSON.toJSONString(paymentReq));

            return UserPaymentOrderWrapper.PaymentReq.from(JSON.toJSONString(paymentReq));

        } catch (Exception e) {
            log.error("executePayment reqConfig={}", reqConfig.jsonString(), e);

            // 拉起三方支付失败，主动调整订单状态为已关闭
            userPaymentOrderService.closeUserPaymentOrder(userPaymentOrder.getId());

            throw e;
        }

    }

    /**
     * 用户取消支付
     *
     * @param userInfo JwtUserInfo
     * @param orderNo  订单编号
     */
    @Transactional
    @Override
    public void cancelPayment(JwtUserInfo<?> userInfo, String orderNo) {

        // 查询订单信息，支付状态
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByUserId(Long.parseLong(userInfo.getUserId()), orderNo);
        if (Objects.isNull(paymentOrder)) {
            throw new BizException("订单不存在");
        }

        // 订单状态处理
        switch (paymentOrder.getStatus()) {
            case PAID:
                // 订单支付已完成不可取消，走申请退款流程
                throw new BizException("订单已支付");
            case REFUNDED:
                // 订单已取消
                throw new BizException("订单已取消");
            case CLOSED:
                throw new BizException("订单已关闭");
            default:
                break;
        }

        // 任务执行锁
        String lockName = redisCacheService.getPaymentCacheKey(orderNo);
        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

            // 下单未拉起三方支付，直接关闭
            if (StringUtils.isEmpty(paymentOrder.getTransNo())
                    && (EPaymentStatus.WAIT_PAY == paymentOrder.getStatus()||EPaymentStatus.PAYING == paymentOrder.getStatus())) {

                closeWaitOrder(paymentOrder);

            } else {
                // 获取三方支付订单信息，根据订单状处理
                PaymentResp paymentResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
                    .query(paymentOrder.getTransNo(), paymentOrder.getOrderNo());
                if (Objects.isNull(paymentResp)) {
                    throw new BizException("订单支付状态获取异常，稍后请重试");
                }
                // 支付订单信息
                UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(paymentOrder));

                // 订单取消执行流程
                cancelPayment(order, paymentResp);
            }

        }, 10L, TimeUnit.SECONDS);

    }

    private void closeWaitOrder(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder) {
        // 直接关闭订单
        UserPaymentOrderWrapper.UserPaymentOrder order = UserPaymentOrderWrapper.UserPaymentOrder
            .builder()
            .id(paymentOrder.getId())
            .status(EPaymentStatus.CLOSED)
            .updateTime(DateTime.now().toDate())
            .errorMsg(paymentOrder.getErrorMsg())
            .build();
        userPaymentOrderService.updateById(order);

        // 订单关闭后的数据处理流程
        userOrderService.payCancel(userOrderService.detail(order.getId()));

    }


    /**
     * 扫描支付超时定时
     */
    @Override
    public void scanPaymentTimeoutOrderRecord() {

        // 查询半小时前创建的并且还未完成的订单 WAIT_PAY 待支付订单 PAYING 支付中订单
        UserPaymentOrderWrapper.UserPaymentOrderQuery waitPayQuery = UserPaymentOrderWrapper.UserPaymentOrderQuery
            .builder()
            .paymentStatus(Lists.newArrayList(OrderStatusEnum.parse(EPaymentStatus.WAIT_PAY)))
//            .endTime(DateTime.now().minusMinutes(30).toDate())
            .build();

        IPage<UserPaymentOrderWrapper.UserPaymentOrder> page = QueryInfo.getPage(1, 10);
        // 查询待支付订单数
        userPaymentOrderService.selectPage(page, waitPayQuery);

        // 更新订单状态
        scheduleUpdatePaymentOrderStatus(page, waitPayQuery, EPaymentStatus.WAIT_PAY);

        // 查询支付中订单，超过2个小时且还未完成自动关闭
        UserPaymentOrderWrapper.UserPaymentOrderQuery payingQuery = UserPaymentOrderWrapper.UserPaymentOrderQuery
            .builder()
            .paymentStatus(Lists.newArrayList(OrderStatusEnum.parse(EPaymentStatus.PAYING)))
//            .endTime(DateTime.now().plusMinutes(120).toDate())
            .build();
        // 查询支付中订单数
        userPaymentOrderService.selectPage(page, payingQuery);

        // 更新订单状态
        scheduleUpdatePaymentOrderStatus(page, payingQuery, EPaymentStatus.PAYING);

    }


    /**
     * 检测订单支付方式
     *
     * @param payTypeReq UserPaymentOrderWrapper.OrderPayTypeReq
     */
    @Override
    public UserPaymentOrderWrapper.OrderPayTypeResp orderPayType(UserPaymentOrderWrapper.OrderPayTypeReq payTypeReq) {

        UserPaymentOrderWrapper.OrderPayTypeResp resp = new UserPaymentOrderWrapper.OrderPayTypeResp();
        resp.setPaymentVersion(EPaymentVersion.V1);
        // 检测用户 是否为机构 或者机构的学生
        if (payTypeReq.getClientType().equals(ClientEnum.TENANT)) {
            resp.setPaymentVersion(EPaymentVersion.V2);
        }
        // 检测商品是属于老师，老师是否设置的结算给机构

        switch (payTypeReq.getGoodType()) {
            case VIDEO: {
                VideoLessonGroup lessonGroup = videoLessonGroupService.getById(payTypeReq.getBizId());
                if (Objects.isNull(lessonGroup)) {
                    throw new BizException("课程信息不存在");
                }
                Teacher teacher = teacherService.getById(lessonGroup.getTeacherId());
                if (Objects.isNull(teacher)) {
                    throw new BizException("老师信息不存在");
                }
                if (teacher.getTenantId() != null && teacher.getTenantId() > 0) {
                    resp.setPaymentVersion(EPaymentVersion.V2);
                }
                break;
            }
            case LIVE: {
                CourseGroup courseGroup = courseGroupService.getById(payTypeReq.getBizId());
                if (Objects.isNull(courseGroup)) {
                    throw new BizException("课程信息不存在");
                }
                Teacher teacher = teacherService.getById(courseGroup.getTeacherId());
                if (Objects.isNull(teacher)) {
                    throw new BizException("老师信息不存在");
                }
                if (teacher.getTenantId() != null && teacher.getTenantId() > 0) {
                    resp.setPaymentVersion(EPaymentVersion.V2);
                }
                break;
            }
            case PRACTICE: {
                Teacher teacher = teacherService.getById(payTypeReq.getBizId());
                if (Objects.isNull(teacher)) {
                    throw new BizException("老师信息不存在");
                }
                if (teacher.getTenantId() != null && teacher.getTenantId() > 0) {
                    resp.setPaymentVersion(EPaymentVersion.V2);
                }
                break;
            }
            case MUSIC: {
                MusicSheet musicSheet = musicSheetService.getById(payTypeReq.getBizId());
                if (Objects.isNull(musicSheet)) {
                    throw new BizException("曲目信息不存在");
                }
                if (musicSheet.getSourceType().equals(SourceTypeEnum.PLATFORM)) {
                    break;
                }
                Teacher teacher = teacherService.getById(musicSheet.getUserId());
                if (Objects.isNull(teacher)) {
                    throw new BizException("老师信息不存在");
                }
                if (teacher.getTenantId() != null && teacher.getTenantId() > 0 ) {
                    resp.setPaymentVersion(EPaymentVersion.V2);
                }
                break;
            }
            case TENANT_ALBUM:
                resp.setPaymentVersion(EPaymentVersion.V2);
        }

        // 设置推荐人
        if(payTypeReq.getRecomUserId() != null ) {
            Teacher teacher = teacherService.getById(payTypeReq.getRecomUserId());
            if (Objects.isNull(teacher)) {
                throw new BizException("推荐人信息不存在");
            }
            if (!payTypeReq.getClientType().equals(ClientEnum.TEACHER)) {
                if (teacher.getTenantId() != null && teacher.getTenantId() > 0) {
                    resp.setPaymentVersion(EPaymentVersion.V2);
                }
            }
        }
        
        // 结算给机构的，检测机构的主账户，没有主账户的，查询-1的主账户
        String defaultService = paymentServiceContext.getProperties().getDefaultService();
        if (EPayerType.ORIGINAL.getCode().toLowerCase().equals(defaultService) || resp.getPaymentVersion() == EPaymentVersion.V1) {
            // 微信、支付宝原生支付
            if (Objects.isNull(payTypeReq.getClientType())) {
                throw new BizException("支付客户端类型不能为空");
            }
            List<PaymentMerchantConfig> configs = paymentMerchantConfigService.lambdaQuery()
                    .eq(PaymentMerchantConfig::getPayerType, EPayerType.ORIGINAL.getCode())
                    .eq(PaymentMerchantConfig::getPaymentClient, payTypeReq.getClientType().getCode())
                    .eq(PaymentMerchantConfig::getStatus, true)
                    .list();
            if (CollectionUtils.isEmpty(configs)) {
                throw new BizException("平台主账户信息不存在");
            }
            // 默认支付服务
            resp.setPaymentVendor(configs.get(0).getPaymentVendor());

            // 设置支付服务渠道
            resp.setPaymentChannels(configs.stream().map(PaymentMerchantConfig::getPaymentVendor).distinct().collect(Collectors.toList()));
        } else {
            // 易宝，汇付三方支付
            PaymentMerchantConfig merchantConfig = paymentMerchantConfigService.getByPaymentVendor(defaultService);
            if (Objects.isNull(merchantConfig)) {
                throw new BizException("平台主账户信息不存在");
            }
            resp.setPaymentVendor(merchantConfig.getPaymentVendor());
            if (StringUtils.isNotEmpty(merchantConfig.getPayChannel())) {
                resp.setPaymentChannels(Arrays.asList(merchantConfig.getPayChannel().split(",")));
            }
        }

        resp.setPaymentVersion(EPaymentVersion.V2);
        return resp;
    }

    /**
     * 退款回调
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundPaymentCallback(RefundResp refundResp) {

        String lockName = redisCacheService.getPaymentCacheKey(refundResp.getMerOrderNo());
        // 并发执行锁
        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
            // 退款订单确认
            UserOrderRefundBill refundOrder = userOrderRefundBillService.getByTransNoOrOrderNo(null, refundResp.getMerOrderNo());
            if (Objects.isNull(refundOrder)) {
                throw new com.yonge.toolset.base.exception.BizException("退款订单不存在");
            }

            refundOrder.setUpdateTime(new Date());
            refundOrder.setTransNo(refundResp.getTransNo());
            // 退款申请失败
            if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {

                // 更新用户退款订单状态
                refundOrder.setStatus(TradeStatusEnum.failed);
                refundOrder.setPayFailMsg(refundResp.getMsg());
            }

            // 退款处理已完成,本地订单状态未同步
            if (PaymentStatus.SUCCESSED == refundResp.getPaymentStatus()) {

                refundOrder.setBackRefundAmt(refundResp.getRefundAmount());
                refundOrder.setStatus(TradeStatusEnum.succeeded);
            }
            userOrderRefundBillService.updateById(refundOrder);


        }, 60L, TimeUnit.SECONDS);


        log.info("refundPaymentCallback refundResp={}", JSON.toJSONString(refundResp));
    }

    /**
     * 定时更新订单状态
     * @param page IPage<UserPaymentOrderWrapper.UserPaymentOrder>
     * @param orderQuery UserPaymentOrderWrapper.UserPaymentOrderQuery
     * @param paymentStatus 订单状态
     */
    public void scheduleUpdatePaymentOrderStatus(IPage<UserPaymentOrderWrapper.UserPaymentOrder> page,
                                                  UserPaymentOrderWrapper.UserPaymentOrderQuery orderQuery,
                                                  EPaymentStatus paymentStatus) {

        // 分页数限制
        int limit = 500;
        // 计算总页数
        int totalPages = (int) (page.getTotal() - 1) / limit + 1;

        List<Integer> pageNums = IntStream.iterate(1, i -> i + 1).limit(totalPages).boxed().collect(Collectors.toList());

        IPage<UserPaymentOrderWrapper.UserPaymentOrder> pages;
        String lockName;
        for (Integer pageNum : pageNums) {

            pages = userPaymentOrderService.selectPage(QueryInfo.getPage(pageNum, limit), orderQuery);
            if (CollectionUtils.isNotEmpty(pages.getRecords())) {

                for (UserPaymentOrderWrapper.UserPaymentOrder item : pages.getRecords()) {

                    lockName = redisCacheService.getPaymentCacheKey(item.getOrderNo());
                    // 并发执行锁
                    DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

                        // 订单用户信息
                        JwtUserInfo<Object> userInfo = JwtUserInfo.builder()
                            .userId(String.valueOf(item.getUserId()))
                            .clientType(item.getPaymentClient().getCode())
                            .build();

                        // 用户下单超进关闭
                        if (EPaymentStatus.WAIT_PAY == paymentStatus
                            && new DateTime(item.getCreateTime()).plusMinutes(30).isBeforeNow()) {

                            try {
                                log.info("scanPaymentTimeoutOrderRecord WAIT_PAY, userId={}, orderNo={}", item.getUserId(), item.getOrderNo());
                                // 关闭待支付、超时订单
                                applicationContext.getBean(UserPaymentCoreService.class).cancelPayment(userInfo, item.getOrderNo());
                            } catch (Exception e) {
                                log.error("scanPaymentTimeoutOrderRecord WAIT_PAY, userId={}, orderNo={}", item.getUserId(), item.getOrderNo(), e);
                            }

                        }
                        if (EPaymentStatus.WAIT_PAY == paymentStatus) {
                            return;
                        }

                        // 支付时间未超时，同步订单状态
                        if (EPaymentStatus.PAYING == paymentStatus
                            && new DateTime(item.getCreateTime()).plusMinutes(120).isAfterNow()) {

                            // 支付同小消息
                            PaymentResp paymentResp = paymentServiceContext.getPaymentService(item.getPaymentVendor()).query(item.getTransNo(), item.getOrderNo());
                            if (Objects.nonNull(paymentResp)) {

                                try {

                                    log.info("scanPaymentTimeoutOrderRecord PAYMENT_SYNC, vendor={}, paymentResp={}", item.getPaymentVendor(),
                                        JSON.toJSONString(paymentResp));
                                    // 支付成功
                                    if (PaymentStatus.SUCCESSED == paymentResp.getPaymentStatus()) {
                                        // 根据支付回调消息，更新订单状态
                                        applicationContext.getBean(UserPaymentCoreService.class)
                                            .executePaymentSuccess(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(item)), paymentResp);
                                    }

                                } catch (Exception e) {
                                    log.error("scanPaymentTimeoutOrderRecord PAYMENT_SYNC, userId={}, orderNo={}", item.getUserId(), item.getOrderNo(), e);
                                }

                            }

                        } else {

                            try {
                                log.info("scanPaymentTimeoutOrderRecord WAIT_PAY, userId={}, orderNo={}", item.getUserId(), item.getOrderNo());
                                // 关闭待支付、超时订单
                                applicationContext.getBean(UserPaymentCoreService.class).cancelPayment(userInfo, item.getOrderNo());
                            } catch (Exception e) {
                                log.error("scanPaymentTimeoutOrderRecord WAIT_PAY, userId={}, orderNo={}", item.getUserId(), item.getOrderNo(), e);
                            }
                        }

                    }, 60L, TimeUnit.SECONDS);

                }
            }
        }
        //log.info("scheduleUpdatePaymentOrderStatus PAYMENT_FINISH ------> ");
    }


    /**
     * 用户申请退款
     *
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refundPayment(String orderNo, String reason, List<Long> orderDetailIds) {
        if (CollectionUtils.isEmpty(orderDetailIds)) {
            throw new BizException("退款订单明细不能为空");
        }

        // 查询订单信息，支付状态
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo(orderNo);
        if (Objects.isNull(paymentOrder)) {
            throw new BizException("订单信息不存在");
        }
        if (!OrderStatusEnum.PAID.getCode().equals(paymentOrder.getStatus().getCode())) {
            throw  new BizException("订单状态异常");
        }
        UserOrderVo detail = userOrderService.detail(paymentOrder.getId());
        if (Objects.isNull(detail)) {
            throw new BizException("订单信息不存在");
        }

        // 执行状态锁定
        String lockName = redisCacheService.getPaymentCacheKey(paymentOrder.getOrderNo());
        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

            // 如果是易宝的订单，查询分账是否给到子账户，没有给子账户的直接退款

            // 分账给子账户的 先 分账归还，如果归还成功，再退款，归还失败，不退款，退款后的逻辑还是继续走

            boolean refundFlag = true;
            if (paymentOrder.getPaymentVendor().equals(EPayerType.YEEPAY.getDesc())) {
                List<PaymentDivMemberRecord> records = paymentDivMemberRecordService.getByOrderNo(paymentOrder.getOrderNo());

                for (PaymentDivMemberRecord record : records) {
                    if (Boolean.TRUE.equals(record.getTenantEnterFlag())) {

                        refundFlag = saveDivBackRecord(paymentOrder, record);

                    }
                }
            }

            if (refundFlag) {
                refundOnly(reason, paymentOrder.getOrderNo(),orderDetailIds);
            }

            //处理退款业务
            userOrderRefundService.orderRefundSuccessBizHandleByOrderNo(paymentOrder.getOrderNo(),orderDetailIds);
        }, 10L, TimeUnit.SECONDS);

    }

    /**
     * 退款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundOnly(String reason, String orderNo) {
        refundOnly(reason, orderNo,null);

    }

    /**
     * 退款
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refundOnly(String reason, String orderNo, List<Long> orderDetailIds) {

        // 查询订单信息，支付状态
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo(orderNo);
        if (Objects.isNull(paymentOrder)) {
            throw new BizException("订单信息不存在");
        }
        UserOrderVo detail = userOrderService.detail(paymentOrder.getId());
        if (Objects.isNull(detail)) {
            throw new BizException("订单信息不存在");
        }

        List<UserOrderDetailVo> collect = detail.getOrderDetailList().stream().filter(o -> orderDetailIds.contains(o.getId())).collect(Collectors.toList());
        BigDecimal reduce = collect.stream().map(o -> o.getActualPrice()).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 提交退款申请记录
        UserOrderRefund userRefundOrder = new UserOrderRefund();
        userRefundOrder.setUserId(paymentOrder.getId());
        userRefundOrder.setOrderId(paymentOrder.getId());
        userRefundOrder.setOrderNo(paymentOrder.getOrderNo());
        userRefundOrder.setOredrDetilIds(collect.stream().map(o -> o.getId().toString()).collect(Collectors.joining(",")));
        userRefundOrder.setStatus(AuthStatusEnum.PASS);
        userRefundOrder.setApplyAmount(reduce);
        userRefundOrder.setActualAmount(reduce);
        userRefundOrder.setReason(reason);
        userOrderRefundService.save(userRefundOrder);

        //入退款单表
        UserOrderRefundBill orderRefundBill = new UserOrderRefundBill();
        orderRefundBill.setRefundId(userRefundOrder.getId());
        orderRefundBill.setBillNo(IdWorker.getIdStr());
        orderRefundBill.setRefundAmt(userRefundOrder.getActualAmount());

        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setUserId(paymentOrder.getUserId().toString());
        refundOrder.setMerOrderNo(orderRefundBill.getBillNo());
        refundOrder.setRefundAmount(orderRefundBill.getRefundAmt());
        refundOrder.setOrderAmount(paymentOrder.getActualPrice());
        refundOrder.setReason(reason);
        refundOrder.setTransNo(paymentOrder.getTransNo());
        refundOrder.setPaymentOrderNo(paymentOrder.getOrderNo());

        // 执行状态锁定
        String lockNameInner = redisCacheService.getPaymentCacheKey(orderRefundBill.getBillNo());
        DistributedLock.of(redissonClient).runIfLockCanGet(lockNameInner, () -> {
            if (StringUtils.isEmpty(paymentOrder.getTransNo()) || reduce.compareTo(BigDecimal.ZERO) == 0) {
                orderRefundBill.setStatus(TradeStatusEnum.succeeded);
                userOrderRefundBillService.save(orderRefundBill);
            } else {
                try {
                    RefundResp refundResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor()).refund(refundOrder);
                    // 申请请求失败
                    if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {
                        orderRefundBill.setStatus(TradeStatusEnum.failed);
                        orderRefundBill.setPayFailMsg(refundResp.getMsg());
                    } else {
                        orderRefundBill.setTransNo(refundResp.getTransNo());
                        orderRefundBill.setStatus(TradeStatusEnum.pending);
                    }
                } catch (Exception e) {
                    orderRefundBill.setStatus(TradeStatusEnum.failed);
                    orderRefundBill.setPayFailMsg(e.getMessage());
                    log.error("refundOnly orderNo={}", orderRefundBill.getBillNo(), e);
                }
            }

            userOrderRefundBillService.save(orderRefundBill);

        }, 10L, TimeUnit.SECONDS);
    }

    private boolean saveDivBackRecord(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentDivMemberRecord record) {


        BasePaymentService paymentService = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor());

        boolean refundFlag = true;
        DivBackRecord divBackRecord = new DivBackRecord();
        divBackRecord.setPaymentDivMemberRecordId(record.getId());
        divBackRecord.setDivideBackOrderNo(IdWorker.getIdStr());
        divBackRecord.setTimes(1);
        divBackRecord.setPaymentVendor(paymentOrder.getPaymentVendor());

        // 分账数据
        DivideReq.DivideBackDetail divideBackDetail = DivideReq.DivideBackDetail.builder()
            .amount(record.getAmount())
            .divideDetailNo(record.getTransNo())
            .divideBackReason("订单退款")
            .build();

        List<DivideResp.DivMember> divMembers = JSON.parseArray(record.getDivMemberJson(), DivideResp.DivMember.class);
        if (CollectionUtils.isNotEmpty(divMembers)) {
            divideBackDetail.setDivideDetailNo(divMembers.get(0).getDetailNo());
        }

        DivideReq.MemberDivideBack memberDivideBack = DivideReq.MemberDivideBack.builder()
            .payerName(EPayerType.YEEPAY.getDesc())
            .memberId(record.getMemberId())
            .devOrderNo(record.getDivOrderNo())
            .platformPayeeMemberId(paymentService.getPaymentConfig().getMerchantId())
            .divideBackOrderNo(divBackRecord.getDivideBackOrderNo())
            .payOrderNo(paymentOrder.getOrderNo())
            .transNo(paymentOrder.getTransNo())
            .divideBackDetail(Lists.newArrayList(divideBackDetail))
            .build();


        try {

            DivideResp.DivideBack divideBack = paymentService.divideBack(tenantMemberService
                .getMerchantConfig(paymentOrder.getPaymentVendor()), memberDivideBack);
            if (divideBack.getStatus() != DivideBackStatus.SUCCESS) {
                refundFlag = false;
            }
            divBackRecord.setReason(divideBack.getReason());
            divBackRecord.setDivideBackTransNo(divideBack.getDivideBackTransNo());
            divBackRecord.setStatus(divideBack.getStatus().name());

        }catch (Exception e) {
            log.error("分账回归失败orderNo={}", memberDivideBack.getDivideBackOrderNo(), e);
            refundFlag = false;
            divBackRecord.setReason(e.getMessage());
        }
        divBackRecordService.save(divBackRecord);
        return refundFlag;
    }

    /**
     * 关闭订单
     *
     * @param paymentOrder UserPaymentOrder
     * @return PaymentResp
     */
    @Override
    public PaymentResp closedPayment( UserPaymentOrderWrapper.UserPaymentOrder paymentOrder) {

        // 开启调试模式允许关闭订单
        if (Optional.ofNullable(paymentServiceContext.getProperties().getDebug()).orElse(false)) {
            // 关闭支付订单
            PaymentClose paymentClose = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
                .close(paymentOrder.getTransNo(), "订单超时", paymentOrder.getOrderNo());
            log.info("closedPayment VENDOR: {}, CHANNEL: {} paymentClose={}", paymentOrder.getPaymentVendor(),
                paymentOrder.getPaymentChannel(), JSON.toJSONString(paymentClose));
        }

        // 查询订单信息
        PaymentResp paymentResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
            .query(paymentOrder.getTransNo(), paymentOrder.getOrderNo());
        log.info("closedPayment VENDOR: {}, CHANNEL: {} paymentResp={}", paymentOrder.getPaymentVendor(),
            paymentOrder.getPaymentChannel(), JSON.toJSONString(paymentResp));

        return paymentResp;
    }


    @Transactional
    @Override
    public void paymentStatus(String orderNo) {

        // 订单编号查询
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo( orderNo);
        if (Objects.isNull(paymentOrder)) {
            throw new BizException("订单不存在");
        }

        UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig = UserPaymentOrderWrapper.PaymentOrderReqConfig
            .builder()
            .userId(String.valueOf(paymentOrder.getUserId()))
            .merOrderNo(orderNo)
            .build();

        // 用户下单请求锁
        String lockName = redisCacheService.getPaymentCacheKey(orderNo);
        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {

            // 已产生三方交易流水号，先判断三方订单支付状态若在支付中，则重复返回相同支付配置参数;避免用户重复支付
            // 原生支付（微信，支付宝）流水号后产品，需要查询三方支付订单状态
            if (StringUtils.isNotBlank(paymentOrder.getTransNo())
                || EPaymentVendor.ORIGINAL.name().equalsIgnoreCase(paymentOrder.getPaymentVendor())
                || EPaymentVendor.WXPAY.name().equalsIgnoreCase(paymentOrder.getPaymentVendor())
                || EPaymentVendor.ALIPAY.name().equalsIgnoreCase(paymentOrder.getPaymentVendor())) {

                // 获取三方支付订单信息，根据订单状处理
                PaymentResp paymentResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
                    .query(paymentOrder.getTransNo(), paymentOrder.getOrderNo());
                if (Objects.nonNull(paymentResp)) {
                    if (PaymentStatus.PENDDING == paymentResp.getPaymentStatus()) {

                        // 获取缓存配置信息
                        String paymentConfig = redisCacheService.getUserPaymentConfig(reqConfig.getUserId(), paymentOrder.getOrderNo());
                        if (StringUtils.isBlank(paymentConfig) && EPaymentStatus.CLOSED != paymentOrder.getStatus()) {
                            // 支付配置已失效，待支付订单状态调整为已关闭，提醒用户重新购买
                            PaymentClose paymentClose = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor())
                                .close(paymentOrder.getTransNo(), "支付超时", paymentOrder.getOrderNo());

                            // 更新订单状态为已超时
                            UserPaymentOrderWrapper.UserPaymentOrder update = UserPaymentOrderWrapper.UserPaymentOrder
                                .builder()
                                .id(paymentOrder.getId())
                                .status(EPaymentStatus.CLOSED)
                                .errorMsg(paymentClose.getMsg())
                                .build();
                            userPaymentOrderService.updateById(JSON.parseObject(update.jsonString(), UserPaymentOrderWrapper.UserPaymentOrder.class));

                            // 订单关闭流程
                            cancelPayment(UserPaymentOrderWrapper.UserPaymentOrder.from(JSON.toJSONString(paymentOrder)), paymentResp);
                        }

                    }

                    // 更新用户支付订单状态
                    updateUserPaymentOrderStatus(reqConfig.getUserId(), paymentOrder, paymentResp);
                }
            }
        },10L,TimeUnit.SECONDS);

    }
}
