微信Native支付V3(java版本)

1.支付配置

官方地址:API列表 - Native支付 | 微信支付服务商文档中心 (qq.com)icon-default.png?t=N7T8https://pay.weixin.qq.com/docs/partner/products/partner-native-payment/apilist.html

注意:(appId账号)微信商户平台必须开通Native支付功能

2.业务代码实现

package org.nft.busi.controller;

import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.nft.common.pay.core.NftPayHttpResponse;
import org.nft.common.pay.core.enums.RequestMethodEnum;
import org.nft.common.pay.core.utils.DateTimeZoneUtil;
import org.nft.common.pay.way.wxpay.WxPayApi;
import org.nft.common.pay.way.wxpay.enums.WxDomainEnum;
import org.nft.common.pay.way.wxpay.enums.v3.BasePayApiEnum;
import org.nft.common.pay.way.wxpay.model.v3.Amount;
import org.nft.common.pay.way.wxpay.model.v3.UnifiedOrderModel;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author: dori
 * @createTime: 2024/04/17 13:47
 * @description: Native支付
 */
@Slf4j
@Controller
@RequestMapping("/wxPayV3")
public class demo {

    /**
     * 下单
     */
    @RequestMapping("/nativePay")
    @ResponseBody
    public String nativePay() {
        try {
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                .setAppid("appid值")
                .setMchid("商户id值")
                .setDescription("测试购买商品")
                .setOut_trade_no(UUID.fastUUID().toString(true))
                // 订单失效时间
                .setTime_expire(timeExpire)
                // 附加数据
                .setAttach(" ")
                .setNotify_url("回调地址".concat("/v3/payNotify"))
                .setAmount(new Amount().setTotal(1));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            NftPayHttpResponse response = WxPayApi.v3(
                RequestMethodEnum.POST,
                WxDomainEnum.CHINA.toString(),
                BasePayApiEnum.NATIVE_PAY.toString(),
                "商户id值",
                "序列号",
                null,
                "私钥文件路径",
                JSONUtil.toJsonStr(unifiedOrderModel)
            );
            log.info("统一下单响应 {}", response);
            return response.getBody();
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
    }

    /**
     * 支付回调
     */
    @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    @ResponseBody
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());

            log.info("支付通知明文 {}", plainText);

            if (StrUtil.isNotEmpty(plainText)) {
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }

    /**
     * 退款
     */
    @RequestMapping("/refund")
    @ResponseBody
    public String refund(@RequestParam(required = false) String transactionId,
                         @RequestParam(required = false) String outTradeNo) {
        String refundResult = "";
        try {
            String outRefundNo = PayKit.generateStr();
            log.info("商户退款单号: {}", outRefundNo);

            List<RefundGoodsDetail> list = new ArrayList<>();
            RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
                .setMerchant_goods_id("123")
                .setGoods_name("测试")
                .setUnit_price(1)
                .setRefund_amount(1)
                .setRefund_quantity(1);
            list.add(refundGoodsDetail);

            RefundModel refundModel = new RefundModel()
                .setOut_refund_no(outRefundNo)
                .setReason("测试退款")
                // 退款回调地址
                .setNotify_url(wxPayV3Bean.getRefundNotifyUrl().concat("/v3/refundNotify"))
                .setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
                .setGoods_detail(list);

            if (StrUtil.isNotEmpty(transactionId)) {
                refundModel.setTransaction_id(transactionId);
            }
            if (StrUtil.isNotEmpty(outTradeNo)) {
                refundModel.setOut_trade_no(outTradeNo);
            }
            log.info("退款参数 {}", JSONUtil.toJsonStr(refundModel));
            NftPayHttpResponse response = WxPayApi.v3(
                RequestMethodEnum.POST,
                WxDomainEnum.CHINA.toString(),
                BasePayApiEnum.REFUND.toString(),
                wxPayV3Bean.getMchId(),
                wxPayV3Bean.getMchSerialNo(),
                null,
                wxPayV3Bean.getKeyPath(),
                JSONUtil.toJsonStr(refundModel)
            );
            log.info("退款响应 {}", response);
            refundResult = response.getBody();
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
        return refundResult;
    }

    /**
     * 查询订单
     */
    @RequestMapping("/query")
    @ResponseBody
    public String query(@RequestParam String outTradeNo) {
        try {
            Map<String, String> params = new HashMap<>(16);
            params.put("mchid", wxPayV3Bean.getMchId());

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(params));
            NftPayHttpResponse response = WxPayApi.v3(
                RequestMethodEnum.GET,
                WxDomainEnum.CHINA.toString(),
                String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(), outTradeNo),
                wxPayV3Bean.getMchId(),
                wxPayV3Bean.getMchSerialNo(),
                null,
                wxPayV3Bean.getKeyPath(),
                params
            );
            log.info("查询响应 {}", response);
            if (response.getStatus() == OK) {
                return response.getBody();
            }
            return JSONUtil.toJsonStr(response);
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
    }
}

package org.nft.common.pay.core;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.util.StrUtil;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * NftPay Http Response
 * @author dori
 */
public class NftPayHttpResponse implements Serializable {
    private static final long serialVersionUID = 6089103955998013402L;
    private String body;
    private byte[] bodyByte;
    private int status;
    private Map<String, List<String>> headers;

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public byte[] getBodyByte() {
        return bodyByte;
    }

    public void setBodyByte(byte[] bodyByte) {
        this.bodyByte = bodyByte;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public Map<String, List<String>> getHeaders() {
        return headers;
    }

    public void setHeaders(Map<String, List<String>> headers) {
        this.headers = headers;
    }

    public String getHeader(String name) {
        List<String> values = this.headerList(name);
        return CollectionUtil.isEmpty(values) ? null : values.get(0);
    }

    private List<String> headerList(String name) {
        if (StrUtil.isBlank(name)) {
            return null;
        } else {
            CaseInsensitiveMap<String, List<String>> headersIgnoreCase = new CaseInsensitiveMap<>(getHeaders());
            return headersIgnoreCase.get(name.trim());
        }
    }

    @Override
    public String toString() {
        return "NftPayHttpResponse{" +
            "body='" + body + '\'' +
            ", status=" + status +
            ", headers=" + headers +
            '}';
    }
}
package org.nft.common.pay.core.enums;

/**
 * HTTP 请求的方法
 * @author dori
 */
public enum RequestMethodEnum {
    /**
     * 上传实质是 post 请求
     */
    UPLOAD("POST"),
    /**
     * post 请求
     */
    POST("POST"),
    /**
     * get 请求
     */
    GET("GET"),
    /**
     * put 请求
     */
    PUT("PUT"),
    /**
     * delete 请求
     */
    DELETE("DELETE"),
    /**
     * options 请求
     */
    OPTIONS("OPTIONS"),
    /**
     * head 请求
     */
    HEAD("HEAD"),
    /**
     * trace 请求
     */
    TRACE("TRACE"),
    /**
     * connect 请求
     */
    CONNECT("CONNECT"),
    /**
     * PATCH 请求
     */
    PATCH("PATCH"),
    ;

    private final String method;

    RequestMethodEnum(String method) {
        this.method = method;
    }

