package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.pay.WxPay;
import com.iformall.pay.WxPayment;
import com.iformall.pay.WxRefundOrderP;
import com.iformall.pay.WxRefundOrderSP;
import com.iformall.service.WxOrderService;
import com.iformall.service.WxRefundOrderService;
import com.iformall.utils.BeanUtils;
import com.iformall.utils.CipherUtil;
import com.iformall.utils.Utility;
import com.iformall.utils.XmlUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class WxRefundOrderServiceImpl implements WxRefundOrderService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxAppinfoMapper wxAppinfoMapper;

    @Autowired
    WxRefundOrderMapper wxRefundOrderMapper;

    @Autowired
    WxOrderMapper wxOrderMapper;

    @Autowired
    WxPayOrderMapper wxPayOrderMapper;

    @Autowired
    WxPayAccountMapper wxPayAccountMapper;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxCouponOrderMapper wxCouponOrderMapper;

    @Autowired
    WxMerchantBUserMapper wxMerchantBUserMapper;

    @Autowired
    WxTemplateMsgMapper wxTemplateMsgMapper;

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxCouponMerchantMapper wxCouponMerchantMapper;

    @Autowired
    WxCUserMapper wxCUserMapper;


    JSONObject errorRefundReqMap = JSON.parseObject("{\n" +
            "  \"SYSTEMERROR\": {\n" +
            "    \"detail\": \"接口返回错误\",\n" +
            "    \"reason\": \"系统超时等\",\n" +
            "    \"resolution\": \"请不要更换商户退款单号，请使用相同参数再次调用API。\"\n" +
            "  },\n" +
            "  \"BIZERR_NEED_RETRY\": {\n" +
            "    \"detail\": \"退款业务流程错误，需要商户触发重试来解决\",\n" +
            "    \"reason\": \"并发情况下，业务被拒绝，商户重试即可解决\",\n" +
            "    \"resolution\": \"请不要更换商户退款单号，请使用相同参数再次调用API。\"\n" +
            "  },\n" +
            "  \"TRADE_OVERDUE\": {\n" +
            "    \"detail\": \"订单已经超过退款期限\",\n" +
            "    \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" +
            "    \"resolution\": \"请选择其他方式自行退款\"\n" +
            "  },\n" +
            "  \"ERROR\": {\n" +
            "    \"detail\": \"业务错误\",\n" +
            "    \"reason\": \"申请退款业务发生错误\",\n" +
            "    \"resolution\": \"该错误都会返回具体的错误原因，请根据实际返回做相应处理。\"\n" +
            "  },\n" +
            "  \"USER_ACCOUNT_ABNORMAL\": {\n" +
            "    \"detail\": \"退款请求失败\",\n" +
            "    \"reason\": \"用户帐号注销\",\n" +
            "    \"resolution\": \"此状态代表退款申请失败，商户可自行处理退款。\"\n" +
            "  },\n" +
            "  \"INVALID_REQ_TOO_MUCH\": {\n" +
            "    \"detail\": \"无效请求过多\",\n" +
            "    \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" +
            "    \"resolution\": \"请检查业务是否正常，确认业务正常后请在1分钟后再来重试\"\n" +
            "  },\n" +
            "  \"NOTENOUGH\": {\n" +
            "    \"detail\": \"余额不足\",\n" +
            "    \"reason\": \"商户可用退款余额不足\",\n" +
            "    \"resolution\": \"此状态代表退款申请失败，商户可根据具体的错误提示做相应的处理。\"\n" +
            "  },\n" +
            "  \"INVALID_TRANSACTIONID\": {\n" +
            "    \"detail\": \"无效transaction_id\",\n" +
            "    \"reason\": \"请求参数未按指引进行填写\",\n" +
            "    \"resolution\": \"请求参数错误，检查原交易号是否存在或发起支付交易接口返回失败\"\n" +
            "  },\n" +
            "  \"PARAM_ERROR\": {\n" +
            "    \"detail\": \"参数错误\",\n" +
            "    \"reason\": \"请求参数未按指引进行填写\",\n" +
            "    \"resolution\": \"请求参数错误，请重新检查再调用退款申请\"\n" +
            "  },\n" +
            "  \"APPID_NOT_EXIST\": {\n" +
            "    \"detail\": \"APPID不存在\",\n" +
            "    \"reason\": \"参数中缺少APPID\",\n" +
            "    \"resolution\": \"请检查APPID是否正确\"\n" +
            "  },\n" +
            "  \"MCHID_NOT_EXIST\": {\n" +
            "    \"detail\": \"MCHID不存在\",\n" +
            "    \"reason\": \"参数中缺少MCHID\",\n" +
            "    \"resolution\": \"请检查MCHID是否正确\"\n" +
            "  },\n" +
            "  \"REQUIRE_POST_METHOD\": {\n" +
            "    \"detail\": \"请使用post方法\",\n" +
            "    \"reason\": \"未使用post传递参数\",\n" +
            "    \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" +
            "  },\n" +
            "  \"SIGNERROR\": {\n" +
            "    \"detail\": \"签名错误\",\n" +
            "    \"reason\": \"参数签名结果不正确\",\n" +
            "    \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" +
            "  },\n" +
            "  \"XML_FORMAT_ERROR\": {\n" +
            "    \"detail\": \"XML格式错误\",\n" +
            "    \"reason\": \"XML格式错误\",\n" +
            "    \"resolution\": \"请检查XML参数格式是否正确\"\n" +
            "  },\n" +
            "  \"FREQUENCY_LIMITED\": {\n" +
            "    \"detail\": \"频率限制\",\n" +
            "    \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" +
            "    \"resolution\": \"该笔退款未受理，请降低频率后重试\"\n" +
            "  }\n" +
            "}");

    JSONObject errorRefundQueryMap = JSON.parseObject("{\n" +
            "  \"SYSTEMERROR\": {\n" +
            "    \"detail\": \"接口返回错误\",\n" +
            "    \"reason\": \"系统超时等\",\n" +
            "    \"resolution\": \"请不要更换商户退款单号，请使用相同参数再次调用API。\"\n" +
            "  },\n" +
            "  \"BIZERR_NEED_RETRY\": {\n" +
            "    \"detail\": \"退款业务流程错误，需要商户触发重试来解决\",\n" +
            "    \"reason\": \"并发情况下，业务被拒绝，商户重试即可解决\",\n" +
            "    \"resolution\": \"请不要更换商户退款单号，请使用相同参数再次调用API。\"\n" +
            "  },\n" +
            "  \"TRADE_OVERDUE\": {\n" +
            "    \"detail\": \"订单已经超过退款期限\",\n" +
            "    \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" +
            "    \"resolution\": \"请选择其他方式自行退款\"\n" +
            "  },\n" +
            "  \"ERROR\": {\n" +
            "    \"detail\": \"业务错误\",\n" +
            "    \"reason\": \"申请退款业务发生错误\",\n" +
            "    \"resolution\": \"该错误都会返回具体的错误原因，请根据实际返回做相应处理。\"\n" +
            "  },\n" +
            "  \"USER_ACCOUNT_ABNORMAL\": {\n" +
            "    \"detail\": \"退款请求失败\",\n" +
            "    \"reason\": \"用户帐号注销\",\n" +
            "    \"resolution\": \"此状态代表退款申请失败，商户可自行处理退款。\"\n" +
            "  },\n" +
            "  \"INVALID_REQ_TOO_MUCH\": {\n" +
            "    \"detail\": \"无效请求过多\",\n" +
            "    \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" +
            "    \"resolution\": \"请检查业务是否正常，确认业务正常后请在1分钟后再来重试\"\n" +
            "  },\n" +
            "  \"NOTENOUGH\": {\n" +
            "    \"detail\": \"余额不足\",\n" +
            "    \"reason\": \"商户可用退款余额不足\",\n" +
            "    \"resolution\": \"此状态代表退款申请失败，商户可根据具体的错误提示做相应的处理。\"\n" +
            "  },\n" +
            "  \"INVALID_TRANSACTIONID\": {\n" +
            "    \"detail\": \"无效transaction_id\",\n" +
            "    \"reason\": \"请求参数未按指引进行填写\",\n" +
            "    \"resolution\": \"请求参数错误，检查原交易号是否存在或发起支付交易接口返回失败\"\n" +
            "  },\n" +
            "  \"PARAM_ERROR\": {\n" +
            "    \"detail\": \"参数错误\",\n" +
            "    \"reason\": \"请求参数未按指引进行填写\",\n" +
            "    \"resolution\": \"请求参数错误，请重新检查再调用退款申请\"\n" +
            "  },\n" +
            "  \"APPID_NOT_EXIST\": {\n" +
            "    \"detail\": \"APPID不存在\",\n" +
            "    \"reason\": \"参数中缺少APPID\",\n" +
            "    \"resolution\": \"请检查APPID是否正确\"\n" +
            "  },\n" +
            "  \"MCHID_NOT_EXIST\": {\n" +
            "    \"detail\": \"MCHID不存在\",\n" +
            "    \"reason\": \"参数中缺少MCHID\",\n" +
            "    \"resolution\": \"请检查MCHID是否正确\"\n" +
            "  },\n" +
            "  \"REQUIRE_POST_METHOD\": {\n" +
            "    \"detail\": \"请使用post方法\",\n" +
            "    \"reason\": \"未使用post传递参数\",\n" +
            "    \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" +
            "  },\n" +
            "  \"SIGNERROR\": {\n" +
            "    \"detail\": \"签名错误\",\n" +
            "    \"reason\": \"参数签名结果不正确\",\n" +
            "    \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" +
            "  },\n" +
            "  \"XML_FORMAT_ERROR\": {\n" +
            "    \"detail\": \"XML格式错误\",\n" +
            "    \"reason\": \"XML格式错误\",\n" +
            "    \"resolution\": \"请检查XML参数格式是否正确\"\n" +
            "  },\n" +
            "  \"FREQUENCY_LIMITED\": {\n" +
            "    \"detail\": \"频率限制\",\n" +
            "    \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" +
            "    \"resolution\": \"该笔退款未受理，请降低频率后重试\"\n" +
            "  }\n" +
            "}");


    private boolean isMerchantOrder(WxOrder wxOrder, Long merchantId) {
        if (wxOrder.getType().equals(EnumOrderType.COUPON.getCode())) {
            WxCoupon wxCoupon = wxCouponMapper.selectById(wxOrder.getProductId());
            if (wxCoupon != null) {
                WxCouponMerchant wxCouponMerchant = new WxCouponMerchant();
                wxCouponMerchant.setProductId(wxCoupon.getId());
                wxCouponMerchant.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                List<WxCouponMerchant> couponMerchantList = wxCouponMerchantMapper.findList(wxCouponMerchant);
                if (couponMerchantList.stream().anyMatch(cm -> cm.getMerchantId().equals(merchantId))) {
                    return true;
                }
            }
        } else if (wxOrder.getType().equals(EnumOrderType.MICROPAY.getCode())) {
            WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(wxOrder.getProductId());
            if (wxMerchantBUser != null && wxMerchantBUser.equals(merchantId)) {
                return true;
            }
        } else if (wxOrder.getType().equals(EnumOrderType.NATIVEPAY.getCode())) {


        } else if (wxOrder.getType().equals(EnumOrderType.PREPAIDCARD.getCode())) {

        }

        return false;
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public ResultData createRefundOrder(WxAppinfo appInfo, Long couponOrderId, EnumPayType payType, Long bUserId) {
        WxCouponOrder wxCouponOrder = wxCouponOrderMapper.selectById(couponOrderId);
        if (wxCouponOrder == null) {
            logger.error("券ID不存在:" + couponOrderId);
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
        }

        WxOrder wxOrder = wxOrderMapper.selectById(wxCouponOrder.getOrderId());
        if (wxOrder == null) {
            logger.error("订单ID不存在:" + couponOrderId);
            throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND);
        }

        if (payType == EnumPayType.PAY_B_REFUND) {
            logger.info("B端发起退款: bUserId-" + bUserId);
            if (bUserId == null || bUserId == 0) {
                logger.error("B端用户不存在:" + bUserId);
                throw new MallinkException(ErrorCode.USER_IS_EMPTY);
            }
            // B端用户退款检查一下商户
            WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(bUserId);
            if (wxMerchantBUser == null) {
                logger.error("操作员ID不存在:" + bUserId);
                throw new MallinkException(ErrorCode.REFUND_ORDER_BUSER_IS_NULL);
            }
            if (!isMerchantOrder(wxOrder, wxMerchantBUser.getMerchantId())) {
                logger.error("订单: productId-" + wxOrder.getProductId() + "退款: couponMerchantId-" + wxMerchantBUser.getMerchantId());
                throw new MallinkException(ErrorCode.REFUND_ORDER_BUSER_NOT_EQUAL);
            }
        } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
            logger.info("ADMIN端发起退款: bUserId-" + bUserId);
        } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
            logger.info("auto端发起退款");
        } else {
            logger.info("自己发起退款: cUserId-" + bUserId);
        }

        if (wxOrder.getPayment() <= 0) {
            logger.error("订单支付金额小于等于0: " + wxOrder.toString());
            throw new MallinkException(ErrorCode.REFUND_PAY_ORDER_IS_ZERO);
        }

        if (wxCouponOrder.getCouponOrderStatus().equals(EnumCouponOrderStatus.COUPON_ORDER_INVALID.getCode())) {
            logger.error("已退款: couponOrder-" + couponOrderId);
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_OVER_TIME);
        }
        if (wxCouponOrder.getCouponOrderStatus().equals(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode())) {
            logger.error("已经核销过的券: couponOrder-" + couponOrderId);
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED);
        }
        final IdWorker idWorker = IdWorker.get();
        Long refundOrderId = idWorker.nextId();

        Date currentDate = new Date();

        // 创建 refund Order
        WxOrder rOrder = new WxOrder();
        rOrder.setId(refundOrderId);
        rOrder.setTenantId(appInfo.getTenantId());
        rOrder.setOrderNumber(wxOrder.getOrderNumber());  // 退款订单填写支付订单orderNumber
        rOrder.setProductId(wxOrder.getProductId());
        rOrder.setType(EnumOrderType.COUPON.getCode());
        rOrder.setCUserId(wxOrder.getCUserId());
        if (payType == EnumPayType.PAY_B_REFUND) {
            rOrder.setProductId(bUserId); //B端发起退款后存B端用户ID在此
        }
        rOrder.setPaymentType(payType.getCode());
        rOrder.setPayment(wxOrder.getPayment());
        rOrder.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_REFUND.getCode());
        rOrder.setCreateDate(currentDate);
        rOrder.setUpdateDate(currentDate);
        try {
            wxOrderMapper.insert(rOrder);
        } catch (Exception e) {
            logger.error("退款订单保存出错: " + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "退款订单保存出错");
        }

        // 更改 couponOrder 状态
        if (wxCouponOrder.getCouponType().equals(EnumCouponType.CARD_MULTIMCH.getCode())) {
            wxCouponOrder.setCouponOrderStatus(EnumCouponOrderStatus.CARD_RETURNED.getCode()); // 卡线下退款
        } else {
            wxCouponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_INVALID.getCode()); //3退款,券作废
        }
        if (payType == EnumPayType.PAY_B_REFUND) {
            wxCouponOrder.setBUserId(bUserId);
        } else {
            wxCouponOrder.setBUserId(payType.getCode().longValue());//其他退款模式将退款方式存入BUSERID
        }
        wxCouponOrder.setUpdateDate(currentDate);
        try {
            wxCouponOrderMapper.updateById(wxCouponOrder);
        } catch (Exception e) {
            logger.error("db failed: couponOrder-" + couponOrderId + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }

        // 查找支付订单
        WxPayOrder payOrderQ = new WxPayOrder();
        payOrderQ.setTenantId(appInfo.getTenantId());
        payOrderQ.setCUserId(wxOrder.getCUserId());
        payOrderQ.setOrderId(wxOrder.getId());
        payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());

        WxPayOrder payOrder = null;
        List<WxPayOrder> list = wxPayOrderMapper.findList(payOrderQ);
        if (list.size() > 0) {
            if (list.size() > 1) {
                logger.error("TODO: payOrder成功记录应该只有一条？？？？！！！");
            }
            logger.warn("");
            payOrder = list.get(0);
        }
        if (payOrder == null) {
            logger.error("支付订单不存在(payOrder不存在)");
            return new ResultData(ErrorCode.PAY_ORDER_NOT_FOUND);
        }

        WxRefundOrder record = new WxRefundOrder();
        record.setPayOrderNo(String.valueOf(payOrder.getId()));
        record.setOrderId(rOrder.getId());
        // 创建退款订单
        Long refundId = idWorker.nextId();
        String out_refund_id = String.valueOf(refundId);

        record.setId(refundId);
        record.setTenantId(appInfo.getTenantId());
        record.setCreateTime(currentDate);
        record.setUpdateTime(currentDate);
        // 微信内部订单号
        record.setTransactionId(payOrder.getTransactionId());
        record.setCUserId(payOrder.getCUserId());
        record.setTotalFee(payOrder.getPayAmount());
        record.setRefundFee(payOrder.getPayAmount());
        record.setRefundTimeStart(currentDate);
        record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode());

        // 退款订单
        try {
            int sqlRow = wxRefundOrderMapper.insert(record);
            if (sqlRow != 1) {
                logger.error("退款订单数据库插入出错: " + record.toString());
                throw new MallinkException(ErrorCode.DB_FAIL);
            }
        } catch (Exception e) {
            logger.error("退款订单数据库插入出错: " + record.toString());
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());
        if (StringUtils.isBlank(payAccount.getApiKey())) {
            logger.error("支付密钥为空");
            throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员");
        }
        if (StringUtils.isBlank(payAccount.getCertPath())) {
            logger.error("证书路径为空");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员");
        }
        if (!Utility.isFileExist(payAccount.getCertPath())) {
            logger.error("证书文件不存在");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员");
        }
        // check 是否有退款订单
        List<WxRefundOrder> refundList = wxRefundOrderMapper.findList(record);
        if (refundList.size() > 0) {
            logger.error("退款订单已存在, 无法再提交退款申请");
            throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请");
        }
        // 实际支付
        // 向微信提交退款申请
        if (payAccount.getType() == EnumPayMode.MCH.getCode()) {
            // 普通商户模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderP wxRefundOrderP = new WxRefundOrderP();
            wxRefundOrderP.setAppid(appInfo.getAppId());
            wxRefundOrderP.setMch_id(payAccount.getMchId());
            wxRefundOrderP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null)
                wxRefundOrderP.setTransaction_id(record.getTransactionId());
            // 支付订单号
            wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderP.setOut_refund_no(out_refund_id);
            wxRefundOrderP.setTotal_fee(record.getTotalFee());
            wxRefundOrderP.setRefund_fee(record.getRefundFee());
            if (payType == EnumPayType.PAY_B_REFUND) {
                wxRefundOrderP.setRefund_desc("B端商户退款");
            } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
                wxRefundOrderP.setRefund_desc("管理端商户退款");
            } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
                wxRefundOrderP.setRefund_desc("超期自动退款");
            } else {
                wxRefundOrderP.setRefund_desc("用户自己退款");
            }
            wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl());

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderP);
            } catch (Exception e) {
                logger.error("退款命令生辰: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR);
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap);
            }
        } else {
            // 服务商模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP();
            wxRefundOrderSP.setAppid(appInfo.getParentAppId());
            wxRefundOrderSP.setSub_appid(appInfo.getAppId());
            wxRefundOrderSP.setMch_id(payAccount.getMchId());
            wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId());
            wxRefundOrderSP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null)
                wxRefundOrderSP.setTransaction_id(record.getTransactionId());
            // 支付订单号
            wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderSP.setOut_refund_no(out_refund_id);
            wxRefundOrderSP.setTotal_fee(record.getTotalFee());
            wxRefundOrderSP.setRefund_fee(record.getRefundFee());
            if (payType == EnumPayType.PAY_B_REFUND) {
                wxRefundOrderSP.setRefund_desc("B端商户退款");
            } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
                wxRefundOrderSP.setRefund_desc("管理端商户退款");
            } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
                wxRefundOrderSP.setRefund_desc("超期自动退款");
            } else {
                wxRefundOrderSP.setRefund_desc("用户自己退款");
            }
            wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl());
            wxRefundOrderSP.setSign_type("HMAC-SHA256");

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderSP);
            } catch (Exception e) {
                logger.error("退款命令生成: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败");
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("err_code_des");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg);
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public ResultData createRefundOrderFromMicroPay(WxAppinfo appInfo, Long orderId, EnumPayType payType, Long bUserId) {
        WxOrder wxOrder = wxOrderMapper.selectById(orderId);

        if (payType == EnumPayType.PAY_B_REFUND) {
            logger.info("B端发起退款: bUserId-" + bUserId);
            if (bUserId == null || bUserId == 0) {
                logger.error("B端用户不存在:" + bUserId);
                throw new MallinkException(ErrorCode.USER_IS_EMPTY);
            }
            // B端用户退款检查一下商户
            WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(bUserId);
            if (wxMerchantBUser == null) {
                logger.error("操作员ID不存在:" + bUserId);
                throw new MallinkException(ErrorCode.REFUND_ORDER_BUSER_IS_NULL);
            }
            if (!isMerchantOrder(wxOrder, wxMerchantBUser.getMerchantId())) {
                logger.error("订单: productId-" + wxOrder.getProductId() + "退款: MerchantId-" + wxMerchantBUser.getMerchantId());
                throw new MallinkException(ErrorCode.REFUND_ORDER_BUSER_NOT_EQUAL);
            }
        } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
            logger.info("ADMIN端发起退款: bUserId-" + bUserId);
        } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
            logger.info("auto端发起退款");
        } else {
            logger.info("自己发起退款: cUserId-" + bUserId);
        }
        if (wxOrder.getPayment() <= 0) {
            logger.error("订单支付金额小于等于0: " + wxOrder.toString());
            throw new MallinkException(ErrorCode.REFUND_PAY_ORDER_IS_ZERO);
        }
        final IdWorker idWorker = IdWorker.get();
        Long refundOrderId = idWorker.nextId();

        Date currentDate = new Date();

        // 创建 refund Order
        WxOrder rOrder = new WxOrder();
        rOrder.setId(refundOrderId);
        rOrder.setTenantId(appInfo.getTenantId());
        rOrder.setOrderNumber(wxOrder.getOrderNumber());  // 退款订单填写支付订单orderNumber
        rOrder.setType(EnumOrderType.MICROPAY.getCode());
        rOrder.setCUserId(wxOrder.getCUserId());
        if (payType == EnumPayType.PAY_B_REFUND) {
            rOrder.setProductId(bUserId); //B端发起退款后存B端用户ID在此
        }
        rOrder.setPaymentType(payType.getCode());
        rOrder.setPayment(wxOrder.getPayment());
        rOrder.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_REFUND.getCode());
        rOrder.setCreateDate(currentDate);
        rOrder.setUpdateDate(currentDate);
        try {
            wxOrderMapper.insert(rOrder);
        } catch (Exception e) {
            logger.error("退款订单保存出错: " + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "退款订单保存出错");
        }

        // 查找支付订单
        WxPayOrder payOrderQ = new WxPayOrder();
        payOrderQ.setTenantId(appInfo.getTenantId());
        payOrderQ.setCUserId(wxOrder.getCUserId());
        payOrderQ.setOrderId(wxOrder.getId());
        payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());

        WxPayOrder payOrder = null;
        List<WxPayOrder> list = wxPayOrderMapper.findList(payOrderQ);
        if (list.size() > 0) {
            if (list.size() > 1) {
                logger.error("TODO: payOrder成功记录应该只有一条？？？？！！！");
            }
            logger.warn("");
            payOrder = list.get(0);
        }
        if (payOrder == null) {
            logger.error("支付订单不存在(payOrder不存在)");
            return new ResultData(ErrorCode.PAY_ORDER_NOT_FOUND);
        }

        WxRefundOrder record = new WxRefundOrder();
        record.setPayOrderNo(String.valueOf(payOrder.getId()));
        record.setOrderId(rOrder.getId());
        // 创建退款订单
        Long refundId = idWorker.nextId();
        String out_refund_id = String.valueOf(refundId);

        record.setId(refundId);
        record.setTenantId(appInfo.getTenantId());
        record.setCreateTime(currentDate);
        record.setUpdateTime(currentDate);
        // 微信内部订单号
        record.setTransactionId(payOrder.getTransactionId());
        record.setCUserId(payOrder.getCUserId());
        record.setTotalFee(payOrder.getPayAmount());
        record.setRefundFee(payOrder.getPayAmount());
        record.setRefundTimeStart(currentDate);
        record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode());

        // 退款订单
        try {
            int sqlRow = wxRefundOrderMapper.insert(record);
            if (sqlRow != 1) {
                logger.error("退款订单数据库插入出错: " + record.toString());
                throw new MallinkException(ErrorCode.DB_FAIL);
            }
        } catch (Exception e) {
            logger.error("退款订单数据库插入出错: " + record.toString());
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());
        if (StringUtils.isBlank(payAccount.getApiKey())) {
            logger.error("支付密钥为空");
            throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员");
        }
        if (StringUtils.isBlank(payAccount.getCertPath())) {
            logger.error("证书路径为空");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员");
        }
        if (!Utility.isFileExist(payAccount.getCertPath())) {
            logger.error("证书文件不存在");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员");
        }
        // check 是否有退款订单
        List<WxRefundOrder> refundList = wxRefundOrderMapper.findList(record);
        if (refundList.size() > 0) {
            logger.error("退款订单已存在, 无法再提交退款申请");
            throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请");
        }

        // 向微信提交退款申请
        if (payAccount.getType() == EnumPayMode.MCH.getCode()) {
            // 普通商户模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderP wxRefundOrderP = new WxRefundOrderP();
            wxRefundOrderP.setAppid(appInfo.getAppId());
            wxRefundOrderP.setMch_id(payAccount.getMchId());
            wxRefundOrderP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null)
                wxRefundOrderP.setTransaction_id(record.getTransactionId());
            // 支付订单号
            wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderP.setOut_refund_no(out_refund_id);
            wxRefundOrderP.setTotal_fee(record.getTotalFee());
            wxRefundOrderP.setRefund_fee(record.getRefundFee());
            if (payType == EnumPayType.PAY_B_REFUND) {
                wxRefundOrderP.setRefund_desc("B端商户退款");
            } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
                wxRefundOrderP.setRefund_desc("管理端商户退款");
            } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
                wxRefundOrderP.setRefund_desc("超期自动退款");
            } else {
                wxRefundOrderP.setRefund_desc("用户自己退款");
            }
            wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl());

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderP);
            } catch (Exception e) {
                logger.error("退款命令生辰: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR);
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap);
            }
        } else {
            // 服务商模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP();
            wxRefundOrderSP.setAppid(appInfo.getParentAppId());
            wxRefundOrderSP.setSub_appid(appInfo.getAppId());
            wxRefundOrderSP.setMch_id(payAccount.getMchId());
            wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId());
            wxRefundOrderSP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null)
                wxRefundOrderSP.setTransaction_id(record.getTransactionId());
            // 支付订单号
            wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderSP.setOut_refund_no(out_refund_id);
            wxRefundOrderSP.setTotal_fee(record.getTotalFee());
            wxRefundOrderSP.setRefund_fee(record.getRefundFee());
            if (payType == EnumPayType.PAY_B_REFUND) {
                wxRefundOrderSP.setRefund_desc("B端商户退款");
            } else if (payType == EnumPayType.PAY_ADMIN_REFUND) {
                wxRefundOrderSP.setRefund_desc("管理端商户退款");
            } else if (payType == EnumPayType.PAY_AUTO_REFUND) {
                wxRefundOrderSP.setRefund_desc("超期自动退款");
            } else {
                wxRefundOrderSP.setRefund_desc("用户自己退款");
            }
            wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl());
            wxRefundOrderSP.setSign_type("HMAC-SHA256");

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderSP);
            } catch (Exception e) {
                logger.error("退款命令生辰: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败");
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg);
            }
        }
    }

    /**
     * 微信退款查询
     *
     * @param appInfo
     * @param record
     */
    @Override
    public ResultData queryRefundOrder(WxAppinfo appInfo, WxRefundOrder record) {
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());
        if (payAccount.getType() == EnumPayMode.MCH.getCode()) {
            Map<String, String> paramMap = WxPayment.buildWeappRefundQueryMap(
                    appInfo.getAppId(), payAccount.getMchId(),
                    record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()),
                    record.getRefundId(), payAccount.getApiKey());
            String response = WxPay.orderRefundQuery(paramMap);
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            if ("SUCCESS".equals(result_no)) {
                String refund_id = returnMap.get("refund_id");
                return new ResultData(Result.SUCCESS, "退款", returnMap);
            } else {
                wxRefundOrderMapper.updateById(record);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap);
            }
        } else {
            Map<String, String> paramMap = WxPayment.buildSWeappRefundQueryMap(
                    appInfo.getParentAppId(), appInfo.getAppId(), payAccount.getMchId(), payAccount.getSubMchId(),
                    record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), record.getRefundId(), payAccount.getApiKey());
            String response = WxPay.orderRefundQuery(paramMap);
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            if ("SUCCESS".equals(result_no)) {
                String refund_id = returnMap.get("refund_id");
                return new ResultData(Result.SUCCESS, "退款", returnMap);
            } else {
                String errMsg = "";
                JSONObject errObj = errorRefundQueryMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                wxRefundOrderMapper.updateById(record);
                return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap);
            }
        }
    }

    /**
     * 微信退款结果通知
     *
     * @param paramMap 异步通知参数
     * @param payWay   支付方式
     * @return
     */
    @Override
    public String notify(Map<String, String> paramMap, EnumPayWay payWay) {
        // how to get wechatAppId, wechatMchId, partnerKey
        String appId = paramMap.get("appid");
        String subAppId = paramMap.get("sub_appid");
        String mchId = paramMap.get("mch_id");
        String subMchId = paramMap.get("sub_mch_id");
        if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) {
            // 普通商户号
            WxAppinfo appinfo = wxAppinfoMapper.findByAppId(appId);
            if (appinfo == null) {
                logger.error("未找到appid信息:" + appId);
                throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND);
            }
            WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId());
            if (payAccount == null) {
                logger.error("未找到mch_id信息:" + mchId);
                throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND);
            }
            if (!mchId.equalsIgnoreCase(payAccount.getMchId())) {
                logger.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId());
                throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL);
            }
            String partnerKey = payAccount.getApiKey();
            try {
                if (payWay == EnumPayWay.PAY_WAY_WEAPP) {
                    if (!"SUCCESS".equals(paramMap.get("return_code"))) {
                        logger.warn("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "订单状态码非SUCCESS");
                        return XmlUtil.getRequestXml(resultMap);
                    }

                    // 解密req_info
                    String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey);
                    Map<String, String> reqMap = WxPayment.xmlToMap(req_info);

                    String payOrderNo = reqMap.get("out_trade_no");
                    Long payOrderId = Long.valueOf(payOrderNo);
                    WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId);
                    if (payOrder == null) {
                        logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "支付订单不存在");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证支付金额
                    if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) {
                        logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "支付订单总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    String refundIdStr = reqMap.get("out_refund_no");
                    Long refundOrderId = Long.valueOf(refundIdStr);
                    WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId);
                    if (refundOrder == null) {
                        logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "退款订单不存在");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证支付金额
                    if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) {
                        logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "订单总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证退款金额
                    if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) {
                        logger.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "退款总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }

                    // 处理支付成功
                    handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id"));
                    logger.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                    SortedMap resultMap = new TreeMap();
                    resultMap.put("return_code", "SUCCESS");
                    resultMap.put("return_msg", "OK");
                    return XmlUtil.getRequestXml(resultMap);
                }
            } catch (RuntimeException e) {
                logger.warn("notify refund paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString() + ", e:" + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage());
            } catch (Exception e) {
                logger.warn("notify refund, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString() + ", e:" + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage());
            }
        } else {
            // 服务号回调
            WxAppinfo appinfo = wxAppinfoMapper.findByAppId(subAppId);
            if (appinfo == null) {
                logger.error("未找到appid信息:" + appId);
                throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND);
            }
            WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId());
            if (payAccount == null) {
                logger.error("未找到mch_id信息:" + mchId);
                throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND);
            }
            if (!mchId.equalsIgnoreCase(payAccount.getMchId())) {
                logger.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId());
                throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL);
            }
            String partnerKey = payAccount.getApiKey();
            try {
                if (payWay == EnumPayWay.PAY_WAY_WEAPP) {
                    if (!"SUCCESS".equals(paramMap.get("return_code"))) {
                        logger.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "订单状态码非SUCCESS");
                        return XmlUtil.getRequestXml(resultMap);
                    }

                    // 解密req_info
                    String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey);
                    logger.info(req_info);
                    Map<String, String> reqMap = WxPayment.xmlToMap(req_info);

                    String payOrderNo = reqMap.get("out_trade_no");
                    if (payOrderNo == null) {
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "SUCCESS");
                        resultMap.put("return_msg", "OK");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    Long payOrderId = Long.valueOf(payOrderNo);
                    WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId);
                    if (payOrder == null) {
                        logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "支付订单不存在");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证支付金额
                    if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) {
                        logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "支付订单总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    String refundIdStr = reqMap.get("out_refund_no");
                    Long refundOrderId = Long.valueOf(refundIdStr);
                    WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId);
                    if (refundOrder == null) {
                        logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "退款订单不存在");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证支付金额
                    if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) {
                        logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "订单总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }
                    // 验证退款金额
                    if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) {
                        logger.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString());
                        SortedMap resultMap = new TreeMap();
                        resultMap.put("return_code", "FAIL");
                        resultMap.put("return_msg", "退款总金额不一致");
                        return XmlUtil.getRequestXml(resultMap);
                    }

                    // 处理支付成功
                    handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id"));
                    logger.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + reqMap.toString() + ",  payWay:" + payWay.toString());
                    SortedMap resultMap = new TreeMap();
                    resultMap.put("return_code", "SUCCESS");
                    resultMap.put("return_msg", "OK");
                    return XmlUtil.getRequestXml(resultMap);
                }
            } catch (RuntimeException e) {
                logger.warn("notify refund, wepay checksign error, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString() + ", e:" + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR);
            } catch (Exception e) {
                logger.warn("notify refund, paramMap: " + paramMap.toString() + ",  payWay:" + payWay.toString() + ", e:" + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage());
            }
        }

        SortedMap resultMap = new TreeMap();
        resultMap.put("return_code", "FAIL");
        resultMap.put("return_msg", "FAILED");
        return XmlUtil.getRequestXml(resultMap);
    }

    @Override
    public void callback(Map<String, String> paramMap, EnumPayWay payWay) {

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public void handleRefundSuccess(WxRefundOrder refundOrder, String transactionId, String refundId) {
        EnumRefundStatus refundStatus = EnumRefundStatus.getEnum(refundOrder.getRefundOrderStatus());
        // 判断退款状态
        if (refundStatus != EnumRefundStatus.REFUND_REQ_SUCCESS) {
            logger.error("refund success handle, refundOrder " + refundOrder.getRefundId() +
                    "is paid success , orderId : " + refundOrder.getOrderId());
            return;
        }

        WxOrder order = wxOrderMapper.selectById(refundOrder.getOrderId());
        if (order == null) {
            logger.error("pay success handle, order " + refundOrder.getOrderId() + " not found , refundId : " + refundOrder.getId());
            throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND);
        }

        Date currentDate = new Date();
        WxRefundOrder updateOrder = new WxRefundOrder();
        updateOrder.setId(refundOrder.getId());
        updateOrder.setOrderId(refundOrder.getOrderId());
        updateOrder.setUpdateTime(currentDate);
        updateOrder.setRefundOrderStatus(EnumRefundStatus.REFUND_SUCCESS.getCode());
        updateOrder.setTransactionId(transactionId);
        updateOrder.setRefundId(refundId);
        // 修改退款订单状态
        try {
            wxRefundOrderMapper.updateById(updateOrder);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL);
        }

        // 修改订单状态
        try {
            //拼团 非0为拼团券
            if (!order.getOrderGroupId().equals(0L)) {
                wxOrderService.updateOrderStatus(order);
            } else {
                wxOrderService.updateOrderStatus(order, EnumOrderStatus.ORDER_STATUS_REFUND_SUCCESS);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL);
        }

        // 消息
        /*
        Map<String, String> msgMap = new HashMap<>();
        try {
            msgMap.put("name", String.valueOf(order.getCouponId()));
            msgMap.put("orderNo", String.valueOf(order.getId()));
            msgMap.put("createTime", Utility.getDataFormatString3(order.getCreateDate()));
            msgMap.put("standingTime", order.getCreateDate() + "-" + currentDate );
            // 短信 通知 商户
            //smsSenderHandler.sendSms("SMS_18195394", order.getMobile(), msgMap);
        } catch (Exception e) {
            logger.error("pay success handle, sms send exception, payOrderi: " + updatePayOrder+ ", msgMap: " + msgMap.toString() + ", e: " + e.getMessage());
        }
        */
    }


    @Override
    public PageInfo<WxRefundOrder> listAsPage(WxRefundOrder record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxRefundOrderMapper.findList(record));
    }

    @Override
    public WxRefundOrder getById(Long id) {
        return wxRefundOrderMapper.selectById(id);
    }

    @Override
    public void saveOrUpdate(WxRefundOrder record) {
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            wxRefundOrderMapper.insert(record);
        } else {
            wxRefundOrderMapper.updateById(record);
        }
    }

    @Override
    public void deleteById(Long id) {
        wxRefundOrderMapper.deleteById(id);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public ResultData returnMoney(WxAppinfo appInfo, Long orderId) {
        WxOrder wxOrder = wxOrderMapper.selectById(orderId);
        final IdWorker idWorker = IdWorker.get();
        Date currentDate = new Date();
//        wxOrder.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_REFUND.getCode());
//        wxOrder.setUpdateDate(currentDate);
//        try {
//            wxOrderMapper.updateById(wxOrder);
//        } catch (Exception e) {
//            logger.error("订单修改出错: " + e.getMessage());
//            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "订单修改出错");
//        }

        // 查找支付订单
        WxPayOrder payOrderQ = new WxPayOrder();
        payOrderQ.setTenantId(appInfo.getTenantId());
        payOrderQ.setCUserId(wxOrder.getCUserId());
        payOrderQ.setOrderId(wxOrder.getId());
        payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());

        WxPayOrder payOrder = null;
        List<WxPayOrder> list = wxPayOrderMapper.findList(payOrderQ);
        if (list.size() > 0) {
            if (list.size() > 1) {
                logger.error("TODO: payOrder成功记录应该只有一条？？？？！！！");
            }
            logger.warn("");
            payOrder = list.get(0);
        }
        if (payOrder == null) {
            logger.error("支付订单不存在(payOrder不存在)");
            return new ResultData(ErrorCode.PAY_ORDER_NOT_FOUND);
        }

        WxRefundOrder record = new WxRefundOrder();
        record.setPayOrderNo(String.valueOf(payOrder.getId()));
        record.setOrderId(orderId);
        // 创建退款订单
        Long refundId = idWorker.nextId();
        String out_refund_id = String.valueOf(refundId);

        record.setId(refundId);
        record.setTenantId(appInfo.getTenantId());
        record.setCreateTime(currentDate);
        record.setUpdateTime(currentDate);
        // 微信内部订单号
        record.setTransactionId(payOrder.getTransactionId());
        record.setCUserId(payOrder.getCUserId());
        record.setTotalFee(payOrder.getPayAmount());
        record.setRefundFee(payOrder.getPayAmount());
        record.setRefundTimeStart(currentDate);
        record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode());

        // 退款订单
        try {
            int sqlRow = wxRefundOrderMapper.insert(record);
            if (sqlRow != 1) {
                logger.error("退款订单数据库插入出错: " + record.toString());
                throw new MallinkException(ErrorCode.DB_FAIL);
            }
        } catch (Exception e) {
            logger.error("退款订单数据库插入出错: " + record.toString());
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());
        if (StringUtils.isBlank(payAccount.getApiKey())) {
            logger.error("支付密钥为空");
            throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员");
        }
        if (StringUtils.isBlank(payAccount.getCertPath())) {
            logger.error("证书路径为空");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员");
        }
        if (!Utility.isFileExist(payAccount.getCertPath())) {
            logger.error("证书文件不存在");
            throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员");
        }
        // check 是否有退款订单
        List<WxRefundOrder> refundList = wxRefundOrderMapper.findList(record);
        if (refundList.size() > 0) {
            logger.error("退款订单已存在, 无法再提交退款申请");
            throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请");
        }

        // 实际支付
        // 向微信提交退款申请
        if (payAccount.getType().equals(EnumPayMode.MCH.getCode())) {
            // 普通商户模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderP wxRefundOrderP = new WxRefundOrderP();
            wxRefundOrderP.setAppid(appInfo.getAppId());
            wxRefundOrderP.setMch_id(payAccount.getMchId());
            wxRefundOrderP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null) {
                wxRefundOrderP.setTransaction_id(record.getTransactionId());
            }
            // 支付订单号
            wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderP.setOut_refund_no(out_refund_id);
            wxRefundOrderP.setTotal_fee(record.getTotalFee());
            wxRefundOrderP.setRefund_fee(record.getRefundFee());
            wxRefundOrderP.setRefund_desc("拼团失败退款");
            wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl());

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderP);
            } catch (Exception e) {
                logger.error("退款命令生辰: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR);
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap);
            }
        } else {
            // 服务商模式
            String noncestr = Utility.generate32UUID();
            WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP();
            wxRefundOrderSP.setAppid(appInfo.getParentAppId());
            wxRefundOrderSP.setSub_appid(appInfo.getAppId());
            wxRefundOrderSP.setMch_id(payAccount.getMchId());
            wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId());
            wxRefundOrderSP.setNonce_str(noncestr);
            // 微信内部订单号
            if (record.getTransactionId() != null) {
                wxRefundOrderSP.setTransaction_id(record.getTransactionId());
            }
            // 支付订单号
            wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo());
            // 退款支付订单号
            wxRefundOrderSP.setOut_refund_no(out_refund_id);
            wxRefundOrderSP.setTotal_fee(record.getTotalFee());
            wxRefundOrderSP.setRefund_fee(record.getRefundFee());
            wxRefundOrderSP.setRefund_desc("拼团失败退款");
            wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl());
            wxRefundOrderSP.setSign_type("HMAC-SHA256");

            Map signMap = null;
            try {
                signMap = BeanUtils.toStringMap(wxRefundOrderSP);
            } catch (Exception e) {
                logger.error("退款命令生辰: " + e.getMessage());
                throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常");
            }

            String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey());
            signMap.put("sign", signAgent);
            String response = null;
            try {
                response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId());
            } catch (Exception e) {
                logger.error("退款异常: " + e.getMessage());
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常");
            }
            logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString());
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String result_no = returnMap.get("result_code");
            String refund_id = returnMap.get("refund_id");
            // 设置 微信退款订单号
            record.setRefundId(refund_id);
            record.setRefundVendor(EnumPayWay.PAY_WAY_WEAPP.getCode());
            if ("SUCCESS".equals(result_no)) {
                logger.info("微信退款订单申请成功: " + returnMap.toString());
                try {
                    record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
                    wxRefundOrderMapper.updateById(record);
                    return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap);
                } catch (Exception e) {
                    logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString());
                    throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败");
                }
            } else {
                logger.error("微信退款订单申请失败: " + response);
                String errMsg = "";
                JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
                if (errObj != null) {
                    errMsg = errObj.toJSONString();
                    record.setFailReason(errMsg);
                } else {
                    errMsg = returnMap.get("return_msg");
                    record.setFailReason(errMsg);
                }
                record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
                wxRefundOrderMapper.updateById(record);
                throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg);
            }
        }
    }

    @Override
    public boolean hasRefundOrder(Long orderId, Integer status) {
        WxRefundOrder order = new WxRefundOrder();
        order.setOrderId(orderId);
        order.setRefundOrderStatus(status);
        return wxRefundOrderMapper.selectCount(new QueryWrapper(order)) > 0 ? true : false;
    }

}