    @Override
    public String toString() {
        return this.method;
    }
}
package org.nft.common.pay.core.utils;

import cn.hutool.core.util.StrUtil;
import com.xkzhangsan.time.converter.DateTimeConverterUtil;
import com.xkzhangsan.time.formatter.DateTimeFormatterUtil;

import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Date;


/**
 * 时间工具类
 * @author dori
 */
public class DateTimeZoneUtil implements Serializable {

    private static final long serialVersionUID = -1331008203306650395L;

    /**
     * 时间转 TimeZone
     * <p>
     * 2020-08-17T16:46:37+08:00
     * @param time 时间戳
     * @return {@link String}  TimeZone 格式时间字符串
     * @throws Exception 异常信息
     */
    public static String dateToTimeZone(long time) throws Exception {
        return dateToTimeZone(new Date(time));
    }

    /**
     * 时间转 TimeZone
     * <p>
     * 2020-08-17T16:46:37+08:00
     * @param date {@link Date}
     * @return {@link String} TimeZone 格式时间字符串
     * @throws Exception 异常信息
     */
    public static String dateToTimeZone(Date date) throws Exception {
        String time;
        if (date == null) {
            throw new Exception("date is not null");
        }
        ZonedDateTime zonedDateTime = DateTimeConverterUtil.toZonedDateTime(date);
        time = DateTimeFormatterUtil.format(zonedDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_XXX_FMT);
        return time;
    }

    /**
     * TimeZone 时间转标准时间
     * <p>
     * 2020-08-17T16:46:37+08:00 to 2020-08-17 16:46:37
     * @param str TimeZone格式时间字符串
     * @return {@link String} 标准时间字符串
     * @throws Exception 异常信息
     */
    public static String timeZoneDateToStr(String str) throws Exception {
        String time;
        if (StrUtil.isBlank(str)) {
            throw new Exception("str is not null");
        }
        ZonedDateTime zonedDateTime = DateTimeFormatterUtil.parseToZonedDateTime(str, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_XXX_FMT);
        if (zonedDateTime == null) {
            throw new Exception("str to zonedDateTime fail");
        }
        time = zonedDateTime.format(DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_FMT);
        return time;
    }


    public static void main(String[] args) throws Exception {
        String timeZone = dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
        String timeZone2 = dateToTimeZone(new Date());
        System.out.println(timeZone + " " + timeZone2);
        String date = timeZoneDateToStr(timeZone);
        System.out.println(date);
    }
}

package org.nft.common.pay.way.wxpay;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import org.nft.common.pay.core.NftPayHttpResponse;
import org.nft.common.pay.core.enums.AuthTypeEnum;
import org.nft.common.pay.core.enums.PayModel;
import org.nft.common.pay.core.enums.RequestMethodEnum;
import org.nft.common.pay.core.enums.SignType;
import org.nft.common.pay.core.kit.HttpKit;
import org.nft.common.pay.core.kit.PayKit;
import org.nft.common.pay.core.kit.WxPayKit;
import org.nft.common.pay.way.wxpay.enums.v2.*;
import org.nft.common.pay.way.wxpay.enums.xpay.XPayApiEnum;
import org.nft.common.pay.way.wxpay.enums.WxApiEnum;
import org.nft.common.pay.way.wxpay.enums.WxDomain;
import org.nft.common.pay.way.wxpay.enums.WxDomainEnum;

import java.io.File;
import java.io.InputStream;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付相关接口
 * @author dori
 */
public class WxPayApi {

    /**
     * 获取接口请求的 URL
     * @param wxApiEnum {@link WxApiEnum} 支付 API 接口枚举
     * @return {@link String} 返回完整的接口请求URL
     */
    public static String getReqUrl(WxApiEnum wxApiEnum) {
        return getReqUrl(wxApiEnum, null, false);
    }

    /**
     * 获取接口请求的 URL
     * @param wxApiEnum {@link WxApiEnum} 支付 API 接口枚举
     * @param isSandBox 是否是沙箱环境
     * @return {@link String} 返回完整的接口请求URL
     */
    public static String getReqUrl(WxApiEnum wxApiEnum, boolean isSandBox) {
        return getReqUrl(wxApiEnum, null, isSandBox);
    }

    /**
     * 获取接口请求的 URL
     * @param wxApiEnum {@link WxApiEnum} 支付 API 接口枚举
     * @param wxDomain  {@link WxDomain} 支付 API 接口域名枚举
     * @param isSandBox 是否是沙箱环境
     * @return {@link String} 返回完整的接口请求URL
     */
    public static String getReqUrl(WxApiEnum wxApiEnum, WxDomain wxDomain, boolean isSandBox) {
        if (wxDomain == null) {
            wxDomain = WxDomainEnum.CHINA;
        }
        return wxDomain.getDomain()
            .concat(isSandBox ? PayApiEnum.API_V2_SANDBOX.getUrl() : "")
            .concat(wxApiEnum.getUrl());
    }

    /**
     * 发起请求
     * @param apiUrl 接口 URL
     *               通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *               或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params 接口请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String execution(String apiUrl, Map<String, String> params) {
        return doPost(apiUrl, params);
    }

    /**
     * 发起请求
     * @param apiUrl 接口 URL
     *               通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *               或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params 接口请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String executionByGet(String apiUrl, Map<String, Object> params) {
        return doGet(apiUrl, params);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String execution(String apiUrl, Map<String, String> params, String certPath, String certPass) {
        return doPostSsl(apiUrl, params, certPath, certPass);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String certPass, String protocol) {
        return doPostSslByProtocol(apiUrl, params, certPath, certPass, protocol);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certPath 证书文件路径
     * @return {@link String} 请求返回的结果
     */
    public static String execution(String apiUrl, Map<String, String> params, String certPath) {
        return doPostSsl(apiUrl, params, certPath);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certPath 证书文件路径
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String protocol) {
        return doPostSslByProtocol(apiUrl, params, certPath, protocol);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certFile 证书文件输入流
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String execution(String apiUrl, Map<String, String> params, InputStream certFile, String certPass) {
        return doPostSsl(apiUrl, params, certFile, certPass);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certFile 证书文件输入流
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String executionByProtocol(String apiUrl, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return doPostSslByProtocol(apiUrl, params, certFile, certPass, protocol);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certFile 证书文件输入流
     * @return {@link String} 请求返回的结果
     */
    public static String execution(String apiUrl, Map<String, String> params, InputStream certFile) {
        return doPostSsl(apiUrl, params, certFile);
    }

    /**
     * 发起请求
     * @param apiUrl   接口 URL
     *                 通过 {@link WxPayApi#getReqUrl(WxApiEnum)}
     *                 或者 {@link WxPayApi#getReqUrl(WxApiEnum, WxDomain, boolean)} 来获取
     * @param params   接口请求参数
     * @param certFile 证书文件输入流
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String executionByProtocol(String apiUrl, Map<String, String> params, InputStream certFile, String protocol) {
        return doPostSslByProtocol(apiUrl, params, certFile, protocol);
    }

    public static String execution(String apiUrl, Map<String, String> params,
                                   String certPath, String certPass, String filePath) {
        return doUploadSsl(apiUrl, params, certPath, certPass, filePath);
    }

    public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String certPass, String filePath, String protocol) {
        return doUploadSslByProtocol(apiUrl, params, certPath, certPass, filePath, protocol);
    }


    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号,接口中包含敏感信息时必传
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @param nonceStr     随机字符库
     * @param timestamp    时间戳
     * @param authType     认证类型
     * @param file         文件
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                        String mchId, String serialNo, String platSerialNo, String keyPath,
                                        String body, String nonceStr, long timestamp, String authType,
                                        File file) throws Exception {
        // 构建 Authorization
        String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo,
            keyPath, body, nonceStr, timestamp, authType);

        if (StrUtil.isEmpty(platSerialNo)) {
            platSerialNo = serialNo;
        }

        if (method == RequestMethodEnum.GET) {
            return get(urlPrefix.concat(urlSuffix), authorization, platSerialNo, null);
        } else if (method == RequestMethodEnum.POST) {
            return post(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.DELETE) {
            return delete(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.UPLOAD) {
            return upload(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body, file);
        } else if (method == RequestMethodEnum.PATCH) {
            return patch(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.PUT) {
            return put(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        }
        return null;
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号,接口中包含敏感信息时必传
     * @param privateKey   商户私钥
     * @param body         接口请求参数
     * @param nonceStr     随机字符库
     * @param timestamp    时间戳
     * @param authType     认证类型
     * @param file         文件
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                        String mchId, String serialNo, String platSerialNo, PrivateKey privateKey,
                                        String body, String nonceStr, long timestamp, String authType,
                                        File file) throws Exception {
        // 构建 Authorization
        String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo,
            privateKey, body, nonceStr, timestamp, authType);

        if (StrUtil.isEmpty(platSerialNo)) {
            platSerialNo = serialNo;
        }

        if (method == RequestMethodEnum.GET) {
            return get(urlPrefix.concat(urlSuffix), authorization, platSerialNo, null);
        } else if (method == RequestMethodEnum.POST) {
            return post(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.DELETE) {
            return delete(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.UPLOAD) {
            return upload(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body, file);
        } else if (method == RequestMethodEnum.PATCH) {
            return patch(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        } else if (method == RequestMethodEnum.PUT) {
            return put(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
        }
        return null;
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @param authType     认证类型
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId,
                                        String serialNo, String platSerialNo, String keyPath, String body, String authType) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String nonceStr = WxPayKit.generateStr();
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, null);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId,
                                        String serialNo, String platSerialNo, String keyPath, String body) throws Exception {
        String authType = AuthTypeEnum.RSA.getCode();
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, authType);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param privateKey   商户私钥
     * @param body         接口请求参数
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId,
                                        String serialNo, String platSerialNo, PrivateKey privateKey, String body) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String authType = AuthTypeEnum.RSA.getCode();
        String nonceStr = WxPayKit.generateStr();
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, null);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param params       Get 接口请求参数
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                        String mchId, String serialNo, String platSerialNo, String keyPath,
                                        Map<String, String> params) throws Exception {
        String authType = AuthTypeEnum.RSA.getCode();
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, params, authType);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param params       Get 接口请求参数
     * @param authType     {@link AuthTypeEnum} 授权类型
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                        String mchId, String serialNo, String platSerialNo, String keyPath,
                                        Map<String, String> params, String authType) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String nonceStr = WxPayKit.generateStr();
        if (null != params && !params.keySet().isEmpty()) {
            urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true));
        }
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, "", nonceStr, timestamp, authType, null);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param privateKey   商户私钥
     * @param params       Get 接口请求参数
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                        String mchId, String serialNo, String platSerialNo, PrivateKey privateKey,
                                        Map<String, String> params) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String authType = AuthTypeEnum.RSA.getCode();
        String nonceStr = WxPayKit.generateStr();
        if (null != params && !params.keySet().isEmpty()) {
            urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true));
        }
        return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, "", nonceStr, timestamp, authType, null);
    }

    /**
     * V3 接口统一执行入口
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @param file         文件
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, String keyPath, String body, File file) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String authType = AuthTypeEnum.RSA.getCode();
        String nonceStr = WxPayKit.generateStr();
        return v3(RequestMethodEnum.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, file);
    }

    /**
     * V3 接口统一执行入口
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param privateKey   商户私钥
     * @param body         接口请求参数
     * @param file         文件
     * @return {@link NftPayHttpResponse} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    public static NftPayHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo,
                                        String platSerialNo, PrivateKey privateKey, String body, File file) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String authType = AuthTypeEnum.RSA.getCode();
        String nonceStr = WxPayKit.generateStr();
        return v3(RequestMethodEnum.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, file);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号,接口中包含敏感信息时必传
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @param nonceStr     随机字符库
     * @param timestamp    时间戳
     * @param authType     认证类型
     * @param file         文件
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Execution(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                                  String mchId, String serialNo, String platSerialNo, String keyPath,
                                                  String body, String nonceStr, long timestamp, String authType,
                                                  File file) throws Exception {
        NftPayHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, file);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param method    {@link RequestMethodEnum} 请求方法
     * @param urlPrefix 可通过 {@link WxDomain}来获取
     * @param urlSuffix 可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId     商户Id
     * @param serialNo  商户 API 证书序列号
     * @param keyPath   apiclient_key.pem 证书路径
     * @param body      接口请求参数
     * @return {@link Map} 请求返回的结果
     * @throws Exception 异常信息
     */
    @Deprecated
    public static Map<String, Object> v3Execution(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId,
                                                  String serialNo, String keyPath, String body) throws Exception {
        NftPayHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, body);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Execution(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId,
                                                  String serialNo, String platSerialNo, String keyPath, String body) throws Exception {
        NftPayHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param method       {@link RequestMethodEnum} 请求方法
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param params       Get 接口请求参数
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Execution(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                                  String mchId, String serialNo, String platSerialNo, String keyPath,
                                                  Map<String, String> params) throws Exception {
        NftPayHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, params);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param method    {@link RequestMethodEnum} 请求方法
     * @param urlPrefix 可通过 {@link WxDomain}来获取
     * @param urlSuffix 可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId     商户Id
     * @param serialNo  商户 API 证书序列号
     * @param keyPath   apiclient_key.pem 证书路径
     * @param params    Get 接口请求参数
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Execution(RequestMethodEnum method, String urlPrefix, String urlSuffix,
                                                  String mchId, String serialNo, String keyPath,
                                                  Map<String, String> params) throws Exception {
        NftPayHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, params);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param urlPrefix    可通过 {@link WxDomain}来获取
     * @param urlSuffix    可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId        商户Id
     * @param serialNo     商户 API 证书序列号
     * @param platSerialNo 平台序列号
     * @param keyPath      apiclient_key.pem 证书路径
     * @param body         接口请求参数
     * @param file         文件
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Upload(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, String keyPath, String body, File file) throws Exception {
        NftPayHttpResponse response = v3(urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, file);
        return buildResMap(response);
    }

    /**
     * V3 接口统一执行入口
     * @param urlPrefix 可通过 {@link WxDomain}来获取
     * @param urlSuffix 可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接
     * @param mchId     商户Id
     * @param serialNo  商户 API 证书序列号
     * @param keyPath   apiclient_key.pem 证书路径
     * @param body      接口请求参数
     * @param file      文件
     * @return {@link Map} 请求返回的结果
     * @throws Exception 接口执行异常
     */
    @Deprecated
    public static Map<String, Object> v3Upload(String urlPrefix, String urlSuffix, String mchId, String serialNo, String keyPath, String body, File file) throws Exception {
        return v3Upload(urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, body, file);
    }

    /**
     * 获取验签秘钥API
     * @param mchId      商户号
     * @param partnerKey API 密钥
     * @param signType   签名方式
     * @return {@link String} 请求返回的结果
     */
    public static String getSignKey(String mchId, String partnerKey, SignType signType) {
        Map<String, String> map = new HashMap<>(3);
        String nonceStr = WxPayKit.generateStr();
        map.put("mch_id", mchId);
        map.put("nonce_str", nonceStr);
        map.put("sign", WxPayKit.createSign(map, partnerKey, signType));
        return execution(getReqUrl(PayApiEnum.GET_SIGN_KEY), map);
    }

    /**
     * 统一下单
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String pushOrder(Map<String, String> params) {
        return pushOrder(false, null, params);
    }

    /**
     * 统一下单
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String pushOrder(boolean isSandbox, Map<String, String> params) {
        return pushOrder(isSandbox, null, params);
    }

    /**
     * 统一下单
     * @param isSandbox 是否是沙盒环境
     * @param wxDomain  {@link WxDomain} 支付 API 接口域名枚举
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String pushOrder(boolean isSandbox, WxDomain wxDomain, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.UNIFIED_ORDER, wxDomain, isSandbox), params);
    }

    /**
     * 订单查询
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String orderQuery(Map<String, String> params) {
        return orderQuery(false, null, params);
    }

    /**
     * 订单查询
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String orderQuery(boolean isSandbox, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.ORDER_QUERY, null, isSandbox), params);
    }

    /**
     * 订单查询
     * @param isSandbox 是否是沙盒环境
     * @param wxDomain  {@link WxDomain} 支付 API 接口域名枚举
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String orderQuery(boolean isSandbox, WxDomain wxDomain, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.ORDER_QUERY, wxDomain, isSandbox), params);
    }

    /**
     * 关闭订单
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String closeOrder(Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.CLOSE_ORDER), params);
    }

    /**
     * 撤销订单
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String orderReverse(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(PayApiEnum.REVERSE), params, certPath, certPass);
    }

    /**
     * 撤销订单
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String orderReverse(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(PayApiEnum.REVERSE), params, certFile, certPass);
    }

    /**
     * 申请退款
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @param certPath  证书文件路径
     * @param certPass  证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String orderRefund(boolean isSandbox, Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(PayApiEnum.REFUND, null, isSandbox), params, certPath, certPass);
    }

    /**
     * 申请退款
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @param certPath  证书文件路径
     * @param certPass  证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String orderRefundByProtocol(boolean isSandbox, Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(PayApiEnum.REFUND, null, isSandbox), params, certPath, certPass, protocol);
    }

    /**
     * 申请退款
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @param certFile  证书文件的 InputStream
     * @param certPass  证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String orderRefund(boolean isSandbox, Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(PayApiEnum.REFUND, null, isSandbox), params, certFile, certPass);
    }

    /**
     * 申请退款
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @param certFile  证书文件的 InputStream
     * @param certPass  证书密码
     * @param protocol  协议
     * @return {@link String} 请求返回的结果
     */
    public static String orderRefundByProtocol(boolean isSandbox, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(PayApiEnum.REFUND, null, isSandbox), params, certFile, certPass, protocol);
    }

    /**
     * 查询退款
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String orderRefundQuery(boolean isSandbox, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.REFUND_QUERY, null, isSandbox), params);
    }

    /**
     * 下载对账单
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String downloadBill(boolean isSandbox, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.DOWNLOAD_BILL, null, isSandbox), params);
    }

    /**
     * 交易保障
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String orderReport(Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.REPORT, null, false), params);
    }

    /**
     * 转换短链接
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String toShortUrl(Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.SHORT_URL, null, false), params);
    }

    /**
     * 授权码查询 openId
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String authCodeToOpenid(Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.AUTH_CODE_TO_OPENID, null, false), params);
    }

    /**
     * 刷卡支付
     * @param isSandbox 是否是沙盒环境
     * @param params    请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String microPay(boolean isSandbox, Map<String, String> params) {
        return execution(getReqUrl(PayApiEnum.MICRO_PAY, null, isSandbox), params);
    }

    /**
     * 企业付款到零钱
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String transfers(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.TRANSFER, null, false), params, certPath, certPass);
    }

    /**
     * 企业付款到零钱
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String transfersByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.TRANSFER, null, false), params, certPath, certPass, protocol);
    }

    /**
     * 企业付款到零钱
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String transfers(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.TRANSFER, null, false), params, certFile, certPass);
    }

    /**
     * 企业付款到零钱
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String transfersByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.TRANSFER, null, false), params, certFile, certPass, protocol);
    }

    /**
     * 查询企业付款到零钱
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getTransferInfo(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_TRANSFER_INFO, null, false), params, certPath, certPass);
    }

    /**
     * 查询企业付款到零钱
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getTransferInfo(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_TRANSFER_INFO, null, false), params, certFile, certPass);
    }

    /**
     * 企业付款到银行
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String payBank(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.TRANSFER_BANK, null, false), params, certPath, certPass);
    }

    /**
     * 企业付款到银行
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String payBankByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.TRANSFER_BANK, null, false), params, certPath, certPass, protocol);
    }

    /**
     * 企业付款到银行
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String payBank(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.TRANSFER_BANK, null, false), params, certFile, certPass);
    }

    /**
     * 企业付款到银行
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String payBankByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.TRANSFER_BANK, null, false), params, certFile, certPass, protocol);
    }

    /**
     * 查询企业付款到银行
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryBank(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_TRANSFER_BANK_INFO, null, false), params, certPath, certPass);
    }

    /**
     * 查询企业付款到银行
     * @param params   请求参数
     * @param certFile 证书文件的  InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryBank(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_TRANSFER_BANK_INFO, null, false), params, certFile, certPass);
    }

    /**
     * 获取 RSA 加密公钥
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getPublicKey(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_PUBLIC_KEY, WxDomainEnum.FRAUD, false), params, certPath, certPass);
    }

    /**
     * 获取 RSA 加密公钥
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String getPublicKeyByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return execution(getReqUrl(TransferApiEnum.GET_PUBLIC_KEY, WxDomainEnum.FRAUD, false), params, certPath, certPass, protocol);
    }

    /**
     * 获取 RSA 加密公钥
     * @param params   请求参数
     * @param certFile 证书文件的   InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getPublicKey(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.GET_PUBLIC_KEY, WxDomainEnum.FRAUD, false), params, certFile, certPass);
    }


    /**
     * 获取 RSA 加密公钥
     * @param params   请求参数
     * @param certFile 证书文件的   InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String getPublicKeyByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.GET_PUBLIC_KEY, WxDomainEnum.FRAUD, false), params, certFile, certPass, protocol);
    }

    /**
     * 公众号纯签约
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String entrustWeb(Map<String, Object> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return executionByGet(getReqUrl(EntrustPayApiEnum.ENTRUST_WEB), params);
        } else {
            return executionByGet(getReqUrl(EntrustPayApiEnum.PARTNER_ENTRUST_WEB), params);
        }
    }


    /**
     * APP 纯签约
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String preEntrustWeb(Map<String, Object> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return executionByGet(getReqUrl(EntrustPayApiEnum.PRE_ENTRUST_WEB), params);
        } else {
            return executionByGet(getReqUrl(EntrustPayApiEnum.PARTNER_PRE_ENTRUST_WEB), params);
        }
    }


    /**
     * H5 纯签约
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String h5EntrustWeb(Map<String, Object> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return executionByGet(getReqUrl(EntrustPayApiEnum.H5_ENTRUST_WEB), params);
        } else {
            return executionByGet(getReqUrl(EntrustPayApiEnum.PARTNER_H5_ENTRUST_WEB), params);
        }
    }

    /**
     * 支付中签约
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String contractOrder(Map<String, String> params) {
        return execution(getReqUrl(EntrustPayApiEnum.PAY_CONTRACT_ORDER), params);
    }

    /**
     * 查询签约关系
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String queryContract(Map<String, String> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return execution(getReqUrl(EntrustPayApiEnum.QUERY_ENTRUST_CONTRACT), params);
        } else {
            return execution(getReqUrl(EntrustPayApiEnum.PARTNER_QUERY_ENTRUST_CONTRACT), params);
        }
    }

    /**
     * 申请扣款
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String papPayApply(Map<String, String> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return execution(getReqUrl(EntrustPayApiEnum.PAP_PAY_APPLY), params);
        } else {
            return execution(getReqUrl(EntrustPayApiEnum.PARTNER_PAP_PAY_APPLY), params);
        }
    }

    /**
     * 申请解约
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String deleteContract(Map<String, String> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return execution(getReqUrl(EntrustPayApiEnum.DELETE_ENTRUST_CONTRACT), params);
        } else {
            return execution(getReqUrl(EntrustPayApiEnum.PARTNER_DELETE_ENTRUST_CONTRACT), params);
        }
    }

    /**
     * 查询签约关系对账单
     * @param params   请求参数
     * @param payModel 商户平台模式
     * @return {@link String} 请求返回的结果
     */
    public static String contractBill(Map<String, String> params, PayModel payModel) {
        if (payModel == PayModel.BUSINESS_MODEL) {
            return execution(getReqUrl(EntrustPayApiEnum.QUERY_ENTRUST_CONTRACT), params);
        } else {
            return execution(getReqUrl(EntrustPayApiEnum.PARTNER_QUERY_ENTRUST_CONTRACT), params);
        }
    }

    /**
     * 请求单次分账
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharing(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING), params, certPath, certPass);
    }

    /**
     * 请求单次分账
     * @param params   请求参数
     * @param certFile 证书文件的  InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharing(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING), params, certFile, certPass);
    }

    /**
     * 请求多次分账
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String multiProfitSharing(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.MULTI_PROFIT_SHARING), params, certPath, certPass);
    }

    /**
     * 请求多次分账
     * @param params   请求参数
     * @param certFile 证书文件的  InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String multiProfitSharing(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.MULTI_PROFIT_SHARING), params, certFile, certPass);
    }

    /**
     * 查询分账结果
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingQuery(Map<String, String> params) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_QUERY), params);
    }

    /**
     * 添加分账接收方
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingAddReceiver(Map<String, String> params) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_ADD_RECEIVER), params);
    }

    /**
     * 删除分账接收方
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingRemoveReceiver(Map<String, String> params) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_REMOVE_RECEIVER), params);
    }

    /**
     * 完结分账
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingFinish(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_FINISH), params, certPath, certPass);
    }

    /**
     * 完结分账
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingFinish(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_FINISH), params, certFile, certPass);
    }

    /**
     * 分账回退
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingReturn(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_RETURN), params, certPath, certPass);
    }

    /**
     * 分账回退
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingReturn(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_RETURN), params, certFile, certPass);
    }

    /**
     * 分账回退结果查询
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String profitSharingReturnQuery(Map<String, String> params) {
        return execution(getReqUrl(ProfitSharingApiEnum.PROFIT_SHARING_RETURN_QUERY), params);
    }

    /**
     * 发放代金券
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendCoupon(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(CouponApiEnum.SEND_COUPON), params, certPath, certPass);
    }

    /**
     * 发放代金券
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendCoupon(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(CouponApiEnum.SEND_COUPON), params, certFile, certPass);
    }

    /**
     * 查询代金券批次
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String queryCouponStock(Map<String, String> params) {
        return execution(getReqUrl(CouponApiEnum.QUERY_COUPON_STOCK), params);
    }

    /**
     * 查询代金券信息
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String queryCouponsInfo(Map<String, String> params) {
        return execution(getReqUrl(CouponApiEnum.QUERY_COUPONS_INFO), params);
    }

    /**
     * 支付押金(人脸支付)
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String depositFacePay(Map<String, String> params) {
        return execution(getReqUrl(DepositApiEnum.FACE_PAY), params);
    }

    /**
     * 支付押金(付款码支付)
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String depositMicroPay(Map<String, String> params) {
        return execution(getReqUrl(DepositApiEnum.MICRO_PAY), params);
    }

    /**
     * 查询订单
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String depositOrderQuery(Map<String, String> params) {
        return execution(getReqUrl(DepositApiEnum.ORDER_QUERY), params);
    }

    /**
     * 撤销订单
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositReverse(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(DepositApiEnum.REVERSE), params, certPath, certPass);
    }

    /**
     * 撤销订单
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositReverse(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(DepositApiEnum.REVERSE), params, certFile, certPass);
    }

    /**
     * 消费押金
     * @param params   请求参数
     * @param certPath 证书文件的目录
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositConsume(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(DepositApiEnum.CONSUME), params, certPath, certPass);
    }

    /**
     * 消费押金
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositConsume(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(DepositApiEnum.CONSUME), params, certFile, certPass);
    }

    /**
     * 申请退款(押金)
     * @param params   请求参数
     * @param certPath 证书文件的目录
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositRefund(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(DepositApiEnum.REFUND), params, certPath, certPass);
    }

    /**
     * 申请退款(押金)
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String depositRefund(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(DepositApiEnum.REFUND), params, certFile, certPass);
    }

    /**
     * 查询退款(押金)
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String depositRefundQuery(Map<String, String> params) {
        return execution(getReqUrl(DepositApiEnum.REFUND_QUERY), params);
    }

    /**
     * 下载资金账单
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String downloadFundFlow(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(PayApiEnum.DOWNLOAD_FUND_FLOW), params, certPath, certPass);
    }

    /**
     * 下载资金账单
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String downloadFundFlow(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(PayApiEnum.DOWNLOAD_FUND_FLOW), params, certFile, certPass);
    }

    /**
     * 刷脸设备获取设备调用凭证
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String getAuthInfo(Map<String, String> params) {
        return execution(getReqUrl(FacePayApiEnum.GET_AUTH_INFO, WxDomainEnum.PAY_APP, false), params);
    }

    /**
     * 刷脸支付
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String facePay(Map<String, String> params) {
        return execution(getReqUrl(FacePayApiEnum.FACE_PAY), params);
    }

    /**
     * 查询刷脸支付订单
     * @param params 请求参数
     * @return {@link String} 请求返回的结果
     */
    public static String facePayQuery(Map<String, String> params) {
        return execution(getReqUrl(FacePayApiEnum.FACE_PAY_QUERY), params);
    }

    /**
     * 刷脸支付撤销订单
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String facePayReverse(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(FacePayApiEnum.FACE_PAY_REVERSE), params, certPath, certPass);
    }

    /**
     * 刷脸支付撤销订单
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String facePayReverse(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(FacePayApiEnum.FACE_PAY_REVERSE), params, certFile, certPass);
    }

    /**
     * 发放普通红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendRedPack(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_RED_PACK), params, certPath, certPass);
    }

    /**
     * 发放普通红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_RED_PACK), params, certPath, certPass, protocol);
    }

    /**
     * 发放普通红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendRedPack(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_RED_PACK), params, certFile, certPass);
    }

    /**
     * 发放普通红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_RED_PACK), params, certFile, certPass, protocol);
    }

    /**
     * 发放裂变红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendGroupRedPack(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_GROUP_RED_PACK), params, certPath, certPass);
    }

    /**
     * 发放裂变红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendGroupRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_GROUP_RED_PACK), params, certPath, certPass, protocol);
    }

    /**
     * 发放裂变红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendGroupRedPack(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_GROUP_RED_PACK), params, certFile, certPass);
    }

    /**
     * 发放裂变红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendGroupRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_GROUP_RED_PACK), params, certFile, certPass, protocol);
    }

    /**
     * 查询红包记录
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getHbInfo(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.GET_HB_INFO), params, certPath, certPass);
    }

    /**
     * 查询红包记录
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String getHbInfo(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.GET_HB_INFO), params, certFile, certPass);
    }

    /**
     * 小程序发放红包接口
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendMiniProgramRedPack(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_MINI_PROGRAM_HB), params, certPath, certPass);
    }

    /**
     * 小程序发放红包接口
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendMiniProgramRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_MINI_PROGRAM_HB), params, certPath, certPass, protocol);
    }

    /**
     * 小程序发放红包接口
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendMiniProgramRedPack(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_MINI_PROGRAM_HB), params, certFile, certPass);
    }

    /**
     * 小程序发放红包接口
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendMiniProgramRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_MINI_PROGRAM_HB), params, certFile, certPass, protocol);
    }

    /**
     * 发放企业红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendWorkWxRedPack(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_WORK_WX_RED_PACK), params, certPath, certPass);
    }

    /**
     * 发放企业红包
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendWorkWxRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_WORK_WX_RED_PACK), params, certPath, certPass, protocol);
    }

    /**
     * 发放企业红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String sendWorkWxRedPack(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.SEND_WORK_WX_RED_PACK), params, certFile, certPass);
    }

    /**
     * 发放企业红包
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String sendWorkWxRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.SEND_WORK_WX_RED_PACK), params, certFile, certPass, protocol);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryWorkWxRedPack(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.QUERY_WORK_WX_RED_PACK), params, certPath, certPass);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String queryWorkWxRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.QUERY_WORK_WX_RED_PACK), params, certPath, certPass, protocol);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryWorkWxRedPack(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(RedPackApiEnum.QUERY_WORK_WX_RED_PACK), params, certFile, certPass);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String queryWorkWxRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(RedPackApiEnum.QUERY_WORK_WX_RED_PACK), params, certFile, certPass, protocol);
    }

    /**
     * 向员工付款
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String trans2pocket(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.PAY_WWS_TRANS_2_POCKET), params, certPath, certPass);
    }

    /**
     * 向员工付款
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String trans2pocketByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.PAY_WWS_TRANS_2_POCKET), params, certPath, certPass, protocol);
    }

    /**
     * 向员工付款
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String trans2pocket(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.PAY_WWS_TRANS_2_POCKET), params, certFile, certPass);
    }

    /**
     * 向员工付款
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String trans2pocketByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.PAY_WWS_TRANS_2_POCKET), params, certFile, certPass, protocol);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryTrans2pocket(Map<String, String> params, String certPath, String certPass) {
        return execution(getReqUrl(TransferApiEnum.QUERY_WWS_TRANS_2_POCKET), params, certPath, certPass);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certPath 证书文件路径
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String queryTrans2pocketByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.QUERY_WWS_TRANS_2_POCKET), params, certPath, certPass, protocol);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @return {@link String} 请求返回的结果
     */
    public static String queryTrans2pocket(Map<String, String> params, InputStream certFile, String certPass) {
        return execution(getReqUrl(TransferApiEnum.QUERY_WWS_TRANS_2_POCKET), params, certFile, certPass);
    }

    /**
     * 查询向员工付款记录
     * @param params   请求参数
     * @param certFile 证书文件的 InputStream
     * @param certPass 证书密码
     * @param protocol 协议
     * @return {@link String} 请求返回的结果
     */
    public static String queryTrans2pocket(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return executionByProtocol(getReqUrl(TransferApiEnum.QUERY_WWS_TRANS_2_POCKET), params, certFile, certPass, protocol);
    }

    /**
     * 小程序虚拟支付接口
     * @param apiEnum     接口枚举 {@link XPayApiEnum}
     * @param appKey      应用秘钥
     * @param accessToken 小程序Token
     * @param postBody    POST的数据包体
     * @return {@link NftPayHttpResponse} 请求返回的结果
     */
    public static NftPayHttpResponse xPay(WxApiEnum apiEnum, String appKey, String accessToken, String postBody) {
        String url = getReqUrl(apiEnum);
        String needSignMsg = url.concat("&").concat(postBody);
        String paySig = PayKit.hmacSha256(needSignMsg, appKey);
        url = url.concat("?access_token=").concat(accessToken).concat("&pay_sig=").concat(paySig);
        return post(url, postBody, null);
    }

    /**
     * @param url    请求url
     * @param params 请求参数
     * @return {@link String}    请求返回的结果
     */
    public static String doGet(String url, Map<String, Object> params) {
        return HttpKit.getDelegate().get(url, params);
    }

    /**
     * get 请求
     * @param url     请求url
     * @param params  请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse get(String url, Map<String, Object> params, Map<String, String> headers) {
        return HttpKit.getDelegate().get(url, params, headers);
    }

    /**
     * get 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param params        请求参数
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse get(String url, String authorization, String serialNumber, Map<String, Object> params) {
        return get(url, params, getHeaders(authorization, serialNumber));
    }

    /**
     * post 请求
     * @param url     请求url
     * @param data    请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse post(String url, String data, Map<String, String> headers) {
        return HttpKit.getDelegate().post(url, data, headers);
    }

    /**
     * post 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse post(String url, String authorization, String serialNumber, String data) {
        return post(url, data, getHeaders(authorization, serialNumber));
    }

    /**
     * delete 请求
     * @param url     请求url
     * @param data    请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse delete(String url, String data, Map<String, String> headers) {
        return HttpKit.getDelegate().delete(url, data, headers);
    }

    /**
     * delete 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse delete(String url, String authorization, String serialNumber, String data) {
        return delete(url, data, getHeaders(authorization, serialNumber));
    }

    /**
     * upload 请求
     * @param url     请求url
     * @param params  请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse upload(String url, Map<String, Object> params, Map<String, String> headers) {
        return HttpKit.getDelegate().post(url, params, headers);
    }

    /**
     * upload 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @param file          上传文件
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse upload(String url, String authorization, String serialNumber, String data, File file) {
        Map<String, Object> paramMap = new HashMap<>(2);
        paramMap.put("file", file);
        paramMap.put("meta", data);
        return upload(url, paramMap, getUploadHeaders(authorization, serialNumber));
    }

    /**
     * patch 请求
     * @param url     请求url
     * @param data    请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse patch(String url, String data, Map<String, String> headers) {
        return HttpKit.getDelegate().patch(url, data, headers);
    }


    /**
     * patch 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse patch(String url, String authorization, String serialNumber, String data) {
        return patch(url, data, getHeaders(authorization, serialNumber));
    }


    /**
     * put 请求
     * @param url     请求url
     * @param data    请求参数
     * @param headers 请求头
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse put(String url, String data, Map<String, String> headers) {
        return HttpKit.getDelegate().put(url, data, headers);
    }

    /**
     * put 请求
     * @param url           请求url
     * @param authorization 授权信息
     * @param serialNumber  公钥证书序列号
     * @param data          请求参数
     * @return {@link NftPayHttpResponse}    请求返回的结果
     */
    public static NftPayHttpResponse put(String url, String authorization, String serialNumber, String data) {
        return put(url, data, getHeaders(authorization, serialNumber));
    }

    public static String doPost(String url, Map<String, String> params) {
        return HttpKit.getDelegate().post(url, WxPayKit.toXml(params));
    }

    public static String doPostSsl(String url, Map<String, String> params, String certPath, String certPass) {
        return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certPath, certPass);
    }

    public static String doPostSslByProtocol(String url, Map<String, String> params, String certPath, String certPass, String protocol) {
        return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certPath, certPass, protocol);
    }

    public static String doPostSsl(String url, Map<String, String> params, InputStream certFile, String certPass) {
        return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certFile, certPass);
    }

    public static String doPostSslByProtocol(String url, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
        return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certFile, certPass, protocol);
    }

    public static String doPostSsl(String url, Map<String, String> params, String certPath) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doPostSsl(url, params, certPath, certPass);
    }

    public static String doPostSslByProtocol(String url, Map<String, String> params, String certPath, String protocol) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doPostSslByProtocol(url, params, certPath, certPass, protocol);
    }

    public static String doPostSsl(String url, Map<String, String> params, InputStream certFile) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doPostSsl(url, params, certFile, certPass);
    }

    public static String doPostSslByProtocol(String url, Map<String, String> params, InputStream certFile, String protocol) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doPostSslByProtocol(url, params, certFile, certPass, protocol);
    }

    public static String doUploadSsl(String url, Map<String, String> params, String certPath, String certPass, String filePath) {
        return HttpKit.getDelegate().upload(url, WxPayKit.toXml(params), certPath, certPass, filePath);
    }

    public static String doUploadSslByProtocol(String url, Map<String, String> params, String certPath, String certPass, String filePath, String protocol) {
        return HttpKit.getDelegate().upload(url, WxPayKit.toXml(params), certPath, certPass, filePath, protocol);
    }

    public static String doUploadSsl(String url, Map<String, String> params, String certPath, String filePath) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doUploadSsl(url, params, certPath, certPass, filePath);
    }

    public static String doUploadSslByProtocol(String url, Map<String, String> params, String certPath, String filePath, String protocol) {
        if (params.isEmpty() || !params.containsKey("mch_id")) {
            throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
        }
        String certPass = params.get("mch_id");
        return doUploadSslByProtocol(url, params, certPath, certPass, filePath, protocol);
    }


    private static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version");
    private static final String VERSION = System.getProperty("java.version");

    public static Map<String, String> getBaseHeaders(String authorization) {
        String userAgent = String.format(
            "WeChatPay-NftPay-HttpClient/%s (%s) Java/%s",
            WxPayApi.class.getPackage().getImplementationVersion(),
            OS,
            VERSION == null ? "Unknown" : VERSION);

        Map<String, String> headers = new HashMap<>(5);
        headers.put("Accept", ContentType.JSON.toString());
        headers.put("Authorization", authorization);
        headers.put("User-Agent", userAgent);
        return headers;
    }

    public static Map<String, String> getHeaders(String authorization, String serialNumber) {
        Map<String, String> headers = getBaseHeaders(authorization);
        headers.put("Content-Type", ContentType.JSON.toString());
        if (StrUtil.isNotEmpty(serialNumber)) {
            headers.put("Wechatpay-Serial", serialNumber);
        }
        return headers;
    }

    public static Map<String, String> getUploadHeaders(String authorization, String serialNumber) {
        Map<String, String> headers = getBaseHeaders(authorization);
        headers.put("Content-Type", "multipart/form-data;boundary=\"boundary\"");
        if (StrUtil.isNotEmpty(serialNumber)) {
            headers.put("Wechatpay-Serial", serialNumber);
        }
        return headers;
    }

    /**
     * 构建返回参数
     * @param response {@link NftPayHttpResponse}
     * @return {@link Map}
     */
    public static Map<String, Object> buildResMap(NftPayHttpResponse response) {
        if (response == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(6);
        String timestamp = response.getHeader("Wechatpay-Timestamp");
        String nonceStr = response.getHeader("Wechatpay-Nonce");
        String serialNo = response.getHeader("Wechatpay-Serial");
        String signature = response.getHeader("Wechatpay-Signature");
        String body = response.getBody();
        int status = response.getStatus();
        map.put("timestamp", timestamp);
        map.put("nonceStr", nonceStr);
        map.put("serialNumber", serialNo);
        map.put("signature", signature);
        map.put("body", body);
        map.put("status", status);
        return map;
    }
}
package org.nft.common.pay.way.wxpay.enums;

/**
 * 微信支付可用域名枚举
 * @author dori
 */
public enum WxDomainEnum implements WxDomain {
    /**
     * 中国国内
     */
    CHINA("https://api.mch.weixin.qq.com"),
    /**
     * 中国国内(备用域名)
     */
    CHINA2("https://api2.mch.weixin.qq.com"),
    /**
     * 东南亚
     */
    HK("https://apihk.mch.weixin.qq.com"),
    /**
     * 其它
     */
    US("https://apius.mch.weixin.qq.com"),
    /**
     * 获取公钥
     */
    FRAUD("https://fraud.mch.weixin.qq.com"),
    /**
     * 活动
     */
    ACTION("https://action.weixin.qq.com"),
    /**
     * 刷脸支付
     * PAY_APP
     */
    PAY_APP("https://payapp.weixin.qq.com");


    /**
     * 域名
     */
    private final String domain;

    WxDomainEnum(String domain) {
        this.domain = domain;
    }

    @Override
    public String getDomain() {
        return domain;
    }

    @Override
    public String toString() {
        return domain;
    }
}
package org.nft.common.pay.way.wxpay.enums.v3;

import org.nft.common.pay.way.wxpay.enums.WxApiEnum;

/**
 * 微信支付 v3 接口-基础支付接口枚举
 * @author dori
 */
public enum BasePayApiEnum implements WxApiEnum {
    /**
     * JSAPI下单
     */
    JS_API_PAY("/v3/pay/transactions/jsapi", "JSAPI 下单"),

    /**
     * 服务商模式-JSAPI下单
     */
    PARTNER_JS_API_PAY("/v3/pay/partner/transactions/jsapi", "服务商模式-JSAPI下单"),

    /**
     * APP 下单
     */
    APP_PAY("/v3/pay/transactions/app", "APP 下单"),

    /**
     * 服务商模式-APP 下单
     */
    PARTNER_APP_PAY("/v3/pay/partner/transactions/app", "服务商模式-APP 下单"),

    /**
     * H5 下单
     */
    H5_PAY("/v3/pay/transactions/h5", "H5 下单"),

    /**
     * 服务商模式-H5 下单
     */
    PARTNER_H5_PAY("/v3/pay/partner/transactions/h5", "服务商模式-H5 下单"),

    /**
     * Native 下单
     */
    NATIVE_PAY("/v3/pay/transactions/native", "Native 下单"),

    /**
     * 服务商模式-Native 下单
     */
    PARTNER_NATIVE_PAY("/v3/pay/partner/transactions/native", "服务商模式-Native 下单"),

    /**
     * 合单 APP 下单
     */
    COMBINE_TRANSACTIONS_APP("/v3/combine-transactions/app", "合单 APP 下单"),

    /**
     * 合单 JSAPI 下单
     */
    COMBINE_TRANSACTIONS_JS("/v3/combine-transactions/jsapi", "合单 JSAPI 下单"),

    /**
     * 合单 H5 下单
     */
    COMBINE_TRANSACTIONS_H5("/v3/combine-transactions/h5", "合单 H5 下单"),

    /**
     * 合单 Native下单
     */
    COMBINE_TRANSACTIONS_NATIVE("/v3/combine-transactions/native", "合单 Native 下单"),

    /**
     * 合单查询订单
     */
    COMBINE_QUERY_BY_OUT_TRADE_NO("/v3/combine-transactions/out-trade-no/%s", "合单查询订单"),

    /**
     * 合单关闭订单
     */
    COMBINE_CLOSE_BY_OUT_TRADE_NO("/v3/combine-transactions/out-trade-no/%s/close", "合单关闭订单"),

    /**
     * 合单支付-申请退款
     */
    DOMESTIC_REFUND("/v3/refund/domestic/refunds", "合单支付-申请退款"),

    /**
     * 合单支付-查询单笔退款
     */
    DOMESTIC_REFUND_QUERY("/v3/refund/domestic/refunds/%s", "合单支付-查询单笔退款"),

    /**
     * 微信支付订单号查询
     */
    ORDER_QUERY_BY_TRANSACTION_ID("/v3/pay/transactions/id/%s", "微信支付订单号查询"),

    /**
     * 服务商模式-微信支付订单号查询
     */
    PARTNER_ORDER_QUERY_BY_TRANSACTION_ID("/v3/pay/partner/transactions/id/%s", "服务商模式-微信支付订单号查询"),

    /**
     * 商户订单号查询
     */
    ORDER_QUERY_BY_OUT_TRADE_NO("/v3/pay/transactions/out-trade-no/%s", "商户订单号查询"),

    /**
     * 服务商模式-商户订单号查询
     */
    PARTNER_ORDER_QUERY_BY_OUT_TRADE_NO("/v3/pay/partner/transactions/out-trade-no/%s", "服务商模式-商户订单号查询"),

    /**
     * 关闭订单
     */
    CLOSE_ORDER_BY_OUT_TRADE_NO("/v3/pay/transactions/out-trade-no/%s/close", "关闭订单"),

    /**
     * 服务商模式-关闭订单
     */
    PARTNER_CLOSE_ORDER_BY_OUT_TRADE_NO("/v3/pay/partner/transactions/out-trade-no/%s/close", "服务商模式-关闭订单"),

    /**
     * 申请退款
     */
    REFUND("/v3/refund/domestic/refunds", "申请退款"),

    /**
     * 查询单笔退款
     */
    REFUND_QUERY_BY_OUT_REFUND_NO("/v3/refund/domestic/refunds/%s", "查询单笔退款"),


    /**
     * 申请交易账单
     */
    TRADE_BILL("/v3/bill/tradebill", "申请交易账单"),

    /**
     * 申请资金账单
     */
    FUND_FLOW_BILL("/v3/bill/fundflowbill", "申请资金账单"),

    /**
     * 申请单个子商户资金账单
     */
    SUB_MERCHANT_FUND_FLOW_BILL("/v3/bill/sub-merchant-fundflowbill", "申请单个子商户资金账单"),

    /**
     * 下载账单
     */
    BILL_DOWNLOAD("/v3/billdownload/file", "下载账单"),
    ;

    /**
     * 接口URL
     */
    private final String url;

    /**
     * 接口描述
     */
    private final String desc;

    BasePayApiEnum(String url, String desc) {
        this.url = url;
        this.desc = desc;
    }

    @Override
    public String getUrl() {
        return url;
    }

    @Override
    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return url;
    }
}
package org.nft.common.pay.way.wxpay.model.v3;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * V3 统一下单-订单金额
 * @author dori
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class Amount {
    /**
     * 总金额
     */
    private int total;
    /**
     * 货币类型
     */
    private String currency;
}
package org.nft.common.pay.way.wxpay.model.v3;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * V3 统一下单 Model
 * @author dori
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class UnifiedOrderModel {
    /**
     * 公众号ID
     */
    private String appid;
    /**
     * 服务商公众号ID
     */
    private String sp_appid;
    /**
     * 直连商户号
     */
    private String mchid;
    /**
     * 服务商户号
     */
    private String sp_mchid;
    /**
     * 子商户公众号ID
     */
    private String sub_appid;
    /**
     * 子商户号
     */
    private String sub_mchid;
    /**
     * 商品描述
     */
    private String description;
    /**
     * 商户订单号
     */
    private String out_trade_no;
    /**
     * 交易结束时间
     */
    private String time_expire;
    /**
     * 附加数据
     */
    private String attach;
    /**
     * 通知地址
     */
    private String notify_url;
    /**
     * 订单优惠标记
     */
    private String goods_tag;
    /**
     * 结算信息
     */
    private SettleInfo settle_info;
    /**
     * 订单金额
     */
    private Amount amount;
    /**
     * 支付者
     */
    private Payer payer;
    /**
     * 优惠功能
     */
    private Detail detail;
    /**
     * 场景信息
     */
    private SceneInfo scene_info;
}


  • 17
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信支付v3版的支付回调是基于异步通知机制进行的,需要在接收支付结果的服务器端编写Java代码来处理回调请求。以下是一个简单的示例代码: ```java import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/pay") public class WechatPayCallbackController { private final WxPayService wxPayService; public WechatPayCallbackController() { // 初始化微信支付服务 wxPayService = new WxPayServiceImpl(); wxPayService.setKey("your-wxpay-api-key"); // 设置支付密钥 } @PostMapping("/callback") public String payCallback(@RequestBody String notifyData) { try { // 解析支付通知 wxPayService.parseNotifyResult(notifyData); // 处理支付成功逻辑,例如更新订单状态等 // 返回成功响应给微信支付平台 return WxPayNotifyResponse.success("处理成功"); } catch (WxPayException e) { // 处理支付失败逻辑,例如记录错误日志等 // 返回失败响应给微信支付平台 return WxPayNotifyResponse.fail(e.getMessage()); } } } ``` 上述代码是一个使用Spring Boot框架的控制器类,负责处理微信支付的回调请求。在回调方法`payCallback`中,通过`wxPayService.parseNotifyResult`方法解析支付通知的XML数据,并在处理成功或失败后返回相应的结果。 需要注意的是,为了保证安全性,建议在实际开发中将`your-wxpay-api-key`替换为实际的支付密钥。 另外,此代码仅作为示例,实际情况可能需要结合具体的业务逻辑进行扩展和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值