# Technical Documentation: go-pay/gopay

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/go-pay/gopay)

### Overview (`README.md`)

<div align=center><img width="240" height="240" alt="Logo was Loading Faild!" src="logo.png"/></div>

# GoPay

### 微信、支付宝、抖音、QQ、通联支付、拉卡拉、PayPal、扫呗、Apple支付的 Golang 版本SDK

[](https://github.com/iGoogle-ink)
[](https://github.com/go-pay/gopay/fork)

[](https://golang.google.cn)
[](https://pkg.go.dev/github.com/go-pay/gopay)
[](https://github.com/go-pay/gopay/actions/workflows/go.yml)
[](https://github.com/go-pay/gopay/releases)
[](https://www.apache.org/licenses/LICENSE-2.0)
[](https://goreportcard.com/report/github.com/go-pay/gopay)

---

# 一、安装

```bash
go get github.com/go-pay/gopay
```

#### 查看 GoPay 版本

  [版本更新记录](https://github.com/go-pay/gopay/blob/main/release_note.md)

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/xlog"
)

func main() {
    xlog.Info("GoPay Version: ", gopay.Version)
}
```

---

<br>

# 二、文档目录

> ### 点击查看不同支付方式的使用文档。方便的话，请留下您认可的小星星，十分感谢！

* #### [支付宝支付（V3版）](https://github.com/go-pay/gopay/blob/main/doc/alipay_v3.md)
* #### [支付宝支付](https://github.com/go-pay/gopay/blob/main/doc/alipay.md)
* #### [微信支付（V3版）](https://github.com/go-pay/gopay/blob/main/doc/wechat_v3.md)
  * 微信商家转账产品升级，目前已支持新版商家转账接口
* #### [微信支付（V2版，不推荐）](https://github.com/go-pay/gopay/blob/main/doc/wechat_v2.md)
* #### [抖音支付](https://github.com/go-pay/gopay/blob/main/doc/douyin.md)
* #### [招商银行聚合支付](https://github.com/go-pay/gopay/blob/main/doc/cmbpay.md)
* #### [QQ支付](https://github.com/go-pay/gopay/blob/main/doc/qq.md)
* #### [通联支付](https://github.com/go-pay/gopay/blob/main/doc/allinpay.md)
* #### [拉卡拉支付](https://github.com/go-pay/gopay/blob/main/doc/lakala.md)
* #### [Paypal支付](https://github.com/go-pay/gopay/blob/main/doc/paypal.md)
* #### [Apple支付校验](https://github.com/go-pay/gopay/blob/main/doc/apple.md)
* #### [扫呗支付](https://github.com/go-pay/gopay/blob/main/doc/saobei.md)

---

<br>

# 三、其他说明

* **【v1.5.119 起 TLS 证书校验默认开启】** 此前 `pkg/xhttp.NewClient()` 默认 `tls.Config{InsecureSkipVerify: true}`，存在中间人攻击风险（CWE-295），自 v1.5.119 起改为使用 Go 标准库默认安全配置。
  * **不影响生产环境**：所有支付平台官方域名证书均受信任。
  * **沙箱 / 自签证书场景需手动恢复**：New Client 后调用 `SetHttpClient` 注入跳过校验的 xhttp.Client：
    ```go
    import (
        "crypto/tls"
        "github.com/go-pay/gopay/pkg/xhttp"
    )

    hc := xhttp.NewClient().SetHttpTLSConfig(&tls.Config{InsecureSkipVerify: true})
    client.SetHttpClient(hc) // wechat / alipay / douyin / paypal / qq / allinpay / lakala / saobei 均支持
    ```

* 如需自定义Log输出，New Client 后，调用 `client.SetLogger()` 方法设置自定义Logger，自定义Logger实现 `xlog.XLogger` interface即可。

* 各支付方式接入，请仔细查看 `xxx_test.go` 使用方式
    * `gopay/wechat/v3/client_test.go`
    * `gopay/alipay/v3/client_test.go`
    * `gopay/alipay/client_test.go`
    * `gopay/examples/douyin/douyin.go`（示例代码）
    * `gopay/qq/client_test.go`
    * `gopay/allinpay/client_test.go`
    * `gopay/lakala/client_test.go`
    * `gopay/paypal/client_test.go`
    * `gopay/apple/verify_test.go`
    * 或 examples
* 接入gopay示例项目(可参考接入使用方式)：[gopay-platform](https://github.com/go-pay/gopay-platform)
* 有问题请加微信群 或 关注抖音账号，加入首页粉丝群拉微信群。在此，非常感谢提出宝贵意见和反馈问题的同志们！
* 开发过程中，请尽量使用正式环境，1分钱测试法！
* 有偿承接技术咨询、开发，如需要加微信联系。

<br>

---

## 赞赏多少是您的心意，感谢支持！

微信赞赏码： <img width="200" height="200" src=".github/zanshang.png"/>
&nbsp;&nbsp;&nbsp;&nbsp;
支付宝赞助码： <img width="200" height="200" src=".github/zanshang_zfb.png"/>

---

## 问题沟通（非必要不用加微信）
> 微信: **[85411418](.github/wechat_jerry.png)**（加个人微信备注清楚来意，谢谢）。

[//]: # (关注抖音：)

[//]: # (<img width="240" height="240" src=".github/douyin_jerry.png"/>)

[//]: # (&nbsp;&nbsp;&nbsp;&nbsp;QQ群：)

[//]: # (<img width="240" height="240" src=".github/wx_gopay.png"/>)

---

<br>

## 鸣谢

> [GoLand](https://www.jetbrains.com/go/?from=gopay) A Go IDE with extended support for JavaScript, TypeScript, and Databases。

特别感谢 [JetBrains](https://www.jetbrains.com/?from=gopay) 为开源项目提供免费的 [GoLand](https://www.jetbrains.com/go/?from=gopay) 等 IDE 的授权  
<br>
[<img src=".github/jetbrains.png" width="300"/>](https://www.jetbrains.com/?from=gopay)

> Copyright © 2025 JetBrains s.r.o. JetBrains and the JetBrains logo are trademarks of JetBrains s.r.o.

---

### Overview (`.claude/skills/README.md`)

# GoPay 项目 Skills

本目录包含 GoPay 项目专用的 Claude Code skills。

## 可用 Skills

### add-payment-interface

为 GoPay 项目添加新支付接口的标准化工作流程。

**功能：**
- 分析官方接口文档
- 实现接口代码（常量、模型、方法）
- 更新项目文档
- 更新版本记录
- 准备 git 提交

**适用场景：**
- 添加微信支付新接口
- 添加支付宝新接口
- 添加其他支付平台接口

## 安装 Skills

Skills 需要安装到全局 `~/.claude/skills/` 目录才能被 Claude Code 识别。

### 方法一：使用脚本安装（推荐）

```bash
# 在项目根目录执行
.claude/skills/install.sh
```

### 方法二：手动安装

```bash
# 复制 skill 到全局目录
cp -r .claude/skills/add-payment-interface ~/.claude/skills/

# 重新加载 skills
# 在 Claude Code 中执行: /skills reload
```

## 使用 Skills

安装完成后，在 Claude Code 中：

1. 查看所有可用 skills：
   ```
   /skills
   ```

2. 使用 skill：
   - 直接告诉 Claude："使用 add-payment-interface skill 添加 xxx 接口"
   - 或者提供接口文档链接，Claude 会自动识别并使用相应的 skill

## 维护说明

### 更新 Skill

如果需要修改 skill：

1. 编辑项目中的 skill 文件：`.claude/skills/add-payment-interface/SKILL.md`
2. 重新安装到全局目录：
   ```bash
   cp -r .claude/skills/add-payment-interface ~/.claude/skills/
   ```
3. 在 Claude Code 中重新加载：`/skills reload`

### 换电脑后的设置

1. Clone 项目仓库
2. 运行安装脚本：
   ```bash
   .claude/skills/install.sh
   ```
3. 在 Claude Code 中验证：`/skills`

## 目录结构

```
.claude/
└── skills/
    ├── README.md                          # 本文件
    ├── install.sh                         # 安装脚本
    └── add-payment-interface/
        └── SKILL.md                       # Skill 定义文件
```

## 注意事项

- Skills 必须安装到全局目录 `~/.claude/skills/` 才能生效
- 项目中的 `.claude/skills/` 目录仅用于版本控制和分发
- 修改 skill 后需要重新安装并重新加载
- 建议将 `.claude/skills/` 目录提交到 git，方便团队协作

---

### Doc Alipay (`doc/alipay.md`)

## 支付宝

> #### [开发文档（V3版）](https://opendocs.alipay.com/open-v3) 支付宝v3版本已支持，接口持续完善中。

> #### 因支付宝接口太多，如没实现的接口，还请开发者自行调用 `client.PostAliPayAPISelfV2()`方法实现！请参考 `client_test.go` 内的 `TestClient_PostAliPayAPISelfV2()` 方法

> #### 希望有时间的伙伴儿Fork完后，补充并提交Pull Request，一起完善支付宝各个类别下的接口到相应的go文件中

- 已实现API列表附录：[API 列表附录](https://github.com/go-pay/gopay/blob/main/doc/alipay.md#%E9%99%84%E5%BD%95)

- 支付宝官方文档：[官方文档](https://openhome.alipay.com/docCenter/docCenter.htm)

- 技术接入指南：[技术接入指南](https://opendocs.alipay.com/common/02mse2)

- 技术支持&案例FAQ：[技术支持&案例FAQ](https://opendocs.alipay.com/support/01rarm)

- 支付宝RSA秘钥生成文档：[生成RSA密钥](https://opendocs.alipay.com/common/02kipl) （推荐使用 RSA2）

- 沙箱环境(新) 使用说明：[新版沙箱文档](https://opendocs.alipay.com/common/02kkv7)

---

### 1、初始化支付宝客户端并做配置

> 具体API使用介绍，请参考 `gopay/alipay/client_test.go`

```go
import (
    "github.com/go-pay/gopay/alipay"
    "github.com/go-pay/xlog"
)

// 初始化支付宝客户端
// appid：应用ID
// privateKey：应用私钥，支持PKCS1和PKCS8
// isProd：是否是正式环境，沙箱环境请选择新版沙箱应用。
client, err := alipay.NewClient("2016091200494382", privateKey, false)
if err != nil {
    xlog.Error(err)
    return
}

// 自定义配置http请求接收返回结果body大小，默认 10MB
client.SetBodySize() // 没有特殊需求，可忽略此配置

// 设置自定义RequestId生成方法，非必须
client.SetRequestIdFunc()

// 打开Debug开关，输出日志，默认关闭
client.DebugSwitch = gopay.DebugOn

// 设置支付宝请求 公共参数
//    注意：具体设置哪些参数，根据不同的方法而不同，此处列举出所有设置参数
client.SetLocation(alipay.LocationShanghai). // 设置时区，不设置或出错均为默认服务器时间
SetCharset(alipay.UTF8).  // 设置字符编码，不设置默认 utf-8
SetSignType(alipay.RSA2). // 设置签名类型，不设置默认 RSA2
SetReturnUrl("https://www.fmm.ink").            // 设置返回URL
    SetNotifyUrl("https://www.fmm.ink").        // 设置异步通知URL
    SetAppAuthToken()                           // 设置第三方应用授权

// 设置biz_content加密KEY，设置此参数默认开启加密（目前不可用，设置后会报错）
//client.SetAESKey("1234567890123456")

// 自动同步验签（只支持证书模式）
// 传入 alipayPublicCert.crt 内容
client.AutoVerifySign([]byte("alipayPublicCert.crt bytes"))

// 公钥证书模式，需要传入证书，以下两种方式二选一
// 证书路径
err := client.SetCertSnByPath("appPublicCert.crt", "alipayRootCert.crt", "alipayPublicCert.crt")
// 证书内容
err := client.SetCertSnByContent("appPublicCert.crt bytes", "alipayRootCert bytes", "alipayPublicCert.crt bytes")
```

### 2、API 方法调用及入参

> 具体参数请根据不同接口查看：[支付宝支付API接口文档](https://opendocs.alipay.com/open/065yhr)

> 业务错误处理：当 `err != nil` 时，可通过 `alipay.IsBizError()` 捕获业务错误状态码和说明。
> 不在乎 `BizError` 的可忽略统一判错处理

> ★入参 BodyMap中，支持如下公共参数在当次请求中自定义设置：`version`、`return_url`、`notify_url`、`app_auth_token`

- 统一收单交易支付接口 - 示例

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/alipay"
)

// 初始化 BodyMap
bm := make(gopay.BodyMap)
bm.Set("subject", "条码支付").
    Set("scene", "bar_code").
    Set("auth_code", "286248566432274952").
    Set("out_trade_no", "GZ201909081743431443").
    Set("total_amount", "0.01").
    Set("timeout_express", "2m").
    Set(alipay.AppAuthToken, "i_am_app_auth_token") // 如果需要，可以设置自定义应用授权

aliRsp, err := client.TradePay(bm)
if err != nil {
    xlog.Errorf("client.TradePay(%+v),err:%+v", bm, err)
    return
}
```

### 3、同步返回参数验签Sign、异步通知参数解析和验签Sign、异步通知返回

> 异步通知请求参数需要先解析，解析出来的结构体或BodyMap再验签（此处需要注意，`http.Request.Body` 只能解析一次，如果需要解析前调试，请处理好Body复用问题）

[Gin Web框架（推荐）](https://github.com/gin-gonic/gin)

[Echo Web框架](https://github.com/labstack/echo)

> 注意：APP支付、手机网站支付、电脑网站支付 不支持同步返回验签

> 支付宝支付后的同步/异步通知验签文档：[支付结果通知](https://opendocs.alipay.com/common/02mse7)

- 同步返回验签，手动验签（如已开启自动验签，则无需手动验签操作）

```go
import (
    "github.com/go-pay/gopay/alipay"
)

aliRsp, err := client.TradePay(bm)
if err != nil {
    xlog.Error("err:", err)
    return
}

// 公钥模式验签
//    注意：APP支付，手机网站支付，电脑网站支付 不支持同步返回验签
//    aliPayPublicKey：支付宝平台获取的支付宝公钥
//    signData：待验签参数，aliRsp.SignData
//    sign：待验签sign，aliRsp.Sign
ok, err := alipay.VerifySyncSign(aliPayPublicKey, aliRsp.SignData, aliRsp.Sign)

// 公钥证书模式验签
//    aliPayPublicKeyCert：支付宝公钥证书存放路径 alipayPublicCert.crt 或文件内容[]byte
//    signData：待验签参数，aliRsp.SignData
//    sign：待验签sign，aliRsp.Sign
ok, err := alipay.VerifySyncSignWithCert(aliPayPublicKeyCert, aliRsp.SignData, aliRsp.Sign)
```

- 异步通知验签

```go
import (
    "github.com/go-pay/gopay/alipay"
)

// 解析异步通知的参数
// req：*http.Request
notifyReq, err = alipay.ParseNotifyToBodyMap(c.Request)     // c.Request 是 gin 框架的写法
if err != nil {
    xlog.Error(err)
    return
}
 或
// value：url.Values
notifyReq, err = alipay.ParseNotifyByURLValues()
if err != nil {
    xlog.Error(err)
    return
}

// 支付宝异步通知验签（公钥模式）
ok, err = alipay.VerifySign(aliPayPublicKey, notifyReq)

// 支付宝异步通知验签（公钥证书模式）
ok, err = alipay.VerifySignWithCert("alipayPublicCert.crt content", notifyReq)

// 如果需要，可将 BodyMap 内数据，Unmarshal 到指定结构体指针 ptr
err = notifyReq.Unmarshal(ptr)

// ====异步通知，返回支付宝平台的信息====
// 文档：https://opendocs.alipay.com/open/203/105286
// 程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）

// 此写法是 gin 框架返回支付宝的写法
c.String(http.StatusOK, "%s", "success")

// 此写法是 echo 框架返回支付宝的写法
return c.String(http.StatusOK, "success")
```

### 4、支付宝 公共API（仅部分说明）

> 支付宝换取授权访问令牌文档：[换取授权访问令牌](https://opendocs.alipay.com/apis/api_9/alipay.system.oauth.token)

> 支付宝小程序 获取用户手机号文档：[获取用户手机号](https://opendocs.alipay.com/mini/api/getphonenumber)

> 支付宝加解密文档：[AES加解密文档](https://opendocs.alipay.com/open/common/104567)

```go
import (
    "github.com/go-pay/gopay/alipay"
    "github.com/go-pay/xlog"
)

// 换取授权访问令牌（默认使用utf-8，RSA2）
// appId：应用ID
// privateKey：应用私钥，支持PKCS1和PKCS8
// grantType：值为 authorization_code 时，代表用code换取；值为 refresh_token 时，代表用refresh_token换取，传空默认code换取
// codeOrToken：支付宝授权码或refresh_token
rsp, err := alipay.SystemOauthToken(appId, privateKey, grantType, codeOrToken)
if err != nil {
    xlog.Error(err)
    return
}

// 解密支付宝开放数据带到指定结构体
// 以小程序获取手机号为例
phone := new(alipay.UserPhone)
// 解密支付宝开放数据
// encryptedData:包括敏感数据在内的完整用户信息的加密数据
// secretKey:AES密钥，支付宝管理平台配置
// beanPtr:需要解析到的结构体指针
err := alipay.DecryptOpenDataToStruct(encryptedData, secretKey, phone)
xlog.Infof("%+v", phone)
```

---

## 附录：

### 支付宝支付 API

* 支付宝接口自行实现方法：`client.PostAliPayAPISelfV2()`
* 生成请求参数：`client.RequestParam()`
* <font color='#027AFF' size='4'>支付产品</font>
  * 当面付
    * 付款码支付接口(商家扫用户付款码)：`client.TradePay()`
    * 统一收单线下交易预创建接口(用户扫商品收款码)：`client.TradePrecreate()`
  * App支付
    * APP支付接口2.0(APP支付)：`client.TradeAppPay()`
  * 手机网站支付
    * 手机网站支付接口2.0(手机网站支付)：`client.TradeWapPay()`
  * 电脑网站支付
    * 统一收单下单并支付页面接口(电脑网站支付)：`client.TradePagePay()`
  * 刷脸付
    * 刷脸支付初始化接口：`client.ZolozAuthenticationSmilepayInitialize()`
    * 查询刷脸结果信息接口：`client.ZolozAuthenticationCustomerFtokenQuery()`
  * 预授权支付
    * 线上资金授权冻结接口：`client:FundAuthOrderAppFreeze()`
    * 资金授权操作查询接口：`client.FundAuthOperationDetailQuery()`
    * 资金授权撤销接口：`client.FundAuthOperationCancel()`
    * 资金授权解冻接口：`client.FundAuthOrderUnfreeze()`
    * 资金授权发码接口：`client.FundAuthOrderVoucherCreate()`
    * 资金授权冻结接口：`client.FundAuthOrderFreeze()`
  * 交易
    * 统一收单交易创建接口：`client.TradeCreate()`
    * 统一收单交易订单支付接口：`client.TradeOrderPay()`
    * 统一收单线下交易查询: `client.TradeQuery()`
    * 统一收单交易退款接口: `client.TradeRefund()`
    * 统一收单交易退款查询: `client.TradeFastPayRefundQuery()`
    * 统一收单交易关闭接口: `client.TradeClose()`
    * 统一收单交易撤销接口: `client.TradeCancel()`
    * 支付宝订单信息同步接口: `client.TradeOrderInfoSync()`
  * 账单
    * 查询对账单下载地址：`client.DataBillDownloadUrlQuery()`
  * 商家分账
    * 分账关系维护
      * 分账关系绑定接口：`client.TradeRelationBind()`
      * 分账关系解绑接口：`client.TradeRelationUnbind()`
      * 分账关系查询接口：`client.TradeRelationBatchQuery()`
    * 分账请求
      * 统一收单交易结算接口：`client.TradeOrderSettle()`
      * 统一收单确认结算接口：`client.TradeSettleConfirm()`
    * 分账查询 
      * 分账比例查询：`client.TradeRoyaltyRateQuery()`
      * 分账剩余金额查询：`client.TradeOrderOnSettleQuery()`
      * 交易分账查询接口：`client.TradeOrderSettleQuery()`
  * 商家扣款
    * 支付宝个人协议页面签约接口: `client.UserAgreementPageSign()`
    * 支付宝个人协议页面签约接口 - PC转二维码唤起签约页: `client.UserAgreementPageSignInQRCode()`
    * 支付宝个人代扣协议查询接口: `client.UserAgreementQuery()`
    * 支付宝个人代扣协议解约接口: `client.UserAgreementPageUnSign()`
    * 周期性扣款协议执行计划修改接口: `client.UserAgreementExecutionplanModify()`
* <font color='#027AFF' size='4'>私域产品</font>
  * 支付有礼
    * 推广计划
* <font color='#027AFF' size='4'>公域产品</font>
  * 经营推广
    * 推广计划
      * 推广计划状态变更消息接口：`client.MarketingActivityDeliveryChanged()`
      * 创建推广计划接口：`client.MarketingActivityDeliveryCreate()`
      * 查询推广计划接口：`client.MarketingActivityDeliveryQuery()`
      * 停止推广计划接口：`client.MarketingActivityDeliveryStop()` 
      * 营销图片资源上传接口：`client.MarketingMaterialImageUpload()`
* <font color='#027AFF' size='4'>营销产品</font>
  * 支付券
    * 创建支付券接口：`client.MarketingActivityVoucherCreate()`
    * 激活支付券接口：`client.MarketingActivityVoucherPublish()`
    * 查询支付券详情接口：`client.MarketingActivityVoucherQuery()`
    * 修改支付券基本信息接口：`client.MarketingActivityVoucherModify()`
    * 追加支付券预算接口：`client.MarketingActivityVoucherAppend()`
    * 停止支付券接口：`client.MarketingActivityVoucherStop()`
  * 私域营销
    * 条件查询活动列表接口：`client.MarketingActivityBatchQuery()`
    * 活动领取咨询接口：`client.MarketingActivityConsult()`
    * 查询活动详情接口：`client.MarketingActivityQuery()`
    * 查询活动可用商户接口：`client.MarketingActivityQueryMerchantBatchQuery()`
    * 查询活动可用小程序接口：`client.MarketingActivityQueryAppBatchQuery()`
    * 查询活动可用门店接口：`client.MarketingActivityQueryShopBatchQuery()`
    * 查询活动适用商品接口：`client.MarketingActivityQueryGoodsBatchQuery()`
    * 条件查询用户券接口：`client.MarketingActivityQueryUserBatchQueryVoucher()`
    * 查询用户券详情接口：`client.MarketingActivityQueryUserQueryVoucher()`
    * 订单优惠前置咨询接口：`client.MarketingCampaignOrderVoucherConsult()`
  * 蚂蚁门店管理
    * 蚂蚁店铺创建接口: `client.AntMerchantShopCreate()`
    * 修改蚂蚁店铺接口: `client.AntMerchantShopModify()`
    * 商户申请单查询接口: `client.AntMerchantOrderQuery()`
    * 店铺分页查询接口：`client.AntMerchantShopPageQuery()`
    * 店铺查询接口：`client.AntMerchantShopQuery()`
    * 蚂蚁店铺关闭接口：`client.AntMerchantShopClose()`
    * 图片上传接口：`client.AntMerchantExpandIndirectImageUpload()`
    * 商户mcc信息查询接口：`client.AntMerchantExpandMccQuery()`
    * 店铺增加收单账号接口：`client.AntMerchantExpandShopReceiptAccountSave()`
  * 商家券 2.0
    * 活动创建 
      * 创建商家券活动接口：`client.MarketingActivityOrderVoucherCreate()`
      * 同步商家券券码接口：`client.MarketingActivityOrderVoucherCodeDeposit()`
    * 活动修改
      * 修改商家券活动基本信息接口：`client.MarketingActivityOrderVoucherModify()`
    * 活动停止
      * 停止商家券活动接口：`client.MarketingActivityOrderVoucherStop()`
    * 预算追加
      * 修改商家券活动发券数量上限接口：`client.MarketingActivityOrderVoucherAppend()`
    * 活动发放
      * 活动领取咨询接口：`client.MarketingActivityConsult()`
    * 优惠券核销
      * 同步券核销状态接口：`client.MarketingActivityOrderVoucherUse()`
      * 取消券核销状态接口：`client.MarketingActivityOrderVoucherRefund()`
    * 活动查询
      * 查询商家券活动接口：`client.MarketingActivityOrderVoucherQuery()`
      * 查询活动详情接口：`client.MarketingActivityQuery()`
      * 统计商家券券码数量接口：`client.MarketingActivityOrderVoucherCodeCount()`
      * 条件查询活动列表接口：`client.MarketingActivityBatchQuery()`
      * 条件查询用户券接口：`client.MarketingActivityQueryUserBatchQueryVoucher()`
      * 查询用户券详情接口：`client.MarketingActivityQueryUserQueryVoucher()`
      * 查询活动可用小程序接口：`client.MarketingActivityQueryAppBatchQuery()`
      * 查询活动可用门店接口：`client.MarketingActivityQueryShopBatchQuery()`
      * 查询活动适用商品接口：`client.MarketingActivityQueryGoodsBatchQuery()`
  * 商家会员卡
    * 会员卡模板创建接口：`client.MarketingCardTemplateCreate()`
    * 会员卡模板修改接口：`client.MarketingCardTemplateModify()`
    * 会员卡模板查询接口：`client.MarketingCardTemplateQuery()`
    * 会员卡更新接口：`client.MarketingCardUpdate()`
    * 会员卡查询接口：`client.MarketingCardQuery()`
    * 会员卡删卡接口：`client.MarketingCardDelete()`
    * 会员卡消息通知接口：`client.MarketingCardMessageNotify()`
    * 会员卡开卡表单模板配置接口：`client.MarketingCardFormTemplateSet()`
    * 上传门店照片和视频接口：`client.OfflineMaterialImageUpload()`
  * 营销活动送红包 
    * 创建现金活动接口：`client.MarketingCampaignCashCreate()`
    * 触发现金红包活动接口：`client.MarketingCampaignCashTrigger()`
    * 更改现金活动状态接口：`client.MarketingCampaignCashStatusModify()`
    * 现金活动列表查询接口：`client.MarketingCampaignCashListQuery()`
    * 现金活动详情查询接口：`client.MarketingCampaignCashDetailQuery()`
  * 红包
    * 资金转账页面支付接口: `client.FundTransPagePay()`
    * 现金红包无线支付接口: `client.FundTransAppPay()`
    * 单笔转账接口：`client.FundTransUniTransfer()`
    * 转账业务单据查询接口：`client.FundTransCommonQuery()`
    * 资金退回接口: `client.FundTransRefund()`
  * 棋盘密云
    * 接口上传人群
      * 上传创建人群接口：`client.MerchantQipanCrowdCreate()`
      * 人群中追加用户接口：`client.MerchantQipanCrowdUserAdd()`
      * 人群中删除用户接口：`client.MerchantQipanCrowdUserDelete()`
    * 标签圈选创建人群
      * 棋盘人群圈选标签基本信息查询接口：`client.MarketingQipanTagBaseBatchQuery()`
      * 棋盘标签圈选值查询接口：`client.MarketingQipanTagQuery()`
      * 棋盘人群创建接口：`client.MarketingQipanCrowdOperationCreate()`
      * 查询圈选标签列表接口：`client.MarketingQipanCrowdTagQuery()`
      * 标签圈选创建人群接口：`client.MarketingQipanCrowdWithTagCreate()`
      * 标签圈选预估人群规模接口：`client.MarketingQipanCrowdWithTagQuery()`
    * 管理人群
      * 查询人群列表接口：`client.MarketingQipanCrowdBatchQuery()`
      * 查询人群详情接口：`client.MarketingQipanCrowdQuery()`
      * 修改人群接口：`client.MarketingQipanCrowdModify()`
    * 数据洞察 
      * 看板分析接口：`client.MarketingQipanBoardQuery()`
      * 画像分析接口：`client.MarketingQipanInsightQuery()`
      * 行为分析接口：`client.MarketingQipanBehaviorQuery()`
      * 趋势分析接口：`client.MarketingQipanTrendQuery()`
      * 常住省市查询接口：`client.MarketingQipanInsightCityQuery()`
* <font color='#027AFF' size='4'>资金产品</font>
  * 转账到支付宝账户
    * 支付宝资金账户资产查询接口：`client.FundAccountQuery()`
    * 申请电子回单(incubating)接口：`client.DataBillEreceiptApply()`
    * 查询电子回单状态(incubating)接口：`client.DataBillEreceiptQuery()`
    * 查询转账订单接口: `client.FundTransOrderQuery()`
    * 批次下单接口: `client.FundBatchCreate()`
    * 批量转账关单接口: `client.FundBatchClose()`
    * 批量转账明细查询接口: `client.FundBatchDetailQuery()`
    * 资金收款账号绑定关系查询: `client.FundTransPayeeBindQuery()`
* <font color='#027AFF' size='4'>会员产品</font>
  * 人脸验证
    * 人脸核身
      * APP人脸核身初始化接口：`client.FaceVerificationInitialize()`
      * APP人脸核身结果查询接口：`client.FaceVerificationQuery()`
      * H5人脸核身初始化接口：`client.FaceCertifyInitialize()`
      * H5人脸核身开始认证接口：`client.FaceCertifyVerify()`
      * H5人脸核身查询记录接口：`client.FaceCertifyQuery()`
      * 纯服务端人脸核身接口：`client.FaceSourceCertify()`
    * 活体检测
      * 人脸检测初始化接口：`client.FaceCheckInitialize()`
      * 人脸检测结果数据查询接口：`client.FaceCheckQuery()`
    * OCR文字识别
      * 服务端OCR接口：`client.OcrServerDetect()`
      * App端OCR初始化接口：`client.OcrMobileInitialize()`
      * 文字识别OCR接口：`client.OcrCommonDetect()`
  * 获取会员信息
    * 支付宝会员授权信息查询接口：`client.UserInfoShare()`
    * 换取授权访问令牌接口：`client.SystemOauthToken()`
    * 用户授权关系查询接口：`client.UserAuthRelationshipQuery()`
    * 查询解除授权明细接口：`client.UserDelOAuthDetailQuery()`
  * 支付宝身份验证
    * 身份认证记录查询: `client.UserCertifyOpenQuery()`
    * 身份认证初始化服务接口: `client.UserCertifyOpenInit()`
    * 身份认证开始认证: `client.UserCertifyOpenCertify()`
  * APP支付宝登录
    * 用户登录授权接口：`client.UserInfoAuth()`
* <font color='#027AFF' size='4'>信用产品</font>
  * 芝麻GO
    * 芝麻GO签约预创单接口：`client.ZhimaCreditPeZmgoPreorderCreate()`
    * 芝麻GO页面签约接口：`client.ZhimaCreditPeZmgoSignApply()`
    * 商家芝麻GO累计数据回传接口：`client.ZhimaMerchantZmgoCumulateSync()`
    * 商家芝麻GO累计数据查询接口：`client.ZhimaMerchantZmgoCumulateQuery()`
    * 芝麻GO结算申请接口：`client.ZhimaCreditPeZmgoSettleApply()`
    * 芝麻GO结算退款接口：`client.ZhimaCreditPeZmgoSettleRefund()`
    * 芝麻Go协议查询接口：`client.ZhimaCreditPeZmgoAgreementQuery()`
    * 芝麻GO协议解约接口：`client.ZhimaCreditPeZmgoAgreementUnsign()`
    * 商户创建芝麻GO模板接口：`client.ZhimaMerchantZmgoTemplateCreate()`
    * 芝麻GO模板查询接口：`client.ZhimaMerchantZmgoTemplateQuery()`
    * 芝麻GO用户数据回传: `client.ZhimaCreditPeZmgoCumulationSync()`
    * 芝麻GO签约关单: `client.ZhimaCreditPeZmgoBizoptClose()`
    * 芝麻GO解冻接口: `client.ZhimaCreditPeZmgoSettleUnfreeze()`
    * 芝麻GO支付下单链路签约申请: `client.ZhimaCreditPeZmgoPaysignApply()`
    * 芝麻GO支付下单链路签约确认: `client.ZhimaCreditPeZmgoPaysignConfirm()`
  * 芝麻先享
    * 服务开通
      * 信用服务开通/授权接口：`client.ZhimaCreditPayAfterUseAgreementSign()`
      * 查询服务开通/授权信息接口：`client.ZhimaCreditPayAfterUseAgreementQuery()`
    * 信用下单 
      * 芝麻先享信用服务下单（免用户确认场景）接口：`client.ZhimaCreditPayAfterUseCreditBizOrder()`
      * 芝麻先享信用服务下单（用户确认场景）接口：支付宝 SDK 实现
      * 信用服务订单查询接口：`client.ZhimaCreditPayAfterUseCreditBizOrderQuery()`
      * 结束信用服务订单接口：`client.ZhimaCreditPayAfterUseCreditBizOrderFinish()`
  * 扣款
    * 统一收单交易订单支付接口：`client.TradeOrderPay()`
  * 芝麻免押
    * 创建免押订单接口：`client:FundAuthOrderAppFreeze()` 
    * 完结免押订单接口：`client.FundAuthOrderUnfreeze()`
    * 查询免押订单接口：`client.FundAuthOperationDetailQuery()`
    * 取消免押订单接口：`client.FundAuthOperationCancel()`
  * 芝麻身份信息验证
    * 信用服务开通/授权接口：`client.ZhimaCreditPayAfterUseAgreementSign()`
    * 职得身份认证查询接口：`client.ZhimaCustomerJobworthAuthQuery()`
    * 职得工作证信息匹配度查询: `client.ZhimaCustomerJobworthAdapterQuery()`
    * 职得工作证外部渠道应用数据回流: `client.ZhimaCustomerJobworthSceneUse()`
    * 身份验真预咨询服务接口：`client.ZhimaCustomerJobworthAuthPreConsult()`
* <font color='#027AFF' size='4'>安全产品</font>
  * 交易安全防护
    * 商户数据同步：`client.SecurityCustomerRiskSend()`
  * RiskGO
    * 消费者投诉
      * 处理消费者投诉接口：`client.SecurityRiskComplaintProcessFinish()`
      * 投诉处理附件图片上传接口：`client.SecurityRiskComplaintFileUpload()`
      * 查询消费者投诉详情接口：`client.SecurityRiskComplaintInfoQuery()`
      * 查询消费者投诉列表接口：`client.SecurityRiskComplaintInfoBatchquery()`
    * 营销风险识别
      * 营销风险识别发奖接口：`client.SecurityRiskMarketingAwardingQuery()`
      * 营销风险识别抢购接口：`client.SecurityRiskMarketingPurchaseQuery()`
    * 行业风险识别
      * 行业风险识别黄牛接口：`client.SecurityRiskIndustryScalperQuery()`
      * 行业风险识别刷单接口：`client.SecurityRiskIndustryFarmingQuery()`
      * 行业风险识别先享后付违约接口：`client.SecurityRiskIndustryNsfQuery()`
    * 内容风险识别
      * 内容风险同步识别接口：`client.SecurityRiskContentSyncDetect()`
* <font color='#027AFF' size='4'>广告产品</font>
  * 支付宝广告投放
    * 转化数据回传接口：`client.DataServiceAdConversionUpload()`
    * 广告投放数据通用查询接口：`client.DataServiceAdReportdataQuery()`
    * 自建推广页列表批量查询接口：`client.DataServiceAdPromotepageBatchquery()`
    * 自建推广页留资数据查询接口：`client.DataServiceAdPromotepageDownload()`
    * 任务广告完成状态查询接口：`client.DataServiceXlightTaskQuery()`
* <font color='#027AFF' size='4'>其他通用产品</font>
  * 商家费率申请
    * 特殊费率申请接口：`client.OpenFeeAdjustApply()`
* <font color='#027AFF' size='4'>第三方应用产品</font>
  * 第三方应用授权
    * 换取应用授权令牌：`client.OpenAuthTokenApp()`
    * 查询某个应用授权AppAuthToken的授权信息：`client.OpenAuthTokenAppQuery()`
    * ISV向商户发起应用授权邀约：`client.OpenAuthTokenAppInviteCreate()`
  * 三方开发基础
    * 查询应用可申请的接口出参敏感字段列表：`client.OpenAppApiQuery()`
    * 申请获取接口用户敏感信息字段：`client.OpenAppApiFieldApply()`
    * 查询接口字段使用场景：`client.OpenAppApiSceneQuery()`
    * 用户信息申请记录查询：`client.OpenAppApiFieldQuery()`
    * 应用信息修改接口：`client.OpenAppInfoModify()`
    * 应用信息查询接口：`client.OpenAppInfoQuery()`
* <font color='#027AFF' size='4'>邀测站点</font>
  * 营销咨询
    * 商户前置内容咨询接口： `client.PayAppMarketingConsult()`
  * 订阅
    * 商品创建接口：`client.TradeProductCreate()`
    * 商品修改接口：`client.TradeProductModify()`
    * 商品查询接口：`client.TradeProductQuery()`
    * 价格创建接口：`client.TradePriceCreate()`
    * 价格查询接口：`client.TradePriceQuery()`
    * 客户创建接口：`client.TradeCustomerCreate()`
    * 订阅创建接口：`client.TradeSubscriptionCreate()`
    * 订阅修改接口：`client.TradeSubscriptionModify()`
    * 订阅查询接口：`client.TradeSubscriptionQuery()`
* <font color='#027AFF' size='4'>支付宝电子发票</font>
  * 正向开票
    * 支付开票开票申请创建接口：`client.IndustryInvoiceApplyCreate()`
    * 支付开票开票申请查询接口：`client.IndustryInvoiceApplyQuery()`
    * 支付开票开票申请重试接口：`client.IndustryInvoiceApplyRetry()`
  * 企业信息
    * 企业信息查询接口：`client.IndustryInvoiceCompanyQuery()`
* <font color='#027AFF' size='4'>可能失效的接口</font>
  * 应用支付宝公钥证书下载：`client.PublicCertDownload()`
  * 小程序生成推广二维码接口：`client.OpenAppQrcodeCreate()`
  * 花芝轻会员结算申请: `client.PcreditHuabeiAuthSettleApply()`
  * NFC用户卡信息同步: `client.CommerceTransportNfccardSend()`
  * 广告投放数据查询: `client.DataDataserviceAdDataQuery()`
  * 航司电话订票待申请接口: `client.CommerceAirCallcenterTradeApply()`
  * 网商银行全渠道收单业务订单创建: `client.PaymentTradeOrderCreate()`
  * 聚合支付订单咨询服务: `client.KoubeiTradeOrderAggregateConsult()`
  * 口碑订单预下单: `client.KoubeiTradeOrderPrecreate()`
  * 口碑商品交易购买接口: `client.KoubeiTradeItemorderBuy()`
  * 口碑订单预咨询: `client.KoubeiTradeOrderConsult()`
  * 口碑商品交易退货接口: `client.KoubeiTradeItemorderRefund()`
  * 口碑商品交易查询接口: `client.KoubeiTradeItemorderQuery()`
  * 码商发码成功回调接口: `client.KoubeiTradeTicketTicketcodeSend()`
  * 口碑凭证延期接口: `client.KoubeiTradeTicketTicketcodeDelay()`
  * 口碑凭证码查询: `client.KoubeiTradeTicketTicketcodeQuery()`
  * 口碑凭证码撤销核销: `client.KoubeiTradeTicketTicketcodeCancel()`
  * 蚂蚁店铺创建咨询: `client.AntMerchantShopConsult()`
  * 申请权益发放: `client.CommerceBenefitApply()`
  * 权益核销: `client.CommerceBenefitVerify()`
  * 还款账单查询: `client.TradeRepaybillQuery()`
  * 芝麻企业信用信用评估初始化: `client.ZhimaCreditEpSceneRatingInitialize()`
  * 信用服务履约同步: `client.ZhimaCreditEpSceneFulfillmentSync()`
  * 加入信用服务: `clinet.ZhimaCreditEpSceneAgreementUse()`
  * 取消信用服务: `client.ZhimaCreditEpSceneAgreementCancel()`
  * 信用服务履约同步(批量): `client.ZhimaCreditEpSceneFulfillmentlistSync()`
  * 小程序生成推广二维码接口：`client.OpenAppQrcodeCreate()`
  * 协议由普通通用代扣协议产品转移到周期扣协议产品: `client.UserAgreementTransfer()`
  * 通用当面付二阶段接口: `client.UserTwostageCommonUse()`
  * 芝麻企业征信基于身份的协议授权: `client.UserAuthZhimaorgIdentityApply()`
  * 查询是否在支付宝公益捐赠的接口: `client.UserCharityRecordexistQuery()`
  * 集分宝发放接口: `client.UserAlipaypointSend()`
  * isv 会员CRM数据回流: `client.MemberDataIsvCreate()`
  * 询家人信息档案(选人授权)组件已选的家人档案信息: `client.UserFamilyArchiveQuery()`
  * 初始化家人信息档案(选人授权)组件: `client.UserFamilyArchiveInitialize()`
  * 实名证件信息比对验证预咨询: `client.UserCertdocCertverifyPreconsult()`
  * 实名证件信息比对验证咨询: `client.UserCertdocCertverifyConsult()`
  * 初始化家庭芝麻GO共享组件: `client.UserFamilyShareZmgoInitialize()`
  * 数字分行银行码明细数据查询: `client.UserDtbankQrcodedataQuery()`
  * 查询集分宝预算库详情: `client.UserAlipaypointBudgetlibQuery()`

### 支付宝公共 API

* `alipay.IsBizError()` => 判断并捕获业务错误 BizError
* `alipay.GetCertSN()` => 获取证书SN号（app_cert_sn、alipay_cert_sn）
* `alipay.GetRootCertSN()` => 获取证书SN号（alipay_root_cert_sn）
* `alipay.GetRsaSign()` => 获取支付宝参数签名（参数sign值）
* `alipay.SystemOauthToken()` => 换取授权访问令牌（得到access_token，user_id等信息）
* `alipay.FormatPrivateKey()` => 格式化应用私钥
* `alipay.FormatPublicKey()` => 格式化支付宝公钥
* `alipay.FormatURLParam()` => 格式化支付宝请求URL参数
* `alipay.ParseNotifyToBodyMap()` => 解析支付宝支付异步通知的参数到BodyMap
* `alipay.ParseNotifyByURLValues()` => 通过 url.Values 解析支付宝支付异步通知的参数到BodyMap
* `alipay.VerifySign()` => 支付宝异步通知参数验签
* `alipay.VerifySignWithCert()` => 支付宝异步通知参数验签（证书方式）
* `alipay.VerifySyncSign()` => 支付宝同步返回参数验签
* `alipay.DecryptOpenDataToStruct()` => 解密支付宝开放数据到 结构体
* `alipay.DecryptOpenDataToBodyMap()` => 解密支付宝开放数据到 BodyMap
* `alipay.MonitorHeartbeatSyn()` => 验签接口

---

### Doc Alipay V3 (`doc/alipay_v3.md`)

## 支付宝

> #### 支付宝v3版本已支持，接口持续完善中。

> #### 因支付宝接口太多，如没实现的接口，还请开发者自行调用 `client.DoAliPayAPISelfV3()`方法实现！请参考 `client_test.go` 内的 `TestDoAliPayAPISelfV3()` 方法

> #### 希望有时间的伙伴儿Fork完后，补充并提交Pull Request，一起完善支付宝各个类别下的接口到相应的go文件中

- 已实现API列表附录：[API 列表附录](https://github.com/go-pay/gopay/blob/main/doc/alipay_v3.md#%E9%99%84%E5%BD%95)

- 开发文档（V3版）：[开发文档（V3版）](https://opendocs.alipay.com/open-v3) 

- 接口规则：[接口规则](https://opendocs.alipay.com/open-v3/053sd1)

- 支付宝RSA秘钥生成文档：[生成RSA密钥](https://opendocs.alipay.com/common/02kipl) （推荐使用 RSA2）

- 沙箱环境(新) 使用说明：[新版沙箱文档](https://opendocs.alipay.com/common/02kkv7)

---

### 1、初始化支付宝客户端并做配置

> 具体API使用介绍，请参考 `gopay/alipay/v3/client_test.go`

>  

```go
import (
    "github.com/go-pay/gopay/alipay/v3"
    "github.com/go-pay/xlog"
)

// 初始化支付宝客V3户端
// appid：应用ID
// privateKey：应用私钥，支持PKCS1和PKCS8
// isProd：是否是正式环境，沙箱环境请选择新版沙箱应用。
client, err := alipay.NewClientV3("2016091200494382", privateKey, false)
if err != nil {
    xlog.Error(err)
    return
}

// 设置自定义配置（如需要）
//client.
//	SetAppAuthToken("app_auth_token").    // 设置授权token
//	SetBodySize().                        // 自定义配置http请求接收返回结果body大小，默认 10MB，没有特殊需求，可忽略此配置
//	SetRequestIdFunc().                   // 设置自定义RequestId生成方法
//	SetAESKey("KvKUTqSVZX2fUgmxnFyMaQ==") // 设置biz_content加密KEY，设置此参数默认开启加密（目前不可用）

// 打开Debug开关，输出日志，默认关闭
client.DebugSwitch = gopay.DebugOn

// 传入证书内容
err := client.SetCert("appPublicCert.crt bytes", "alipayRootCert bytes", "alipayPublicCert.crt bytes")
```

### 2、API 方法调用及入参

> 具体参数请根据不同接口查看：[支付宝V3版API接口文档](https://opendocs.alipay.com/open-v3)

> ★入参 BodyMap中，支持如下公共参数在当次请求中自定义设置：`alipay-app-auth-token`

- 统一收单线下交易预创建 - 示例

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/pkg/js"
    "github.com/go-pay/util"
    "github.com/go-pay/xlog"
    "github.com/go-pay/gopay/alipay/v3"
)

// 请求参数
bm := make(gopay.BodyMap)
bm.Set("subject", "预创建创建订单").
    Set("out_trade_no", util.RandomString(32)).
    Set("total_amount", "0.01")
    Set(alipay.HeaderAppAuthToken, "i_am_app_auth_token") // 如果需要，可以设置自定义应用授权

// 创建订单
aliRsp, err := client.TradePrecreate(ctx, bm)
if err != nil {
    xlog.Errorf("client.TradePrecreate(), err:%v", err)
    return
}
xlog.Warnf("aliRsp:%s", js.Marshal(aliRsp))

if aliRsp.StatusCode != Success {
    xlog.Errorf("aliRsp.StatusCode:%d", aliRsp.StatusCode)
    return
}
xlog.Warnf("aliRsp.QrCode:", aliRsp.QrCode)
xlog.Warnf("aliRsp.OutTradeNo:", aliRsp.OutTradeNo)
```

- 自定义接口调用 - 示例

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/pkg/js"
    "github.com/go-pay/util"
    "github.com/go-pay/xlog"
)

// 请求参数
bm := make(gopay.BodyMap)
bm.Set("subject", "预创建创建订单").
    Set("out_trade_no", util.RandomString(32)).
    Set("total_amount", "0.01")

rsp := new(struct {
    OutTradeNo string `json:"out_trade_no"`
    QrCode     string `json:"qr_code"`
})
// 创建订单
res, err := client.DoAliPayAPISelfV3(ctx, alipay.MethodPost, "/v3/alipay/trade/precreate", bm, rsp)
if err != nil {
    xlog.Errorf("client.TradePrecreate(), err:%v", err)
    return
}
xlog.Warnf("aliRsp:%s", js.Marshal(rsp))
if res.StatusCode != Success {
    xlog.Errorf("aliRsp.StatusCode:%d", res.StatusCode)
    return
}
```

### 3、异步通知参数解析和验签Sign、异步通知返回（复用非V3版方式）

> 异步通知请求参数需要先解析，解析出来的结构体或BodyMap再验签（此处需要注意，`http.Request.Body` 只能解析一次，如果需要解析前调试，请处理好Body复用问题）

[Gin Web框架（推荐）](https://github.com/gin-gonic/gin)

[Echo Web框架](https://github.com/labstack/echo)

> 支付宝支付后的异步通知验签文档：[支付结果通知](https://opendocs.alipay.com/common/02mse7)

- 异步通知验签（复用非V3版方式）

```go
import (
    "github.com/go-pay/gopay/alipay"
)

// 解析异步通知的参数
// req：*http.Request
notifyReq, err = alipay.ParseNotifyToBodyMap(c.Request)     // c.Request 是 gin 框架的写法
if err != nil {
    xlog.Error(err)
    return
}
 或
// value：url.Values
notifyReq, err = alipay.ParseNotifyByURLValues()
if err != nil {
    xlog.Error(err)
    return
}

// 支付宝异步通知验签（公钥模式）
ok, err = alipay.VerifySign(aliPayPublicKey, notifyReq)

// 支付宝异步通知验签（公钥证书模式）
ok, err = alipay.VerifySignWithCert([]byte("alipayPublicCert.crt content"), notifyReq)

// 如果需要，可将 BodyMap 内数据，Unmarshal 到指定结构体指针 ptr
err = notifyReq.Unmarshal(ptr)

// ====异步通知，返回支付宝平台的信息====
// 文档：https://opendocs.alipay.com/open/203/105286
// 程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）

// 此写法是 gin 框架返回支付宝的写法
c.String(http.StatusOK, "%s", "success")

// 此写法是 echo 框架返回支付宝的写法
return c.String(http.StatusOK, "success")
```

---

## 附录：

### 支付宝支付 API

* 支付宝接口自行实现方法：`client.DoAliPayAPISelfV3()`
* <font color='#027AFF' size='4'>支付</font>
  * 统一收单交易支付接口：`client.TradePay()`
  * 统一收单交易查询：`client.TradeQuery()`
  * 统一收单交易退款接口：`client.TradeRefund()`
  * 统一收单交易退款查询：`client.TradeFastPayRefundQuery()`
  * 统一收单交易撤销接口：`client.TradeCancel()`
  * 统一收单交易关闭接口：`client.TradeClose()`
  * 查询对账单下载地址：`client.DataBillDownloadUrlQuery()`
  * 统一收单线下交易预创建：`client.TradePrecreate()`
  * 支付宝APP支付（v2版本）：`client.TradeAppPay()`
  * 统一收单下单并支付页面接口（v2版本）：`client.TradePagePay()`
  * 手机网站支付接口（v2版本）：`client.TradeWapPay()`
  * 统一收单交易创建接口：`client.TradeCreate()`
  * 支付宝订单信息同步接口：`client.TradeOrderInfoSync()`
  * 资金授权操作查询接口：`client.FundAuthOperationDetailQuery()`
  * 资金授权冻结接口：`client.FundAuthOrderFreeze()`
  * 资金授权解冻接口：`client.FundAuthOrderUnfreeze()`
  * 资金授权发码接口：`client.FundAuthOrderVoucherCreate()`
  * 刷脸支付初始化接口：`client.ZolozAuthenticationSmilepayInitialize()`
  * 查询刷脸结果信息接口：`client.ZolozAuthenticationCustomerFtokenQuery()`
* <font color='#027AFF' size='4'>商家扣款</font>
  * 支付宝个人代扣协议查询接口：`client.UserAgreementQuery()`
  * 支付宝个人代扣协议解约接口：`client.UserAgreementPageUnSign()`
* <font color='#027AFF' size='4'>商家分账</font>
  * 分账关系绑定接口：`client.TradeRelationBind()`
  * 分账关系解绑：`client.TradeRelationUnbind()`
  * 分账关系查询：`client.TradeRelationBatchQuery()`
  * 分账比例查询：`client.TradeRoyaltyRateQuery()`
  * 统一收单交易结算接口：`client.TradeOrderSettle()`
  * 分账剩余金额查询：`client.TradeOrderOnSettleQuery()`
* <font color='#027AFF' size='4'>商家转账</font>
  * 支付宝资金账户资产查询接口：`client.FundAccountQuery()`
  * 转账额度查询接口：`client.FundQuotaQuery()`
  * 单笔转账接口：`client.FundTransUniTransfer()`
  * 申请电子回单(incubating)：`client.DataBillEreceiptApply()`
  * 查询电子回单状态(incubating)：`client.DataBillEreceiptQuery()`
  * 转账业务单据查询接口：`client.FundTransCommonQuery()`
  * 多步转账创建并支付：`client.FundTransMultistepTransfer()`
  * 多步转账查询接口：`client.FundTransMultistepQuery()`
* <font color='#027AFF' size='4'>会员</font>
  * 换取授权访问令牌：`client.SystemOauthToken()`
  * 身份认证记录查询：`client.UserCertifyOpenQuery()`
  * 身份认证初始化服务：`client.UserCertifyOpenInitialize()`
  * 支付宝会员授权信息查询接口：`client.UserInfoShare()`
  * 用户授权关系查询：`client.UserAuthRelationshipQuery()`
  * 查询解除授权明细：`client.UserDelOauthDetailQuery()`
* <font color='#027AFF' size='4'>人脸认证</font>
  * 人脸核身初始化：`client.FaceVerificationInitialize()`
  * 人脸核身结果查询：`client.FaceVerificationQuery()`
  * 跳转支付宝人脸核身初始化：`client.FaceCertifyInitialize()`
  * 跳转支付宝人脸核身开始认证：`client.FaceCertifyVerify()`
  * 跳转支付宝人脸核身查询记录：`client.FaceCertifyQuery()`
  * 纯服务端人脸核身：`client.FaceSourceCertify()`
  * 活体检测初始化：`client.FaceCheckInitialize()`
  * 活体检测结果查询：`client.FaceCheckQuery()`
  * 身份证二要素核验：`client.IDCardTwoMetaCheck()`
  * 银行卡核验：`client.BankCardCheck()`
  * 手机号三要素核验简版：`client.MobileThreeMetaSimpleCheck()`
  * 手机号三要素核验详版：`client.MobileThreeMetaDetailCheck()`
  * 服务端OCR：`client.OcrServerDetect()`
  * App端OCR初始化：`client.OcrMobileInitialize()`
* <font color='#027AFF' size='4'>推广计划</font>
  * 创建推广计划：`client.MarketingActivityDeliveryCreate()`
  * 查询推广计划：`client.MarketingActivityDeliveryQuery()`
  * 停止推广计划：`client.MarketingActivityDeliveryStop()`
* <font color='#027AFF' size='4'>营销</font>
  * 创建现金活动：`client.MarketingCampaignCashCreate()`
  * 触发现金红包：`client.MarketingCampaignCashTrigger()`
  * 更改现金活动状态：`client.MarketingCampaignCashStatusModify()`
  * 现金活动列表查询：`client.MarketingCampaignCashListQuery()`
  * 现金活动详情查询：`client.MarketingCampaignCashDetailQuery()`
  * 订单优惠前置咨询：`client.MarketingCampaignOrderVoucherConsult()`
  * 创建商家券活动：`client.MarketingActivityOrderVoucherCreate()`
  * 同步商家券券码：`client.MarketingActivityOrderVoucherCodeDeposit()`
  * 修改商家活动券基本信息：`client.MarketingActivityOrderVoucherModify()`
  * 停止商家活动券：`client.MarketingActivityOrderVoucherStop()`
  * 修改商家活动券发券数量上限：`client.MarketingActivityOrderVoucherAppend()`
  * 同步券核销状态：`client.MarketingActivityOrderVoucherUse()`
  * 取消券核销状态：`client.MarketingActivityOrderVoucherRefund()`
  * 活动领取咨询接口：`client.MarketingActivityConsult()`
  * 查询商家券活动：`client.MarketingActivityOrderVoucherQuery()`
  * 查询活动详情：`client.MarketingActivityQuery()`
  * 统计商家券券码数量：`client.MarketingActivityOrderVoucherCodeCount()`
  * 条件查询活动列表：`client.MarketingActivityBatchQuery()`
  * 条件查询用户券：`client.MarketingActivityQueryUserBatchQueryVoucher()`
  * 查询用户券详情：`client.MarketingActivityQueryUserQueryVoucher()`
  * 查询活动可用小程序：`client.MarketingActivityQueryAppBatchQuery()`
  * 查询活动可用门店：`client.MarketingActivityQueryShopBatchQuery()`
  * 查询活动适用商品：`client.MarketingActivityQueryGoodsBatchQuery()`
  * 蚂蚁店铺创建：`client.AntMerchantShopCreate()`
  * 店铺查询接口：`client.AntMerchantShopQuery()`
  * 修改蚂蚁店铺：`client.AntMerchantShopModify()`
  * 蚂蚁店铺关闭：`client.AntMerchantShopClose()`
  * 商户申请单查询：`client.AntMerchantOrderQuery()`
  * 店铺分页查询接口：`client.AntMerchantShopPageQuery()`
  * 图片上传：`client.AntMerchantExpandIndirectImageUpload()`
  * 商户mcc信息查询：`client.AntMerchantExpandMccQuery()`
  * 店铺增加收单账号：`client.AntMerchantExpandShopReceiptAccountSave()`
  * 会员卡模板创建：`client.MarketingCardTemplateCreate()`
  * 会员卡模板查询接口：`client.MarketingCardTemplateQuery()`
  * 会员卡模板修改：`client.MarketingCardTemplateModify()`
  * 会员卡开卡表单模板配置：`client.MarketingCardFormTemplateSet()`
  * 会员卡查询：`client.MarketingCardQuery()`
  * 会员卡更新：`client.MarketingCardUpdate()`
  * 会员卡删卡：`client.MarketingCardDelete()`
  * 会员卡消息通知：`client.MarketingCardMessageNotify()`
  * 上传门店照片和视频接口：`client.OfflineMaterialImageUpload()`
  * 资金退回接口：`client.FundTransRefund()`
* <font color='#027AFF' size='4'>棋盘密云</font>
  * 上传创建人群：`client.MerchantQipanCrowdCreate()`
  * 人群中追加用户：`client.MerchantQipanCrowdUserAdd()`
  * 人群中删除用户：`client.MerchantQipanCrowdUserDelete()`
  * 棋盘人群圈选标签基本信息查询：`client.MarketingQipanTagBaseBatchQuery()`
  * 棋盘标签圈选值查询：`client.MarketingQipanTagQuery()`
  * 查询人群列表：`client.MarketingQipanCrowdBatchQuery()`
  * 查询人群详情：`client.MarketingQipanCrowdQuery()`
  * 修改人群：`client.MarketingQipanCrowdModify()`
  * 人群池创建：`client.MerchantQipanCrowdPoolCreate()`
  * 人群扩展接口：`client.MerchantQipanCrowdSpread()`
  * 上传创建灰黑产人群：`client.MerchantQipanGreyBlackCrowdCreate()`
  * 灰黑产人群中追加用户：`client.MerchantQipanGreyBlackCrowdUserAdd()`
  * 灰黑产人群中删除用户：`client.MerchantQipanGreyBlackCrowdUserDelete()`
* <font color='#027AFF' size='4'>图片素材</font>
  * 营销图片资源上传接口：`client.MarketingMaterialImageUpload()`
* <font color='#027AFF' size='4'>信用</font>
  * 芝麻GO签约预创单：`client.ZmGoPreorderCreate()`
  * 商家芝麻GO累计数据回传接口：`client.ZmGoCumulateSync()`
  * 商家芝麻GO累计数据查询接口：`client.ZmGoCumulateQuery()`
  * 芝麻GO结算申请：`client.ZmGoSettleApply()`
  * 芝麻GO结算退款：`client.ZmGoSettleRefund()`
  * 芝麻Go协议查询接口：`client.ZmGoAgreementQuery()`
  * 芝麻GO协议解约：`client.ZmGoAgreementQueryUnsign()`
  * 商户创建芝麻GO模板接口：`client.ZmGoTemplateCreate()`
  * 商家芝麻GO模板查询：`client.ZmGoTemplateQuery()`
* <font color='#027AFF' size='4'>广告</font>
  * 转化数据回传：`client.AdConversionUpload()`
  * 广告投放数据通用查询：`client.AdReportdataQuery()`
  * 自建推广页列表批量查询：`client.AdPromotepageBatchquery()`
  * 自建推广页留资数据查询：`client.AdPromotepageDownload()`
  * 任务广告完成状态查询接口：`client.XlightTaskQuery()`
  * 消费明细查询接口：`client.AdConsumehistoryQuery()`
  * 商品落地页信息创建或更新：`client.ProductLandinginfoCreateOrModify()`
  * 商品落地页信息查询：`client.ProductLandinginfoQuery()`
  * 广告代理商投放数据查询：`client.AdAgentreportdataQuery()`
* <font color='#027AFF' size='4'>小程序开发</font>
  * 小程序退回开发：`client.OpenMiniVersionAuditedCancel()`
  * 小程序灰度上架：`client.OpenMiniVersionGrayOnline()`
  * 小程序结束灰度：`client.OpenMiniVersionGrayCancel()`
  * 小程序上架：`client.OpenMiniVersionOnline()`
  * 小程序下架：`client.OpenMiniVersionOffline()`
  * 小程序回滚：`client.OpenMiniVersionRollback()`
  * 小程序删除版本：`client.OpenMiniVersionDelete()`
  * 小程序提交审核：`client.OpenMiniVersionAuditApply()`
  * 小程序基于模板上传版本：`client.OpenMiniVersionUpload()`
  * 查询使用模板的小程序列表：`client.OpenMiniTemplateUsageQuery()`
  * 小程序查询版本构建状态：`client.OpenMiniVersionBuildQuery()`
  * 小程序版本详情查询：`client.OpenMiniVersionDetailQuery()`
  * 小程序版本列表查询：`client.OpenMiniVersionListQuery()`
  * 小程序生成体验版：`client.OpenMiniExperienceCreate()`
  * 小程序体验版状态查询接口：`client.OpenMiniExperienceQuery()`
  * 小程序取消体验版：`client.OpenMiniExperienceCancel()`
* <font color='#027AFF' size='4'>小程序产品-订单中心</font>
  * 商品文件上传接口：`client.MerchantItemFileUpload()`

### 支付宝公共 API

---

### Doc Allinpay (`doc/allinpay.md`)

## 通联支付


- 通联支付：[官方文档中心](https://aipboss.allinpay.com/know/devhelp/index.php)



> 具体API使用介绍，请参考`gopay/allinpay/client_test.go`,`gopay/allinpay/pay_test.go` 等xxx_test.go

### 通联支付 API

* 统一支付接口(暂无账号为测试可用性)：`client.Pay()`
* 统一扫码接口: `client.ScanPay()`
* 撤销订单：`client.Cancel()`
* 交易退款：`client.Refund()`
* 交易结果查询：`client.Query()`
* 关闭订单：`client.Close()`
* 申请退款：`client.Refund()`

---

### Doc Apple (`doc/apple.md`)

## Apple

- App Store Server API：[官方文档](https://developer.apple.com/documentation/appstoreserverapi)

### 初始化Apple客户端

> 具体介绍，请参考 `gopay/apple/client_test.go`

```go
import (
    "github.com/go-pay/xlog"
    "github.com/go-pay/gopay/apple"
)

// 初始化通联客户端
// iss：issuer ID
// bid：bundle ID
// kid：private key ID
// privateKey：私钥文件读取后的字符串内容
// isProd：是否是正式环境
client, err = NewClient(iss, bid, kid, "privateKey", false)
if err != nil {
    xlog.Error(err)
    return
}
```


### Apple Pay 支付校验收据

* [苹果校验收据文档](https://developer.apple.com/documentation/appstorereceipts/verifyreceipt)

> url 请选择 apple.UrlSandbox 或 apple.UrlProd

* `apple.VerifyReceipt()` => 苹果支付校验收据API

---

#### 校验示例

```go
import (
    "github.com/go-pay/gopay/apple"
    "github.com/go-pay/xlog"
)

pwd := ""
receipt := ""
rsp, err := apple.VerifyReceipt(UrlSandbox, pwd, receipt)
if err != nil {
    xlog.Error(err)
    return
}
/**
  response body:
  {"receipt":{"original_purchase_date_pst":"2021-08-14 05:28:17 America/Los_Angeles", "purchase_date_ms":"1628944097586", "unique_identifier":"13f339a765b706f8775f729723e9b889b0cbb64e", "original_transaction_id":"1000000859439868", "bvrs":"10", "transaction_id":"1000000859439868", "quantity":"1", "in_app_ownership_type":"PURCHASED", "unique_vendor_identifier":"6DFDEA8B-38CE-4710-A1E1-BAEB8B66FEBD", "item_id":"1581250870", "version_external_identifier":"0", "bid":"com.huochai.main", "is_in_intro_offer_period":"false", "product_id":"10002", "purchase_date":"2021-08-14 12:28:17 Etc/GMT", "is_trial_period":"false", "purchase_date_pst":"2021-08-14 05:28:17 America/Los_Angeles", "original_purchase_date":"2021-08-14 12:28:17 Etc/GMT", "original_purchase_date_ms":"1628944097586"}, "status":0}
*/
if rsp.Receipt != nil {
    xlog.Infof("receipt:%+v", rsp.Receipt)
}
```

* [苹果服务端通知V2版本](https://developer.apple.com/documentation/appstoreservernotifications)

> 苹果支付服务服务端通知数据解析
> 对应App下 `[App 信息] --> [App Store 服务器通知]  --> [版本 2]` 配置对应的服务器地址,支付状态发生变化时Apple 将通过POST请求推送消息至配置的地址

#### 示例

- 请参考 `notification_v2_test.go`

```
/* Detailed source-code truncated for AI context efficiency. */
```

### App Store Server API Client Function

* `client.GetTransactionInfo()` => Get Transaction Info
* `client.GetTransactionHistory()` => Get Transaction History
* `client.GetAllSubscriptionStatuses()` => GetAllSubscriptionStatuses
* `client.SendConsumptionInformation()` => Send Consumption Information
* `client.GetNotificationHistory()` => Get Notification History
* `client.LookUpOrderId()` => Look Up Order ID
* `client.GetRefundHistory()` => Get Refund History

### Apple Function

* `apple.VerifyReceipt()` => 验证支付凭证
* `apple.ExtractClaims()` => 解析signedPayload
* `apple.DecodeSignedPayload()` => 解析notification signedPayload

---

### Doc Cmbpay (`doc/cmbpay.md`)

# cmbpay — 招商银行商户聚合支付 Go SDK

基于《招商银行商户聚合支付接口 V3.3.6》实现的 Go SDK，封装了报文组装、国密
（SM2/SM3/SM4）加验签、敏感信息加密数字信封、报文头 APP ID 校验、HTTP 调用与
异步通知验签等全部协议细节，让业务代码只需关注接口参数本身。

## 目录

- [特性](#特性)
- [安装](#安装)
- [快速开始](#快速开始)
- [配置说明](#配置说明)
- [示例程序](#示例程序)
- [完整支付闭环](#完整支付闭环)
- [敏感信息加密](#敏感信息加密)
- [异步通知](#异步通知)
- [调用未封装的接口](#调用未封装的接口)
- [错误处理](#错误处理)
- [已封装的类型化接口](#已封装的类型化接口)
- [注意事项](#注意事项)
- [常见问题](#常见问题)
- [测试](#测试)

## 特性

- **协议封装**：外层报文（`biz_content` / `encoding` / `signMethod` / `version` /
  `encryptKey` / `sign`）自动组装与解析（接口文档 2.2）。
- **国密加验签**：SM2withSM3 裸签名（USER_ID `1234567812345678`），请求加签、
  同步响应验签、异步通知验签（接口文档 2.4.1）。
- **敏感信息加密**：SM4 加密字段 + SM2 数字信封（`encryptKey`），一次请求多字段共用
  同一对称密钥（接口文档 2.4.4）。
- **报文头校验**：`appid` / `timestamp` / `apisign`（MD5）自动填充（接口文档 2.4.3）。
- **类型化接口**：收款码申请、支付查询、退款、退款查询、关单、付款码收款、撤销、
  微信统一下单等常用接口提供强类型方法；其余接口可用通用 `Execute` 调用。
- **异步通知**：`ParseNotify` 完成 form-data 验签并结构化，`NotifySuccessBody` /
  `NotifyFailBody` 生成标准应答（接口文档 2.5、4.3）。
- **错误处理**：`APIError` 区分通信层（`returnCode`）与业务层（`respCode`）错误，
  并提供 `IsSystemError()` 辅助识别需查询确认的 `SYSTERM_ERROR`（接口文档 2.2）。
- **并发安全**：`Client` 可在多个 goroutine 间共享。

## 安装

```bash
go get github.com/go-pay/gopay/cmbpay
```

国密算法（SM2 / SM3 / SM4）由 gopay 自有的 `github.com/go-pay/crypto` 提供，
仅使用 Go 标准库实现，不引入第三方国密库。

## 快速开始

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/go-pay/gopay/cmbpay"
)

func main() {
	client, err := cmbpay.NewClient(cmbpay.Config{
		Host:               cmbpay.HostProd, // 联调环境用 cmbpay.HostUAT
		AppID:              "<APP ID>",
		AppSecret:          "<APP SECRET>",
		MerID:              "<商户号>",
		PrivateKeyHex:      "<商户 SM2 私钥 HEX，64 字符>",
		CMBPublicKeyBase64: "<招行 SM2 公钥 Base64>",
	})
	if err != nil {
		log.Fatal(err)
	}

	// 收款码申请（金额单位：分）
	resp, err := client.QrCodeApply(context.Background(), &cmbpay.QrCodeApplyReq{
		MerID:     client.MerID(),
		OrderID:   "your-unique-order-id", // 商户下唯一
		UserID:    "cashier-id",
		NotifyURL: "https://your.domain/cmb/notify",
		TxnAmt:    "1", // 1 分
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("二维码:", resp.QrCode, "平台订单号:", resp.CmbOrderID)
}
```

## 配置说明

`cmbpay.Config` 字段：

| 字段 | 必填 | 说明 |
|------|:---:|------|
| `Host` | 是 | 服务器地址。生产 `cmbpay.HostProd`，联调 `cmbpay.HostUAT` |
| `AppID` | 是 | 聚合收单平台分配的 APP ID（报文头身份标识） |
| `AppSecret` | 是 | 聚合收单平台分配的 APP SECRET（用于报文头加签，不上送） |
| `MerID` | 是 | 招行商户号 |
| `PrivateKeyHex` | 是 | 商户 SM2 私钥，64 字符 HEX，用于报文体加签 |
| `CMBPublicKeyBase64` | 是 | 招行 SM2 公钥，Base64（ASN.1），用于报文体/通知验签 |
| `BillCheckHost` | 否 | 对账文件接口地址（`BillCheckHostPRD` / `BillCheckHostUAT`）。仅调用 `BillRecord` 时需要，其主机地址与支付接口不同 |
| `HTTPClient` | 否 | 自定义 `*http.Client`；为 nil 时使用带 30s 超时的默认客户端 |
| `DebugSwitch` | 否 | 置为 `gopay.DebugOn` 时打印请求与响应报文，可用 `client.SetLogger` 替换日志实现 |

> 联调环境的示例 AppID / AppSecret / 商户私钥 / 招行公钥见接口文档附录 1，
> 本仓库示例在未设置环境变量时会回退到这些参数，可直接体验。

## 示例程序

`example/` 目录提供了 3 个可独立运行的示例，均通过 `example/config` 读取配置
（优先环境变量，回退到联调示例参数）：

```bash
# 完整支付闭环：收款码申请 → 轮询查询 → 关单/退款 → 退款查询 + 付款码加密收款
go run ./example/payment

# 异步通知接收服务（验签 + 幂等 + 标准应答），监听 :8080
go run ./example/notifyserver

# 通用方式调用未封装的接口（银联云闪付、数字人民币统一下单等）
go run ./example/generic
```

指定真实商户参数运行：

```bash
export CMB_ENV=prod
export CMB_APPID=... CMB_APPSECRET=... CMB_MERID=...
export CMB_PRIVKEY=...   # 64 字符 HEX
export CMB_CMBPUBKEY=... # Base64
export CMB_NOTIFYURL=https://your.domain/cmb/notify
go run ./example/payment
```

## 完整支付闭环

```go
ctx := context.Background()
const cashier = "N003109945"
orderID := "your-unique-order-id"

// 1. 收款码申请
qr, err := client.QrCodeApply(ctx, &cmbpay.QrCodeApplyReq{
	MerID: client.MerID(), OrderID: orderID, UserID: cashier,
	NotifyURL: "https://your.domain/cmb/notify", TxnAmt: "1",
})

// 2. 支付结果查询（建议 15s 后首查，之后每 5-10s 一次；遇 SYSTERM_ERROR 继续查）
st, err := client.OrderQuery(ctx, &cmbpay.OrderQueryReq{
	MerID: client.MerID(), OrderID: orderID, UserID: cashier,
})
switch st.TradeState {
case cmbpay.TradeStateSuccess: // "S" 交易成功
case cmbpay.TradeStateProcess: // "P" 进行中，继续轮询
	// ...
}

// 3. 未支付则关单，可用新订单号重新发起
client.Close(ctx, &cmbpay.CloseReq{MerID: client.MerID(), OrderID: orderID, UserID: cashier})

// 4. 已支付则退款 + 退款查询
client.Refund(ctx, &cmbpay.RefundReq{
	MerID: client.MerID(), OrderID: "refund-unique-id",
	CmbOrderID: st.CmbOrderID, UserID: cashier, RefundAmt: "1",
})
client.RefundQuery(ctx, &cmbpay.RefundQueryReq{
	MerID: client.MerID(), OrderID: "refund-unique-id", UserID: cashier,
})
```

完整可运行版本见 [`example/payment/main.go`](example/payment/main.go)。

## 敏感信息加密

对 `terminalInfo`、实名支付信息等需加密的字段，先用 `Encryptor` 加密，再用带
`...Encrypted` 后缀的方法（或 `ExecuteEncrypted`）发送，SDK 会自动生成数字信封
（`encryptKey`）。同一次请求的多个敏感字段共用同一个 `Encryptor`：

```go
enc, _ := cmbpay.NewEncryptor() // 生成随机 SM4 密钥
cipher, _ := enc.Encrypt(`{"location":"+37.12/-121.213","mobile_country_cd":"460"}`)

resp, err := client.PayEncrypted(ctx, &cmbpay.PayReq{
	MerID:               client.MerID(),
	OrderID:             "order-id",
	UserID:              "cashier-id",
	AuthCode:            "134650123456789012",
	TxnAmt:              "1",
	EncryptTerminalInfo: cipher, // 填入密文
}, enc)
```

## 异步通知

招行以 form-data POST 推送支付/退款结果通知。处理要点：**验签 → 幂等判重 →
更新业务 → 返回标准应答**。

```go
func notifyHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	data, err := client.ParseNotify(r) // 自动验签并结构化
	if err != nil {
		body, _ := client.NotifyFailBody("verify failed") // 返回 FAIL，招行会重试
		w.Write(body)
		return
	}

	// 幂等：同一通知可能重复投递，处理前先查本地状态
	if alreadyProcessed(data.OrderID) {
		body, _ := client.NotifySuccessBody()
		w.Write(body)
		return
	}

	if data.IsPaySuccess() { // 仅当通知明确带 tradeState=S 时为 true
		// 更新本地订单为已支付、发货等
	}

	// 加签失败时不可返回未加签的报文（招行会判定无效），应返回 5xx 让招行重试
	body, err := client.NotifySuccessBody() // {"returnCode":"SUCCESS","respCode":"SUCCESS",...}
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(body)
}
```

> `IsPaySuccess()` 只在 `tradeState=S` 时返回 `true`。若通知未携带 `tradeState`
> （如退款通知），请调用 `OrderQuery` 查询订单确认真实状态，切勿直接入账。

未使用 `net/http` 时可用 `client.ParseNotifyValues(url.Values)`。完整可运行版本见
[`example/notifyserver/main.go`](example/notifyserver/main.go)。

## 调用未封装的接口

SDK 为常用接口提供了类型化方法；其余接口（数字人民币、微信支付分、支付宝 APP/WAP、
银联云闪付等，路径常量见 [`endpoints.go`](endpoints.go)）可用通用方法调用，请求体可用
`map` 或自定义结构体：

```go
// 请求体用结构体，响应解析到结构体
type ecnyResp struct {
	CmbOrderID string `json:"cmbOrderId"`
	QrCode     string `json:"qrCode"`
}
var out ecnyResp
err := client.Execute(ctx, cmbpay.PathEcnyUnifiedOrder, map[string]string{
	"merId":     client.MerID(),
	"orderId":   "unique-id",
	"userId":    "cashier-id",
	"notifyUrl": "https://your.domain/cmb/notify",
	"txnAmt":    "1",
}, &out)

// 含敏感字段时用 ExecuteEncrypted
err = client.ExecuteEncrypted(ctx, cmbpay.PathXxx, reqWithCipher, enc, &out)
```

完整可运行版本见 [`example/generic/main.go`](example/generic/main.go)。

## 错误处理

招行返回分通信层（`returnCode`）与业务层（`respCode`）两级。当任一为 FAIL 时，
SDK 返回 `*cmbpay.APIError`：

```go
resp, err := client.OrderQuery(ctx, req)
if err != nil {
	var apiErr *cmbpay.APIError
	if errors.As(err, &apiErr) {
		switch {
		case apiErr.IsSystemError():
			// errCode=SYSTERM_ERROR：交易结果不明确，需继续发起查询确认（接口文档 2.2）
		case apiErr.IsCommFail():
			// returnCode=FAIL：报文不合规范（字段超长、非法字符、签名错误等）
		default:
			// 业务失败，查看 apiErr.ErrCode / apiErr.RespMsg
		}
	} else {
		// 网络错误、验签失败、序列化错误等
	}
}
```

## 已封装的类型化接口

带 `Encrypted` 后缀的方法用于请求含需加密敏感字段（如 `encryptTerminalInfo`、
`encryptIdentity`）的场景，会自动生成数字信封。

| 方法 | 说明 | 文档章节 |
|------|------|----------|
| `QrCodeApply` / `QrCodeApplyEncrypted` | 收款码申请 | 4.1 |
| `OrderQuery` | 支付结果查询 | 4.2 |
| `Refund` | 退款申请 | 4.4 |
| `RefundQuery` | 退款结果查询 | 4.5 |
| `Close` | 关闭订单 | 4.7 |
| `Pay` / `PayEncrypted` | 付款码收款 | 4.8 |
| `Cancel` | 付款码支付撤销 | 4.9 |
| `OnlinePay` | 微信统一下单 | 4.10 |
| `ServPay` / `ServPayEncrypted` | 服务窗支付 | 4.11 |
| `ZfbNative` / `ZfbNativeEncrypted` | 支付宝 native 码支付 | 4.12 |
| `BillRecord` | 对账单下载地址获取，和下单/查单接口签名规则不一样，需配置 `BillCheckHost` 或传入专用主机地址 | - |
| `OrderQrCodeApply` / `OrderQrCodeApplyEncrypted` | 订单二维码申请 | 4.14 |
| `MiniAppOrder` / `MiniAppOrderEncrypted` | 微信小程序下单 | 4.15 |
| `CloudPay` | 银联云闪付 | 4.16 |
| `EcnyUnifiedOrder` | 数字人民币统一下单 | 4.17 |
| `EcnyUnifiedPayment` | 数字人民币统一支付 | 4.18 |
| `EcnySubwalletPay` | 数字人民币子钱包支付 | 4.19 |
| `EcnyContractSubwalletPay` | 数字人民币子钱包支付-带合约 | 4.20 |
| `EcnyContractUnifiedOrder` | 数字人民币统一下单-带合约 | 4.21 |
| `PapQuery` | 微信委托代扣查询 | 4.23 |
| `ZfbApp` / `ZfbAppEncrypted` | 支付宝 APP 支付 | 4.24 |
| `ZfbWap` / `ZfbWapEncrypted` | 支付宝手机网站支付 | 4.25 |
| `OpenIDQuery` | 微信授权码查询 openid | 4.37 |

其余接口（微信委托代扣下单、微信支付分系列、智能合约分账、先享后付等）路径见
[`endpoints.go`](endpoints.go)，通过 `Execute` / `ExecuteEncrypted` 调用。

## 注意事项

- **金额单位为分**，字符串传输，不含小数点（接口文档 2.3）。
- **商户订单号需全局唯一**；重发同一笔支付请使用原订单号避免重复支付；已支付/已关单/
  已撤销的订单号不能重新发起支付。
- **必须实现查询机制**：网络异常导致未收到通知时，商户须主动查询直至结果明确，
  否则风险自负（接口文档 2.2、4.2）。
- **`SYSTERM_ERROR` 不等于失败**：支付/退款/查询遇到该错误时交易结果不明确，
  应继续查询确认，而非直接判失败（接口文档 2.2 第 9、10 条）。
- **通知需幂等**：同一通知可能重复投递，处理前请加锁并检查业务状态；处理成功后
  必须返回 `SUCCESS`，否则招行按 `0/15/15/30/180/1800...` 秒的策略重试（接口文档 2.5）。
- **回调地址需提前报备**：招行到商户回调地址的网络开通约需 2-3 个工作日。
- **测试环境二维码**需将 `https://qr.95516.com` 替换为
  `http://payment-uat.cs.cmburl.cn` 再生成图片（接口文档附录 1）。

## 常见问题

**Q：验签失败怎么排查？**
A：确认 `CMBPublicKeyBase64` 是招行公钥（用于验签）而非商户自己的公钥；确认私钥为
32 字节、64 字符 HEX。同步响应验签中，SDK 已按接口文档 2.4.1.2 对 `/` 做 `\/` 转义。

**Q：如何切换联调 / 生产环境？**
A：仅需改 `Config.Host` 为 `cmbpay.HostUAT` 或 `cmbpay.HostProd`，其余不变。

**Q：请求超时时间如何设置？**
A：两种方式——传入自定义 `Config.HTTPClient`，或在调用方法时传入带 `context.WithTimeout`
的 `ctx`（推荐，可按请求粒度控制）。

**Q：SDK 覆盖了全部接口吗？**
A：常用接口提供类型化方法，全部接口路径（含数字人民币、微信支付分、支付宝系列等）
均在 `endpoints.go` 中，可用 `Execute` / `ExecuteEncrypted` 调用。

## 测试

```bash
go test ./...
```

---

### Doc Douyin (`doc/douyin.md`)

## 抖音支付

> 抖音支付 SDK 面向直连商户，覆盖基础支付、账单、分账、转账及相关回调通知。

- 已实现API列表附录：[API 列表附录](https://github.com/go-pay/gopay/blob/main/doc/douyin.md#%E9%99%84%E5%BD%95)

- 抖音官方文档入口：[抖音支付开放平台](https://pay.douyinpay.com/wiki/)

- 通用签名认证 / 敏感字段加密 / 回调解密规则：请以官方文档为准

---

### 1、初始化抖音支付客户端并做配置

> 抖音支付无沙箱环境，测试请使用正式环境 1 分钱测试法。

> 具体 API 使用介绍，请参考 `gopay/examples/douyin/douyin.go`。

```go
import (
    "github.com/go-pay/xlog"
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/douyin"
)

// NewClient 初始化抖音支付客户端
// mchid：商户号
// serialNo：商户 API 证书序列号
// apiKey：接口加密密钥（32 字节，用于回调 AES-256-GCM 解密）
// privateKey：商户 API 私钥 apiclient_key.pem 内容
client, err := douyin.NewClient(Mchid, SerialNo, ApiKey, PrivateKey)
if err != nil {
    xlog.Error(err)
    return
}

// 注册抖音支付平台证书（可多次调用注册多张，签名头 Douyinpay-Serial 会自动带最新一张）
// 抖音无平台证书自动拉取接口，请从抖音支付商户后台或运营处获取后手动注册
if err = client.SetPlatformCert([]byte(PlatformCertPEM), PlatformCertSerial); err != nil {
    xlog.Error(err)
    return
}

// 打开 Debug 开关，输出日志（默认关闭）
client.DebugSwitch = gopay.DebugOn

// 可选：自定义 xhttp.Client / Logger / 代理
// client.SetHttpClient(hc)
// client.SetLogger(logger)
// client.SetProxyHost("https://your-proxy.internal")
```

---

### 2、基础支付

四类下单接口结构一致（`bm gopay.BodyMap` 直接组装官方 body 字段，`mchid` 未设置时自动填 `client.Mchid`）：

```go
// App 下单
rsp, err := client.AppOrder(ctx, bm)         // rsp.Response.PrepayId
// JSAPI 下单
rsp, err := client.JsapiOrder(ctx, bm)       // rsp.Response.PrepayId
// H5 下单（响应直接返回 h5_url）
rsp, err := client.H5Order(ctx, bm)          // rsp.Response.H5Url
// Native 下单（响应直接返回二维码 code_url）
rsp, err := client.NativeOrder(ctx, bm)      // rsp.Response.CodeUrl
```

前端调起签名：

```go
appParams, err   := client.PaySignOfApp(appid, prepayId)   // App 端
jsapiParams, err := client.PaySignOfJSAPI(appid, prepayId) // JSAPI/小程序
```

订单查询 & 关单：

```go
q1, err := client.OrderQueryByTransactionId(ctx, "TP20221013...") // 抖音支付订单号
q2, err := client.OrderQueryByOutTradeNo(ctx, "OUT_XXX")          // 商户订单号
_,  err := client.CloseOrder(ctx, "OUT_XXX", nil)                 // 关单
```

退款：

```go
r1, err := client.Refund(ctx, bm)                            // 申请退款
r2, err := client.RefundQuery(ctx, "REF_XXX", mchid, appid)  // 查询退款
```

---

### 3、账单

三种账单 + 通用下载器 + 完整性校验：

```go
tradeBM  := gopay.BodyMap{"bill_date": "2026-06-30"} // bill_type 默认 TRADE，tar_type 默认 GZIP
fundBM   := gopay.BodyMap{"bill_date": "2026-06-30", "account_type": "BaseAccount"}
profitBM := gopay.BodyMap{"bill_date": "2026-06-30"}

tRsp, _ := client.ApplyTradeBill(ctx, tradeBM)
fRsp, _ := client.ApplyFundBill(ctx, fundBM)
pRsp, _ := client.ApplyProfitBill(ctx, profitBM)

// 下载 + 解压 + SHA1 校验
gz,   _ := client.DownloadBillFile(ctx, tRsp.Response.DownloadUrl)
raw,  _ := douyin.UngzipBill(gz)
err     := douyin.VerifyBillHash(raw, tRsp.Response.HashType, tRsp.Response.HashValue)
```

---

### 4、分账

```go
// 敏感字段先加密（type=MERCHANT_ID 时 name 必传）
encName, _ := client.EncryptText("接收方商户名称")

// 请求分账（异步受理）
rsp, _ := client.ProfitRequest(ctx, gopay.BodyMap{
    "appid":            "your_appid",
    "transaction_id":   "TP20221013...",
    "out_order_no":     "SPLIT_XXX",
    "unfreeze_unsplit": false,
    "notify_url":       "https://your.callback",
    "receivers": []douyin.ProfitReceiverReq{
        {Type: "MERCHANT_ID", Account: "6020...", Name: encName, Amount: 100, Description: "分账"},
    },
})

// 查询分账
_, _ = client.ProfitQuery(ctx, "SPLIT_XXX", gopay.BodyMap{"transaction_id": "TP..."})
// 完结分账
_, _ = client.ProfitComplete(ctx, gopay.BodyMap{"transaction_id": "TP...", "out_order_no": "FIN_XXX", "description": "完结"})
// 分账回退 / 回退查询
_, _ = client.ProfitRollback(ctx, gopay.BodyMap{...})
_, _ = client.ProfitRollbackQuery(ctx, "OUT_RETURN_XXX", gopay.BodyMap{"out_order_no": "SPLIT_XXX"})
// 剩余待分账余额
_, _ = client.ProfitBalanceQuery(ctx, "TP...", "") // mchid 传 "" 默认使用 client.Mchid
// 接收方管理
_, _ = client.ProfitReceiverAdd(ctx, gopay.BodyMap{"appid": "...", "type": "MERCHANT_ID", "account": "...", "name": encName, "relation_type": "STORE"})
_, _ = client.ProfitReceiverDelete(ctx, gopay.BodyMap{"appid": "...", "type": "MERCHANT_ID", "account": "..."})
```

---

### 5、转账（商户转账到零钱）

```go
// ≥2000.00 元时 user_name 必填，需先加密
encUserName, _ := client.EncryptText("张三")

rsp, _ := client.Transfer(ctx, gopay.BodyMap{
    "appid":             "your_appid",
    "out_bill_no":       "OUT_XXX",
    "transfer_scene_id": "SCENE_001",
    "openid":            "oUpF8uMEB4jR",
    "user_name":         encUserName,
    "transfer_amount":   100,
    "transfer_remark":   "商户转账",
    "notify_url":        "https://your.callback",
})

// 查询（两种维度）
_, _ = client.TransferQueryByTransferBillNo(ctx, rsp.Response.TransferBillNo)
_, _ = client.TransferQueryByOutBillNo(ctx, rsp.Response.OutBillNo)
```

---

### 6、回调通知处理

```go
// 1) 解析请求为 NotifyReq（内含 SignInfo）
notifyReq, err := douyin.ParseNotify(req)
if err != nil { /* ... */ }

// 2) 验签（按 header Douyinpay-Serial 匹配已注册的平台证书）
if err := notifyReq.VerifySignByPKMap(client.PlatformCertMap()); err != nil {
    // 验签失败：返回失败应答
    return
}

// 3) 根据 event_type 解密对应载荷
switch notifyReq.EventType {
case douyin.EventTransactionSuccess:      // TRANSACTION.SUCCESS
    pay, err := notifyReq.DecryptPayCipherText(ApiKey)
    _ = pay; _ = err
case douyin.EventRefundSuccess:           // REFUND.SUCCESS
    r, err := notifyReq.DecryptRefundCipherText(ApiKey)
    _ = r; _ = err
case douyin.EventAsyncSplitFinish:        // ASYNC_SPLIT.FINISH（分账结果）
    s, err := notifyReq.DecryptProfitResultCipherText(ApiKey)
    _ = s; _ = err
case douyin.EventSplitSuccess:            // SPLIT.SUCCESS（分账动账）
    d, err := notifyReq.DecryptProfitDynamicCipherText(ApiKey)
    _ = d; _ = err
case douyin.EventTransferSuccess:         // TRANSFER.SUCCESS
    t, err := notifyReq.DecryptTransferCipherText(ApiKey)
    _ = t; _ = err
}
```

---

### 7、敏感字段加解密（RSA-PKCS1v15）

抖音支付敏感字段（接收方姓名、转账收款人姓名等）走 **RSA-PKCS1v15**（注意与微信 V3 的 OAEP 不同）：

```go
// 加密：使用抖音支付平台证书公钥
cipher, err := client.EncryptText("张三")

// 解密：使用商户私钥
plain,  err := client.DecryptText(cipher)
```

---

## 附录：

### 抖音支付 API

* <font color='#07C160' size='4'>基础支付</font>
    * APP下单：`client.AppOrder()`
    * JSAPI/小程序下单：`client.JsapiOrder()`
    * H5下单：`client.H5Order()`
    * Native下单：`client.NativeOrder()`
    * App端调起支付签名：`client.PaySignOfApp()`
    * JSAPI前端调起支付签名：`client.PaySignOfJSAPI()`
    * 抖音支付订单号查询订单：`client.OrderQueryByTransactionId()`
    * 商户订单号查询订单：`client.OrderQueryByOutTradeNo()`
    * 关闭订单：`client.CloseOrder()`
* <font color='#07C160' size='4'>退款</font>
    * 申请退款：`client.Refund()`
    * 查询单笔退款（通过商户退款单号）：`client.RefundQuery()`
* <font color='#07C160' size='4'>账单</font>
    * 申请交易账单：`client.ApplyTradeBill()`
    * 申请资金账单：`client.ApplyFundBill()`
    * 申请分账账单：`client.ApplyProfitBill()`
    * 下载账单文件（跨域名，自动签名）：`client.DownloadBillFile()`
    * GZIP账单解压：`douyin.UngzipBill()`
    * SHA1完整性校验：`douyin.VerifyBillHash()`
* <font color='#07C160' size='4'>分账</font>
    * 请求分账（异步受理）：`client.ProfitRequest()`
    * 查询分账结果：`client.ProfitQuery()`
    * 请求分账回退：`client.ProfitRollback()`
    * 查询分账回退结果：`client.ProfitRollbackQuery()`
    * 完结分账：`client.ProfitComplete()`
    * 查询订单剩余待分账金额：`client.ProfitBalanceQuery()`
    * 添加分账接收方：`client.ProfitReceiverAdd()`
    * 删除分账接收方：`client.ProfitReceiverDelete()`
* <font color='#07C160' size='4'>转账（商户转账到零钱）</font>
    * 发起转账：`client.Transfer()`
    * 商户订单号查询转账单：`client.TransferQueryByOutBillNo()`
    * 抖音转账单号查询转账单：`client.TransferQueryByTransferBillNo()`
* <font color='#07C160' size='4'>客户端基础设施</font>
    * 初始化客户端：`douyin.NewClient()`
    * 注册抖音支付平台证书（多证书）：`client.SetPlatformCert()`
    * 获取已注册平台证书 map：`client.PlatformCertMap()`
    * 获取最新平台证书序列号：`client.NewestPlatformSerialNo()`
    * 设置自定义 xhttp.Client：`client.SetHttpClient()`
    * 设置自定义 Logger：`client.SetLogger()`
    * 设置代理域名：`client.SetProxyHost()`
    * 设置响应体大小上限：`client.SetBodySize()`
* <font color='#07C160' size='4'>敏感字段加解密（RSA-PKCS1v15）</font>
    * 加密（平台证书公钥）：`client.EncryptText()`
    * 解密（商户私钥）：`client.DecryptText()`
    * 包级加密：`douyin.EncryptText()`
    * 包级解密：`douyin.DecryptText()`
* <font color='#07C160' size='4'>回调通知（解析 / 验签 / 解密）</font>
    * 解析回调为结构体：`douyin.ParseNotify()`
    * 解析回调为 BodyMap：`douyin.ParseNotifyToBodyMap()`
    * 指定公钥验签：`(v *NotifyReq).VerifySignByPK()`
    * 按 Serial 匹配公钥 map 验签：`(v *NotifyReq).VerifySignByPKMap()`
    * 通用密文解密到任意结构体：`(v *NotifyReq).DecryptCipherTextToStruct()`
    * 支付成功通知解密（`TRANSACTION.SUCCESS`）：`(v *NotifyReq).DecryptPayCipherText()`
    * 退款结果通知解密（`REFUND.SUCCESS`）：`(v *NotifyReq).DecryptRefundCipherText()`
    * 分账结果通知解密（`ASYNC_SPLIT.FINISH`）：`(v *NotifyReq).DecryptProfitResultCipherText()`
    * 分账动账通知解密（`SPLIT.SUCCESS`）：`(v *NotifyReq).DecryptProfitDynamicCipherText()`
    * 转账结果通知解密（`TRANSFER.SUCCESS`）：`(v *NotifyReq).DecryptTransferCipherText()`
    * 通用回调密文解字节：`douyin.DecryptNotifyCipherTextToBytes()`
    * 通用回调密文解到结构体：`douyin.DecryptNotifyCipherTextToStruct()`

---

### Doc Lakala (`doc/lakala.md`)

## 拉卡拉网关支付

- 拉卡拉网关支付：[官方文档中心](https://payjp.lakala.com/docs/cn)

### 回调通知解析

```
notifyReq, err := lakala.ParseNotify()
if err != nil {
    xlog.Error(err)
    return
}
```

### 拉卡拉 API

* <font color='#07C160' size='4'>QRCode</font>
    * 创建QRCode支付单：`client.CreateQRCodeOrder()`
    * 创建Native QRCode支付单：`client.CreateNativeQRCodeOrder()`
    * QRCode支付跳转页：`client.QRCodePay()`
* <font color='#07C160' size='4'>JSAPI</font>
    * 创建JSAPI订单：`client.CreateJSAPIOrder()`
    * 创建Native JSAPI订单(offline)：`client.CreateNativeJSApiOrder()`
    * 微信JSAPI支付跳转页：`client.JSAPIWechatPay()`
    * 支付宝JSAPI支付跳转页：`client.JSAPIAlipayPay()`
    * Alipay+ JSAPI支付跳转页：`client.JSAPIAlipayPlusPay()`
* <font color='#07C160' size='4'>MobileH5</font>
    * 创建H5支付单：`client.CreateH5PayOrder()`
    * H5支付跳转页：`client.H5Pay()`
    * H5支付跳转页(Alipay+)：`client.H5AlipayPlusPay()`
* <font color='#07C160' size='4'>Miniprogram Payment</font>
    * 创建小程序订单：`client.CreateMiniProgramOrder()`
* <font color='#07C160' size='4'>Channel Web Gateway</font>
    * 创建渠道Web网关订单：`client.CreateWebGatewayOrder()`
* <font color='#07C160' size='4'>SDKPayment</font>
    * 创建SDK订单(Online)：`client.CreateSDKPaymentOrder()`
* <font color='#07C160' size='4'>CommonApi</font>
    * 获取当前汇率：`client.GetExchangeRate()`
    * 获取加密密钥：`client.GetEncrypt()`
    * 关闭订单：`client.CloseOrder()`
    * 查询订单状态：`client.OrderStatus()`
    * 申请退款：`client.ApplyRefund()`
    * 查询退款状态：`client.RefundQuery()`
    * 查看订单：`client.OrderList()`
    * 查看账单流水：`client.TransactionList()`
    * 查看清算详情：`client.Settlements()`
    * 查询可用钱包：`client.ConsultPayment()`
    * 获取优惠券信息：`client.GetCoupon()`
* <font color='#07C160' size='4'>Custom</font>
    * 创建报关单（非拆单）：`client.CreateReportSingle()`
    * 创建报关单（拆单）：`client.CreateReportSeparate()`
    * 报关状态查询：`client.ReportStatus()`
    * 报关子单状态查询：`client.ReportSubStatus()`
    * 修改报关信息（非拆单）：`client.ModifyReportSingle()`
    * 修改报关信息（拆单）：`client.ModifyReportSeparate()`
    * 重推报关（非拆单）：`client.ResendReportSingle()`
    * 报关单子单重推：`client.ResendReportSeparate()`

---

### Doc Paypal (`doc/paypal.md`)

## PayPal

> 具体API使用介绍，请参考`gopay/paypal/client_test.go`,`gopay/paypal/order_test.go`,`gopay/paypal/payment_test.go` 等xxx_test.go

- 已实现API列表附录：[API List](https://github.com/go-pay/gopay/blob/main/doc/paypal.md#%E9%99%84%E5%BD%95)

- PayPal官方文档：[Official Document](https://developer.paypal.com/api/rest)

---

### 1、初始化PayPal客户端并做配置（Init PayPal Client）

```go
import (
    "github.com/go-pay/gopay/paypal"
    "github.com/go-pay/xlog"
)

// 初始化PayPal支付客户端
client, err := paypal.NewClient(Clientid, Secret, false)
if err != nil {
    xlog.Error(err)
    return
}

// 自定义配置http请求接收返回结果body大小，默认 10MB
client.SetBodySize() // 没有特殊需求，可忽略此配置

// 打开Debug开关，输出日志，默认关闭
client.DebugSwitch = gopay.DebugOn
```

### 2、API 方法调用及入参（Call API）

> Orders：[Orders API](https://developer.paypal.com/api/orders/v2/)

> Payments：[Payments API](https://developer.paypal.com/api/payments/v2/)

> Subscriptions：[Subscriptions API](https://developer.paypal.com/docs/api/subscriptions/v1/)

- Create Orders example

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/paypal"
    "github.com/go-pay/util"
    "github.com/go-pay/xlog"
)

// Create Orders example
var pus []*paypal.PurchaseUnit
var item = &paypal.PurchaseUnit{
	ReferenceId: util.GetRandomString(16),
	Amount: &paypal.Amount{
		CurrencyCode: "USD",
		Value:        "8",
	},
}
pus = append(pus, item)

bm := make(gopay.BodyMap)
bm.Set("intent", "CAPTURE").
	Set("purchase_units", pus).
	SetBodyMap("payment_source", func(b gopay.BodyMap) {
		b.SetBodyMap("paypal", func(bb gopay.BodyMap) {
			bb.SetBodyMap("experience_context", func(bbb gopay.BodyMap) {
				bbb.Set("brand_name", "gopay").
					Set("locale", "en-US").
					Set("shipping_preference", "NO_SHIPPING").
					Set("user_action", "PAY_NOW").
					Set("return_url", "http://xxx/return").
					Set("cancel_url", "http://xxx/cancel")
			})
		})
	})
ppRsp, err := client.CreateOrder(ctx, bm)
if err != nil {
	xlog.Error(err)
	return
}
if ppRsp.Code != 200 {
	// do something
	return
}
```

- Capture payment for order

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/xlog"
)

// Capture payment for order
//bm := make(gopay.BodyMap)
//bm.SetBodyMap("payment_source", func(b gopay.BodyMap) {
//	b.SetBodyMap("token", func(b gopay.BodyMap) {
//		b.Set("id", "The PayPal-generated ID for the token").
//			Set("type", "BILLING_AGREEMENT")
//	})
//})
ppRsp, err := client.OrderCapture(ctx, "4X223967G91314611", nil)
if err != nil {
    xlog.Error(err)
    return
}
if ppRsp.Code != paypal.Success {
    // do something
    return
}
```

---

## 附录：

### PayPal API

* <font color='#003087' size='4'>AccessToken</font>
  * 获取AccessToken（Get AccessToken）：`client.GetAccessToken()`
* <font color='#003087' size='4'>Invoices</font>
	* 生成发票号码（Generate invoice number）：`client.InvoiceNumberGenerate()`
	* 发票列表（List invoices）：`client.InvoiceList()`
	* 创建虚拟发票（Create draft invoice）：`client.InvoiceCreate()`
	* 删除发票（Delete invoice）：`client.InvoiceDelete()`
	* 更新发票（Fully update invoice）：`client.InvoiceUpdate()`
	* 获取发票详情（Show invoice details）：`client.InvoiceDetail()`
	* 生成发票二维码（Generate QR code）：`client.InvoiceGenerateQRCode()`
	* 发票付款记录（Record payment for invoice）：`client.InvoicePaymentRecord()`
	* 发票付款删除（Delete external payment）：`client.InvoicePaymentDelete()`
	* 发票退款记录（Record refund for invoice）：`client.InvoiceRefundRecord()`
	* 发票退款删除（Delete external refund）：`client.InvoiceRefundDelete()`
	* 发送发票提醒（Send invoice reminder）：`client.InvoiceSendRemind()`
	* 发送发票（Send invoice）：`client.InvoiceSend()`
	* 发票搜索（Search for invoices）：`client.InvoiceSearch()`
	* 发票模板列表（List templates）：`client.InvoiceTemplateList()`
	* 创建发票模板（Create template）：`client.InvoiceTemplateCreate()`
	* 发票模板详情（Show template details）：`client.InvoiceTemplateDetail()`
	* 删除发票模板（Delete template）：`client.InvoiceTemplateDelete()`
	* 更新发票模板（Fully update template）：`client.InvoiceTemplateUpdate()`
* <font color='#003087' size='4'>Orders</font>
  * 创建订单（Create order）：`client.CreateOrder()`
  * 订单详情（Show order details）：`client.OrderDetail()`
  * 更新订单（Update order）：`client.UpdateOrder()`
  * 订单支付授权（Authorize payment for order）：`client.OrderAuthorize()`
  * 订单支付捕获（Capture payment for order）：`client.OrderCapture()`
  * 订单支付确认（Confirm the Order）：`client.OrderConfirm()`
  * 支持内联订阅计划（循环扣款 / 保存支付方式 / 分期）：`Item.BillingPlan`（类型 `OrderBillingPlan` / `OrderBillingCycle`）
* <font color='#003087' size='4'>Payments</font>
  * 支付授权详情（Show details for authorized payment）：`client.PaymentAuthorizeDetail()`
  * 重新授权支付授权（Reauthorize authorized payment）：`client.PaymentReauthorize()`
  * 作废支付授权（Void authorized payment）：`client.PaymentAuthorizeVoid()`
  * 支付授权捕获（Capture authorized payment）：`client.PaymentAuthorizeCapture()`
  * 支付捕获详情（Show captured payment details）：`client.PaymentCaptureDetail()`
  * 支付捕获退款（Refund captured payment）：`client.PaymentCaptureRefund()`
  * 支付退款详情（Show refund details）：`client.PaymentRefundDetail()`
  * 可用支付方式查询（Find eligible payment methods）：`client.FindEligiblePaymentMethods()`
* <font color='#003087' size='4'>Payment Method Tokens</font>
  * 为给定的支付来源创建支付令牌（Create payment token for a given payment source）：`client.CreatePaymentToken()`
  * 列出所有支付令牌（List all payment tokens）：`client.ListAllPaymentTokens()`
  * 检索付款令牌（Retrieve a payment token）：`client.RetrievePaymentToken()`
  * 删除付款令牌（Delete payment token）：`client.DeletePaymentToken()`
  * 创建设置令牌（Create a setup token）：`client.CreateSetupToken()`
  * 检索设置令牌（Retrieve a setup token）：`client.RetrieveSetupToken()`
* <font color='#003087' size='4'>Payouts</font>
  * 创建批量支出（Create batch payout）：`client.CreateBatchPayout()`
  * 批量支出详情（Show payout batch details）：`client.ShowPayoutBatchDetails()`
  * 批量支出项目详情（Show Payout Item Details）：`client.ShowPayoutItemDetails()`
  * 取消批量支付中收款人无PayPal账号的项目（Cancel Unclaimed Payout Item）：`client.CancelUnclaimedPayoutItem()`
* <font color='#003087' size='4'>Subscriptions</font>
  * 创建计划（Create plan）：`client.CreateBillingPlan()`
  * 计划列表（List plans）：`client.PlanList()`
  * 计划详情（Show plan details）：`client.PlanDetails()`
  * 更新计划（UpdateBillingPlan）：`client.PlanUpdate()`
  * 激活计划（Activate plan）：`client.PlanActivate()`
  * 停用计划（Deactivate plan）：`client.PlanDeactivate()`
  * 更新计划价格（Update pricing）：`client.PlanUpdatePrice()`
  * 创建订阅（Create subscription）：`client.SubscriptionCreate()`
  * 订阅详情（Show subscription details）：`client.SubscriptionDetails()`
  * 更新订阅（Update subscription）：`client.SubscriptionUpdate()`
  * 修改计划或订阅数量（Revise plan or quantity of subscription）：`client.SubscriptionRevise()`
  * 暂停订阅（Suspend subscription）：`client.SubscriptionSuspend()`
  * 取消订阅（Cancel subscription）：`client.SubscriptionCancel()`
  * 激活订阅（Activate subscription）：`client.SubscriptionActivate()`
  * 订阅时获取授权付款（Capture authorized payment on subscription）：`client.SubscriptionCapture()`
  * 订阅的交易列表（List transactions for subscription）：`client.SubscriptionTransactionList()`
* <font color='#003087' size='4'>Catalog Products</font>
  * 创建产品（Create product）：`client.ProductCreate()`
  * 产品列表（List products）：`client.ProductList()`
  * 产品详情（Show product details）：`client.ProductDetails()`
  * 更新产品（Update product）：`client.ProductUpdate()`
* <font color='#003087' size='4'>Tracking（物流）</font>
  * 添加物流单号（Add tracking information for an order）：`client.AddTrackingNumber()`
  * 更新或取消物流（Update or cancel tracking information）：`client.UpdateTracker()`

---

### Doc Qq (`doc/qq.md`)

## QQ

> QQ支付 使用方法请参考 `GoPay微信v2文档` 的文档

> GoPay微信v2文档：[GoPay微信v2文档](https://github.com/go-pay/gopay/blob/main/doc/wechat_v2.md)

### QQ支付 API

* 提交付款码支付：`client.MicroPay()`
* 撤销订单：`client.Reverse()`
* 统一下单：`client.UnifiedOrder()`
* 订单查询：`client.OrderQuery()`
* 关闭订单：`client.CloseOrder()`
* 申请退款：`client.Refund()`
* 退款查询：`client.RefundQuery()`
* 交易账单：`client.StatementDown()`
* 资金账单：`client.AccRoll()`
* 创建现金红包（未测试可用性）：`client.SendCashRed()`
* 对账单下载（未测试可用性）：`client.DownloadRedListFile()`
* 查询红包详情（未测试可用性）：`client.QueryRedInfo()`
* 自定义方法请求微信API接口：`client.PostQQAPISelf()`

### QQ公共 API

* `qq.ParseNotifyToBodyMap()` => 解析QQ支付异步通知的结果到BodyMap
* `qq.ParseNotify()` => 解析QQ支付异步通知的参数
* `qq.VerifySign()` => QQ同步返回参数验签或异步通知参数验签
* `qq.GetAccessToken()` => 获取 AccessToken 信息
* `qq.GetOpenId()` => 获取 Openid 信息
* `qq.GetUserInfo()` => 获取用户信息

---

---

### Doc Saobei (`doc/saobei.md`)

## 扫呗支付 API


- 扫呗支付：[官方文档中心](https://help.lcsw.cn/xrmpic/q6imdiojes7iq5y1/qg52lx)



> 具体API使用介绍，请参考`gopay/saobei/client_test.go`


### 支付2.0接口 
> 请参考`gopay/saobei/pay_test.go`,
* 小程序支付接口(暂无账号为测试可用性)：`client.MiniPay()`
* 付款码支付 `client.BarcodePay()`
* 支付查询  `client.Query()`
* 退款申请 `client.Refund()`
* 退款订单查询 `client.QueryRefund()`

### 资金接口
> 请参考`gopay/saobei/merchant_test.go`,

### CBK企业钱包分账
> 请参考`gopay/saobei/account_test.go`,

---

### Doc Wechat V2 (`doc/wechat_v2.md`)

## 微信v2

> #### 推荐使用v3接口，官方在v3接口实现未覆盖或gopay未开发的接口，还继续用v2接口。

- 已实现API列表附录：[API 列表附录](https://github.com/go-pay/gopay/blob/main/doc/wechat_v2.md#%E9%99%84%E5%BD%95)

---

### 1、初始化微信v2客户端并做配置

微信v2官方文档：[微信v2官方文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)

> 注意：微信支付下单等操作可用沙箱环境测试是否成功，但真正支付时，请使用正式环境 `isProd = true`，不然会报错。

> 微信证书二选一：只传 `apiclient_cert.pem` 和 `apiclient_key.pem` 或者只传 `apiclient_cert.p12`

```go
import (
    "github.com/go-pay/gopay/wechat"
)

// 初始化微信客户端
//    appId：应用ID
//    mchId：商户ID
//    apiKey：API秘钥值
//    isProd：是否是正式环境
client := wechat.NewClient("wxdaa2ab9ef87b5497", mchId, apiKey, false)

// 打开Debug开关，输出请求日志，默认关闭
client.DebugSwitch = gopay.DebugOn

// 自定义配置http请求接收返回结果body大小，默认 10MB
client.SetBodySize() // 没有特殊需求，可忽略此配置

// 设置国家：不设置默认 中国国内
//    wechat.China：中国国内
//    wechat.China2：中国国内备用
//    wechat.SoutheastAsia：东南亚
//    wechat.Other：其他国家
client.SetCountry(wechat.China)

// 添加微信pem证书
client.AddCertPemFilePath()
client.AddCertPemFileContent()
 或
// 添加微信pkcs12证书
client.AddCertPkcs12FilePath()
client.AddCertPkcs12FileContent()
```

### 2、API 方法调用及入参

- #### 微信请求参数

> 微信V2接口通用参数（mch_id、appid、sign）无需传入，client 请求时会默认处理

具体参数请根据不同接口查看：[微信支付接口文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)

```go
import (
    "github.com/go-pay/util"
    "github.com/go-pay/gopay/wechat"
)

// 初始化 BodyMap
bm := make(gopay.BodyMap)
bm.Set("nonce_str", util.RandomString(32)).
    Set("body", "H5支付").
    Set("out_trade_no", number).
    Set("total_fee", 1).
    Set("spbill_create_ip", "127.0.0.1").
    Set("notify_url", "https://www.fmm.ink").
    Set("trade_type", TradeType_H5).
    Set("device_info", "WEB").
    Set("sign_type", SignType_MD5).
    SetBodyMap("scene_info", func(bm gopay.BodyMap) {
        bm.SetBodyMap("h5_info", func(bm gopay.BodyMap) {
            bm.Set("type", "Wap")
            bm.Set("wap_url", "https://www.fmm.ink")
            bm.Set("wap_name", "H5测试支付")
        })
    }) /*.Set("openid", "o0Df70H2Q0fY8JXh1aFPIRyOBgu8")*/
```

- #### client 方法调用

```go
wxRsp, err := client.UnifiedOrder(bm)
wxRsp, err := client.Micropay(bm)
wxRsp, err := client.QueryOrder(bm)
wxRsp, err := client.CloseOrder(bm)
wxRsp, err := client.Reverse(bm)
wxRsp, err := client.Refund(bm)
wxRsp, err := client.QueryRefund(bm)
wxRsp, err := client.DownloadBill(bm)
wxRsp, err := client.DownloadFundFlow(bm)
wxRsp, err := client.BatchQueryComment(bm)
wxRsp, err := client.Transfer(bm)
...
```

### 3、微信统一下单后，获取微信小程序支付、APP支付、微信内H5支付所需要的 paySign

> 微信小程序支付官方文档：[微信小程序支付API](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html)

> APP支付官方文档：[APP端调起支付的参数列表文档](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12)

> 微信内H5支付官方文档：[微信内H5支付文档](https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/pay/OfficialPayMent/chapter5_5.shtml)

```go
import (
    "github.com/go-pay/gopay/wechat"
)

// ====微信小程序 paySign====
timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
packages := "prepay_id=" + wxRsp.PrepayId   // 此处的 wxRsp.PrepayId ,统一下单成功后得到
// 获取微信小程序支付的 paySign
//    appId：AppID
//    nonceStr：随机字符串
//    packages：统一下单成功后拼接得到的值
//    signType：签名方式，务必与统一下单时用的签名方式一致
//    timeStamp：时间
//    apiKey：API秘钥值
paySign := wechat.GetMiniPaySign(AppID, wxRsp.NonceStr, packages, wechat.SignType_MD5, timeStamp, apiKey)

// ====APP支付 paySign====
timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
// 获取APP支付的 paySign
// 注意：package 参数因为是固定值，无需开发者再传入
//    appId：AppID
//    partnerid：partnerid
//    nonceStr：随机字符串
//    prepayId：统一下单成功后得到的值
//    signType：签名方式，务必与统一下单时用的签名方式一致
//    timeStamp：时间
//    apiKey：API秘钥值
paySign := wechat.GetAppPaySign(appid, partnerid, wxRsp.NonceStr, wxRsp.PrepayId, wechat.SignType_MD5, timeStamp, apiKey)

// ====微信内H5支付 paySign====
timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
packages := "prepay_id=" + wxRsp.PrepayId   // 此处的 wxRsp.PrepayId ,统一下单成功后得到
// 获取微信内H5支付 paySign
//    appId：AppID
//    nonceStr：随机字符串
//    packages：统一下单成功后拼接得到的值
//    signType：签名方式，务必与统一下单时用的签名方式一致
//    timeStamp：时间
//    apiKey：API秘钥值
paySign := wechat.GetH5PaySign(AppID, wxRsp.NonceStr, packages, wechat.SignType_MD5, timeStamp, apiKey)
```

### 4、同步返回参数验签Sign、异步通知参数解析和验签Sign、异步通知返回

> 异步通知请求参数需要先解析，解析出来的结构体或BodyMap再验签（此处需要注意，`http.Request.Body` 只能解析一次，如果需要解析前调试，请处理好Body复用问题）

[Gin Web框架（推荐）](https://github.com/gin-gonic/gin)

[Echo Web框架](https://github.com/labstack/echo)

```go
import (
    "github.com/go-pay/gopay"
    "github.com/go-pay/gopay/wechat"
)

// ====同步返回参数验签Sign====
wxRsp, err := client.UnifiedOrder(bm)
// 微信同步返回参数验签或异步通知参数验签
//    apiKey：API秘钥值
//    signType：签名类型（调用API方法时填写的类型）
//    bean：微信同步返回的结构体 wxRsp 或 异步通知解析的结构体 notifyReq
//    返回参数 ok：是否验签通过
//    返回参数 err：错误信息
ok, err := wechat.VerifySign(apiKey, wechat.SignType_MD5, wxRsp)

// ====支付异步通知参数解析和验签Sign====
// 解析支付异步通知的参数
//    req：*http.Request
//    ctx.Request   是 gin 框架的获取 *http.Request
//    ctx.Request() 是 echo 框架的获取 *http.Request
//    返回参数 notifyReq：通知的参数
//    返回参数 err：错误信息
notifyReq, err := wechat.ParseNotifyToBodyMap(ctx.Request)

// 验签操作
ok, err := wechat.VerifySign(apiKey, wechat.SignType_MD5, notifyReq)

// ====退款异步通知参数解析，退款通知无sign，不用验签====
// 
// 解析退款异步通知的参数，解析出来的 req_info 是加密数据，需解密
//    req：*http.Request
//    ctx.Request   是 gin 框架的获取 *http.Request
//    ctx.Request() 是 echo 框架的获取 *http.Request
//    返回参数 notifyReq：通知的参数
//    返回参数 err：错误信息
notifyReq, err := wechat.ParseNotifyToBodyMap(c.Request)
 或
notifyReq, err := wechat.ParseRefundNotify(c.Request)

// ==解密退款异步通知的加密参数 req_info ==
refundNotify, err := wechat.DecryptRefundNotifyReqInfo(notifyReq.ReqInfo, apiKey)

// ==异步通知，返回给微信平台的信息==
rsp := new(wechat.NotifyResponse) // 回复微信的数据
rsp.ReturnCode = gopay.SUCCESS
rsp.ReturnMsg = gopay.OK

// 此写法是 gin 框架返回微信的写法
c.String(http.StatusOK, "%s", rsp.ToXmlString())
// 此写法是 echo 框架返回微信的写法
return c.String(http.StatusOK, rsp.ToXmlString())
```

### 5、公共API（仅部分说明）

---

## 附录：

### 微信支付v2 API

* 统一下单：`client.UnifiedOrder()`
    * JSAPI - JSAPI支付（或小程序支付）
    * NATIVE - Native支付
    * APP - app支付
    * MWEB - H5支付
* 提交付款码支付：`client.Micropay()`
* 查询订单：`client.QueryOrder()`
* 关闭订单：`client.CloseOrder()`
* 撤销订单：`client.Reverse()`
* 申请退款：`client.Refund()`
* 查询退款：`client.QueryRefund()`
* 下载对账单：`client.DownloadBill()`
* 下载资金账单（正式）：`client.DownloadFundFlow()`
* 交易保障：`client.Report()`
* 拉取订单评价数据（正式）：`client.BatchQueryComment()`
* 企业付款（正式）：`client.Transfer()`
* 查询企业付款（正式）：`client.GetTransferInfo()`
* 授权码查询OpenId（正式）：`client.AuthCodeToOpenId()`
* 公众号纯签约（正式）：`client.EntrustPublic()`
* APP纯签约-预签约接口-获取预签约ID（正式）：`client.EntrustAppPre()`
* H5纯签约（正式）：`client.EntrustH5()`
* 支付中签约（正式）：`client.EntrustPaying()`
* 请求单次分账（正式）：`client.ProfitSharing()`
* 请求多次分账（正式）：`client.MultiProfitSharing()`
* 查询分账结果（正式）：`client.ProfitSharingQuery()`
* 查询订单待分账金额 （正式）：`client.ProfitSharingOrderAmountQuery()`
* 查询最大分账比例 （正式）：`client.ProfitSharingMerchantRatioQuery()`
* 添加分账接收方（正式）：`client.ProfitSharingAddReceiver()`
* 删除分账接收方（正式）：`client.ProfitSharingRemoveReceiver()`
* 完结分账（正式）：`client.ProfitSharingFinish()`
* 分账回退（正式）：`client.ProfitSharingReturn()`
* 分账回退结果查询（正式）：`client.ProfitSharingReturnQuery()`
* 企业付款到银行卡API（正式）：`client.PayBank()`
* 查询企业付款到银行卡API（正式）：`client.QueryBank()`
* 获取RSA加密公钥API（正式）：`client.GetRSAPublicKey()`
* 发放现金红包：`client.SendCashRed()`
* 发放现金裂变红包：`client.SendGroupCashRed()`
* 发放小程序红包：`client.SendAppletRed()`
* 查询红包记录：`client.QueryRedRecord()`
* 订单附加信息提交（海关）：`client.CustomsDeclareOrder()`
* 订单附加信息查询（海关）：`client.CustomsDeclareQuery()`
* 订单附加信息重推（海关）：`client.CustomsReDeclareOrder()`
* 自定义方法请求微信API接口：`client.PostWeChatAPISelf()`

### 微信公共v2 API

* `wechat.GetParamSign()` => 获取微信支付所需参数里的Sign值（通过支付参数计算Sign值）
* `wechat.GetSanBoxParamSign()` => 获取微信支付沙箱环境所需参数里的Sign值（通过支付参数计算Sign值）
* `wechat.GetMiniPaySign()` => 获取微信小程序支付所需要的paySign
* `wechat.GetH5PaySign()` => 获取微信内H5支付所需要的paySign
* `wechat.GetAppPaySign()` => 获取APP支付所需要的paySign
* `wechat.ParseNotifyToBodyMap()` => 解析微信支付异步通知的参数到BodyMap
* `wechat.ParseNotify()` => 解析微信支付异步通知的参数
* `wechat.ParseRefundNotify()` => 解析微信退款异步通知的参数
* `wechat.VerifySign()` => 微信同步返回参数验签或异步通知参数验签
* `wechat.GetOpenIdByAuthCode()` => 授权码查询openid
* `wechat.GetOauth2AccessToken()` => 微信第三方登录，code 换取 access_token
* `wechat.RefreshOauth2AccessToken()` => 刷新微信第三方登录后，获取到的 access_token
* `wechat.CheckOauth2AccessToken()` => 检验授权凭证（access_token）是否有效
* `wechat.DecryptRefundNotifyReqInfo()` => 解密微信退款异步通知的加密数据

---

### Doc Wechat V3 (`doc/wechat_v3.md`)

## 微信v3

> #### 推荐使用v3接口，官方在v3接口实现未覆盖或gopay未开发的接口，还继续用v2接口，欢迎参与完善v3接口。

- 已实现API列表附录：[API 列表附录](https://github.com/go-pay/gopay/blob/main/doc/wechat_v3.md#%E9%99%84%E5%BD%95)

- 微信官方文档：[商户平台文档](https://pay.weixin.qq.com/doc/v3/merchant/4012062524)、[服务商平台文档](https://pay.weixin.qq.com/doc/v3/partner/4012069852)

- 通用规则：[通用规则](https://pay.weixin.qq.com/doc/v3/partner/4012081673)

- GoPay微信v2文档：[GoPay微信v2文档](https://github.com/go-pay/gopay/blob/main/doc/wechat_v2.md) （部分接口仅v2版本支持）

---

### 1、初始化微信v3客户端并做配置

> 注意：v3 版本接口持续增加中，不支持沙箱支付，测试请用1分钱测试法

> 具体API使用介绍，请参考 `gopay/wechat/v3/client_test.go`

```go
import (
    "github.com/go-pay/xlog"
    "github.com/go-pay/gopay/wechat/v3"
)

// NewClientV3 初始化微信客户端 v3
// mchid：商户ID 或者服务商模式的 sp_mchid
// serialNo：商户证书的证书序列号
// apiV3Key：apiV3Key，商户平台获取
// privateKey：私钥 apiclient_key.pem 读取后的内容
client, err = wechat.NewClientV3(MchId, SerialNo, APIv3Key, PrivateKey)
if err != nil {
    xlog.Error(err)
    return
}

// 注意：以下两种自动验签方式二选一
// 微信支付公钥自动同步验签（新微信支付用户推荐）
err = client.AutoVerifySignByPublicKey([]byte("微信支付公钥内容"), "微信支付公钥ID，不能删除 PUB_KEY_ID_ 前缀，否则会出错")
if err != nil {
    xlog.Error(err)
    return
}
//// 微信平台证书自动获取证书+同步验签（并自动定时更新微信平台API证书）
//err = client.AutoVerifySign()
//if err != nil {
//	xlog.Error(err)
//	return
//}

// 自定义配置http请求接收返回结果body大小，默认 10MB
client.SetBodySize() // 没有特殊需求，可忽略此配置

// 设置自定义RequestId生成方法，非必须
client.SetRequestIdFunc()

// 打开Debug开关，输出日志，默认是关闭的
client.DebugSwitch = gopay.DebugOn
```

### 2、API 方法调用及入参

> 具体参数请根据不同接口查看：[微信支付V3的API字典概览](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml)

- JSAPI下单 示例
```go
import (
    "github.com/go-pay/gopay"
)

expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
// 初始化 BodyMap
bm := make(gopay.BodyMap)
bm.Set("sp_appid", "sp_appid").
    Set("sp_mchid", "sp_mchid").
    Set("sub_mchid", "sub_mchid").
    Set("description", "测试Jsapi支付商品").
    Set("out_trade_no", tradeNo).
    Set("time_expire", expire).
    Set("notify_url", "https://www.fmm.ink").
    SetBodyMap("amount", func(bm gopay.BodyMap) {
        bm.Set("total", 1).
            Set("currency", "CNY")
    }).
    SetBodyMap("payer", func(bm gopay.BodyMap) {
        bm.Set("sp_openid", "asdas")
    })

wxRsp, err := client.V3TransactionJsapi(bm)
if err != nil {
    xlog.Error(err)
    return
}
if wxRsp.Code == Success {
    xlog.Debugf("wxRsp: %#v", wxRsp.Response)
    return
}
xlog.Errorf("wxRsp:%s", wxRsp.Error)
```

### 3、下单后，获取微信小程序支付、APP支付、JSAPI支付所需要的 pay sign

> 小程序调起支付API：[小程序调起支付API](https://pay.weixin.qq.com/doc/v3/merchant/4012791898)

> APP调起支付API：[APP调起支付API](https://pay.weixin.qq.com/doc/v3/merchant/4013070351)

> JSAPI调起支付API：[JSAPI调起支付API](https://pay.weixin.qq.com/doc/v3/merchant/4012791857)

```go
// 小程序
applet, err := client.PaySignOfApplet("appid", "prepayid")
// app
app, err := client.PaySignOfApp("appid", "prepayid")
// jsapi
jsapi, err := client.PaySignOfJSAPI("appid", "prepayid")
```

### 4、同步请求返回验签Sign、异步通知参数解析+验签Sign+回执、敏感信息加/解密

> 异步通知请求参数需要先解析，解析出来的结构体或BodyMap再验签（此处需要注意，`http.Request.Body` 只能解析一次，如果需要解析前调试，请处理好Body复用问题）

[Gin Web框架（推荐）](https://github.com/gin-gonic/gin)

[Echo Web框架](https://github.com/labstack/echo)

- ~~同步返回验签，手动验签~~（推荐开启自动验签，则无需手动验签操作）

```go
import (
    "github.com/go-pay/gopay/wechat/v3"
    "github.com/go-pay/xlog"
)

wxRsp, err := client.V3TransactionJsapi(bm)
if err != nil {
    xlog.Error(err)
    return
}

pkMap := client.WxPublicKeyMap()
// wxPublicKey：微信平台证书公钥内容，通过 client.WxPublicKeyMap() 获取，然后根据 signInfo.HeaderSerial 获取相应的公钥
err = wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, pkMap[wxRsp.SignInfo.HeaderSerial])
if err != nil {
    xlog.Error(err)
    return
}
```

- 异步通知解析、验签、回执

```go
import (
    "github.com/go-pay/gopay/wechat/v3"
    "github.com/go-pay/xlog"
)

notifyReq, err := wechat.V3ParseNotify()
if err != nil {
    xlog.Error(err)
    return
}

// 获取微信平台证书
certMap := client.WxPublicKeyMap()
// 验证异步通知的签名
err = notifyReq.VerifySignByPKMap(certMap)
if err != nil {
    xlog.Error(err)
    return
}

// ====↓↓↓====异步通知应答====↓↓↓====
// 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功，否则会重试。
// 注意：重试过多会导致微信支付端积压过多通知而堵塞，影响其他正常通知。

// 此写法是 gin 框架返回微信的写法
c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})

// 此写法是 echo 框架返回微信的写法
return c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
```

- 敏感信息加/解密

```go
// ====↓↓↓====入参、出参加解密====↓↓↓====

// 敏感信息加密
client.V3EncryptText()
// 敏感信息解密
client.V3DecryptText()

// ====↓↓↓====异步通知参数解密====↓↓↓====

// 通用通知解密（推荐此方法）
result, err := notifyReq.DecryptCipherTextToStruct(apiV3Key, objPtr)
// 普通支付通知解密
result, err := notifyReq.DecryptPayCipherText(apiV3Key)
// 合单支付通知解密
result, err := notifyReq.DecryptCombineCipherText(apiV3Key)
// 退款通知解密
result, err := notifyReq.DecryptRefundCipherText(apiV3Key)
...
```

### 5、微信v3 公共API（仅部分说明）

```go
import (
    "github.com/go-pay/gopay/wechat/v3"
)

// 获取微信平台证书和序列号信息，推荐使用后者
wechat.GetPlatformCerts()
 或
client.GetAndSelectNewestCert()

// 请求参数 敏感信息加密，推荐使用后者
wechat.V3EncryptText() 或 client.V3EncryptText()

// 返回参数 敏感信息解密，推荐使用后者
wechat.V3DecryptText() 或 client.V3DecryptText()

// 回调通知 resource.ciphertext 敏感信息解密
wechat.V3DecryptNotifyCipherTextToStruct()  // 推荐使用此方法
wechat.V3DecryptPayNotifyCipherText()
wechat.V3DecryptRefundNotifyCipherText()
wechat.V3DecryptCombineNotifyCipherText()
...
```

---

## 附录：

### 微信支付v3 API

* <font color='#07C160' size='4'>基础支付</font>
    * APP下单：`client.V3TransactionApp()`
    * JSAPI/小程序下单：`client.V3TransactionJsapi()`
    * Native下单：`client.V3TransactionNative()`
    * H5下单：`client.V3TransactionH5()`
    * QQ小程序H5下单：`client.V3QQTransactionH5()`
    * 商户订单号/微信支付订单号 查询订单：`client.V3TransactionQueryOrder()`
    * 关闭订单：`client.V3TransactionCloseOrder()`
    * 付款码支付：`client.V3TransactionCodePay()`
    * 付款码支付撤销：`client.V3TransactionCodePayReverse()`
* <font color='#07C160' size='4'>基础支付（服务商）</font>
    * APP下单：`client.V3PartnerTransactionApp()`
    * JSAPI/小程序下单：`client.V3PartnerTransactionJsapi()`
    * Native下单：`client.V3PartnerTransactionNative()`
    * H5下单：`client.V3PartnerTransactionH5()`
    * 查询订单：`client.V3PartnerQueryOrder()`
    * 关闭订单：`client.V3PartnerCloseOrder()`
    * 付款码支付：`client.V3PartnerTransactionCodePay()`
    * 付款码支付撤销：`client.V3PartnerTransactionCodePayReverse()`
* <font color='#07C160' size='4'>合单支付</font>
    * 合单下单-APP：`client.V3CombineTransactionApp()`
    * 合单下单-JSAPI/小程序：`client.V3CombineTransactionJsapi()`
    * 合单下单-NATIVE：`client.V3CombineTransactionNative()`
    * 合单下单-H5：`client.V3CombineTransactionH5()`
    * 合单QQ小程序下单-H5：`client.V3CombineQQTransactionH5()`
    * 合单查询订单：`client.V3CombineQueryOrder()`
    * 合单关闭订单：`client.V3CombineCloseOrder()`
* <font color='#07C160' size='4'>退款</font>
    * 申请退款：`client.V3Refund()`
    * 查询单笔退款（通过商户退款单号）：`client.V3RefundQuery()`
* <font color='#07C160' size='4'>资金/交易账单</font>
    * 申请交易账单：`client.V3BillTradeBill()`
    * 申请资金账单：`client.V3BillFundFlowBill()`
    * 申请特约商户资金账单：`client.V3BillEcommerceFundFlowBill()`
    * 下载账单：`client.V3BillDownLoadBill()`
* <font color='#07C160' size='4'>提现（服务商、电商）</font>
    * 特约商户余额提现/二级商户预约提现：`client.V3Withdraw()`
    * 查询特约商户提现状态/二级商户查询预约提现状态：`client.V3WithdrawStatus()`
    * 电商平台预约提现：`client.V3EcommerceWithdraw()`
    * 电商平台查询预约提现状态：`client.V3EcommerceWithdrawStatus()`
    * 按日下载提现异常文件：`client.V3WithdrawDownloadErrBill()`
* <font color='#07C160' size='4'>微信支付分（服务订单）</font>
    * 创建支付分订单：`client.V3ScoreOrderCreate()`
    * 查询支付分订单：`client.V3ScoreOrderQuery()`
    * 取消支付分订单：`client.V3ScoreOrderCancel()`
    * 修改订单金额：`client.V3ScoreOrderModify()`
    * 完结支付分订单：`client.V3ScoreOrderComplete()`
    * 商户发起催收扣款：`client.V3ScoreOrderPay()`
    * 同步服务订单信息：`client.V3ScoreOrderSync()`
* <font color='#07C160' size='4'>微信支付分（免确认模式）</font>
    * 创单结单合并：`client.V3ScoreDirectComplete()`
* <font color='#07C160' size='4'>微信支付分（免确认预授权模式）</font>
    * 商户预授权：`client.V3ScorePermission()`
    * 查询用户授权记录（授权协议号）：`client.V3ScorePermissionQuery()`
    * 解除用户授权关系（授权协议号）：`client.V3ScorePermissionTerminate()`
    * 查询用户授权记录（openid）：`client.V3ScorePermissionOpenidQuery()`
    * 解除用户授权关系（openid）：`client.V3ScorePermissionOpenidTerminate()`
* <font color='#07C160' size='4'>微信先享卡</font>
    * 预受理领卡请求：`client.V3DiscountCardApply()`
    * 增加用户记录：`client.V3DiscountCardAddUser()`
    * 查询先享卡订单：`client.V3DiscountCardQuery()`
* <font color='#07C160' size='4'>支付即服务</font>
    * 服务人员注册：`client.V3SmartGuideReg()`
    * 服务人员分配：`client.V3SmartGuideAssign()`
    * 服务人员查询：`client.V3SmartGuideQuery()`
    * 服务人员信息更新：`client.V3SmartGuideUpdate()`
* <font color='#07C160' size='4'>智慧商圈</font>
    * 商圈积分同步：`client.V3BusinessPointsSync()`
    * 商圈积分授权查询：`client.V3BusinessAuthPointsQuery()`
    * 商圈会员待积分状态查询：`client.V3BusinessPointsStatusQuery()`
    * 商圈会员停车状态同步：`client.V3BusinessParkingSync()`
* <font color='#07C160' size='4'>微信支付分停车服务</font>
    * 查询车牌服务开通信息：`client.V3VehicleParkingQuery()`
    * 创建停车入场：`client.V3VehicleParkingIn()`
    * 扣费受理：`client.V3VehicleParkingFee()`
    * 查询订单：`client.V3VehicleParkingOrder()`
* <font color='#07C160' size='4'>代金券</font>
    * 创建代金券批次：`client.V3FavorBatchCreate()`
    * 激活代金券批次：`client.V3FavorBatchStart()`
    * 发放代金券批次：`client.V3FavorBatchGrant()`
    * 暂停代金券批次：`client.V3FavorBatchPause()`
    * 重启代金券批次：`client.V3FavorBatchRestart()`
    * 条件查询批次列表：`client.V3FavorBatchList()`
    * 查询批次详情：`client.V3FavorBatchDetail()`
    * 查询代金券详情：`client.V3FavorDetail()`
    * 查询代金券可用商户：`client.V3FavorMerchant()`
    * 查询代金券可用单品：`client.V3FavorItems()`
    * 根据商户号查用户的券：`client.V3FavorUserCoupons()`
    * 下载批次核销明细：`client.V3FavorUseFlowDownload()`
    * 下载批次退款明细：`client.V3FavorRefundFlowDownload()`
    * 查询消息通知地址：`client.V3FavorCallbackUrl()`
    * 设置消息通知地址：`client.V3FavorCallbackUrlSet()`
* <font color='#07C160' size='4'>商家券</font>
    * 创建商家券：`client.V3BusiFavorBatchCreate()`
    * 查询商家券详情：`client.V3BusiFavorBatchDetail()`
    * 核销用户券：`client.V3BusiFavorUse()`
    * 根据过滤条件查询用户券：`client.V3BusiFavorUserCoupons()`
    * 查询用户单张券详情：`client.V3BusiFavorUserCouponDetail()`
    * 上传预存code：`client.V3BusiFavorCodeUpload()`
    * 设置商家券事件通知地址：`client.V3BusiFavorCallbackUrlSet()`
    * 查询商家券事件通知地址：`client.V3BusiFavorCallbackUrl()`
    * 关联订单信息：`client.V3BusiFavorAssociate()`
    * 取消关联订单信息：`client.V3BusiFavorDisassociate()`
    * 修改批次预算：`client.V3BusiFavorBatchUpdate()`
    * 修改商家券基本信息：`client.V3BusiFavorInfoUpdate()`
    * 发放消费卡：`client.V3BusiFavorSend()`
    * 申请退券：`client.V3BusiFavorReturn()`
    * 使券失效：`client.V3BusiFavorDeactivate()`
    * 营销补差付款：`client.V3BusiFavorSubsidyPay()`
    * 查询营销补差付款单详情：`client.V3BusiFavorSubsidyPayDetail()`
* <font color='#07C160' size='4'>委托营销</font>
    * 建立合作关系：`client.V3PartnershipsBuild()`
    * 终止合作关系：`client.V3PartnershipsTerminate()`
    * 查询合作关系列表：`client.V3PartnershipsList()`
* <font color='#07C160' size='4'>支付有礼</font>
    * 创建全场满额送活动：`client.V3PayGiftActivityCreate()`
    * 获取支付有礼活动列表：`client.V3PayGiftActivityList()`
    * 获取活动详情：`client.V3PayGiftActivityDetail()`
    * 获取活动指定商品列表：`client.V3PayGiftActivityGoods()`
    * 终止活动：`client.V3PayGiftActivityTerminate()`
    * 获取活动发券商户号：`client.V3PayGiftActivityMerchant()`
    * 新增活动发券商户号：`client.V3PayGiftActivityMerchantAdd()`
    * 删除活动发券商户号：`client.V3PayGiftActivityMerchantDelete()`
* <font color='#07C160' size='4'>电子发票</font>
    * 创建电子发票卡券模板：`client.V3InvoiceCardTemplateCreate()`
    * 配置开发选项：`client.V3InvoiceMerchantDevConfig()`
    * 查询商户配置的开发选项：`client.V3InvoiceMerchantDevConfigQuery()`
    * 查询电子发票：`client.V3InvoiceQuery()`
    * 获取抬头填写链接：`client.V3InvoiceUserTitleUrl()`
    * 获取用户填写的抬头：`client.V3InvoiceUserTitle()`
    * 获取商户开票基础信息：`client.V3InvoiceMerchantBaseInfo()`
    * 获取商户可开具的商品和服务税收分类编码对照表：`client.V3InvoiceMerchantTaxCodes()`
    * 开具电子发票：`client.V3InvoiceCreate()`
    * 冲红电子发票：`client.V3InvoiceReverse()`
    * 获取发票下载信息：`client.V3InvoiceFileUrl()`
    * 上传电子发票文件：`client.V3InvoiceUploadFile()`
    * 将电子发票插入微信用户卡包：`client.V3InvoiceInsertCard()`
* <font color='#07C160' size='4'>分账</font>
    * 请求分账：`client.V3ProfitShareOrder()`
    * 查询分账结果：`client.V3ProfitShareOrderQuery()`
    * 请求分账回退：`client.V3ProfitShareReturn()`
    * 查询分账回退结果：`client.V3ProfitShareReturnResult()`
    * 解冻剩余资金：`client.V3ProfitShareOrderUnfreeze()`
    * 查询剩余待分金额：`client.V3ProfitShareUnsplitAmount()`
    * 添加分账接收方：`client.V3ProfitShareAddReceiver()`
    * 删除分账接收方：`client.V3ProfitShareDeleteReceiver()`
* <font color='#07C160' size='4'>消费者投诉2.0</font>
    * 查询投诉单列表：`client.V3ComplaintList()`
    * 查询投诉单详情：`client.V3ComplaintDetail()`
    * 查询投诉协商历史：`client.V3ComplaintNegotiationHistory()`
    * 创建投诉通知回调地址：`client.V3ComplaintNotifyUrlCreate()`
    * 查询投诉通知回调地址：`client.V3ComplaintNotifyUrlQuery()`
    * 更新投诉通知回调地址：`client.V3ComplaintNotifyUrlUpdate()`
    * 删除投诉通知回调地址：`client.V3ComplaintNotifyUrlDelete()`
    * 提交回复：`client.V3ComplaintResponse()`
    * 反馈处理完成：`client.V3ComplaintComplete()`
    * 更新退款审批结果：`client.V3ComplaintUpdateRefundProgress()`
    * 回复需要即时服务的投诉单：`client.V3ComplaintResponseImmediateService()`
    * 商户上传反馈图片：`client.V3ComplaintUploadImage()`
    * 商户反馈图片请求：`client.V3ComplaintImage()`
* <font color='#07C160' size='4'>商户平台处置通知</font>
    * 创建商户违规通知回调回调地址：`client.V3ViolationNotifyUrlCreate()`
    * 查询商户违规通知回调回调地址：`client.V3ViolationNotifyUrlQuery()`
    * 更新商户违规通知回调回调地址：`client.V3ViolationNotifyUrlUpdate()`
    * 删除商户违规通知回调回调地址：`client.V3ViolationNotifyUrlDelete()`
* <font color='#07C160' size='4'>其他能力</font>
    * 图片上传：`client.V3MediaUploadImage()`
    * 视频上传：`client.V3MediaUploadVideo()`
    * 图片上传（营销专用）：`client.V3FavorMediaUploadImage()`
    * 图片下载：`client.V3MediaDownloadImage()`
* <font color='#07C160' size='4'>商家转账到零钱（商户）</font>
    * 发起商家转账：`client.V3Transfer()`
    * 通过微信批次单号查询批次单：`client.V3TransferQuery()`
    * 通过微信明细单号查询明细单：`client.V3TransferDetail()`
    * 通过商家批次单号查询批次单：`client.V3TransferMerchantQuery()`
    * 通过商家明细单号查询明细单：`client.V3TransferMerchantDetail()`
    * 转账账单电子回单申请受理接口：`client.V3TransferReceipt()`
    * 查询转账账单电子回单接口：`client.V3TransferReceiptQuery()`
    * 转账明细电子回单受理：`client.V3TransferDetailReceipt()`
    * 查询转账明细电子回单受理结果：`client.V3TransferDetailReceiptQuery()`
* <font color='#07C160' size='4'>转账（服务商）</font>
    * 发起批量转账：`client.V3PartnerTransfer()`
    * 微信批次单号查询批次单：`client.V3PartnerTransferQuery()`
    * 微信明细单号查询明细单：`client.V3PartnerTransferDetail()`
    * 商家批次单号查询批次单：`client.V3PartnerTransferMerchantQuery()`
    * 商家明细单号查询明细单：`client.V3PartnerTransferMerchantDetail()`
* <font color='#07C160' size='4'>商家转账（新版）</font>
    * 发起转账：`client.V3TransferBills()`
    * 撤销转账：`client.V3TransferBillsCancel()`
    * 商户单号查询转账单：`client.V3TransferBillsMerchantQuery()`
    * 微信单号查询转账单：`client.V3TransferBillsQuery()`
    * 商户单号申请电子回单：`client.V3TransferElecsignMerchant()`
    * 微信单号申请电子回单：`client.V3TransferElecsign()`
    * 商户单号查询电子回单：`client.V3TransferElecsignQuery()`
    * 微信单号查询电子回单：`client.V3TransferElecsignMerchantQuery()`
    * 下载电子回单：`client.V3TransferElecsignDownload()`
* <font color='#07C160' size='4'>商家转账（免确认收款授权）</font>
    * 发起转账并完成免确认收款授权：`client.V3TransferPreTransferWithAuth()`
    * 发起免确认收款授权：`client.V3TransferUserConfirmAuth()`
    * 商户单号查询授权结果：`client.V3TransferUserConfirmAuthQuery()`
    * 解除免确认收款授权：`client.V3TransferUserConfirmAuthClose()`
* <font color='#07C160' size='4'>余额查询</font>
    * 查询特约商户账户实时余额：`client.V3EcommerceBalance()`
    * 查询二级商户账户日终余额：`client.V3EcommerceDayBalance()`
    * 查询账户实时余额：`client.V3MerchantBalance()`
    * 查询账户日终余额：`client.V3MerchantDayBalance()`
* <font color='#07C160' size='4'>来账识别</font>
    * 商户银行来账查询：`client.V3MerchantIncomeRecord()`
    * 特约商户银行来账查询：`client.V3EcommerceIncomeRecord()`
* <font color='#07C160' size='4'>特约商户进件（服务商）</font>
    * 提交申请单：`client.V3Apply4SubSubmit()`
    * 查询申请单状态（BusinessCode）：`client.V3Apply4SubQueryByBusinessCode()`
    * 查询申请单状态（ApplyId）：`client.V3Apply4SubQueryByApplyId()`
    * 修改结算账号：`client.V3Apply4SubModifySettlement()`
    * 修改结算账号(新)：`client.V3AsyncApply4SubModifySettlement()`
    * 查询结算账户：`client.V3Apply4SubQuerySettlement()`
    * 查询结算账户修改申请状态：`client.V3Apply4SubMerchantsApplication()`
* <font color='#07C160' size='4'>点金计划（服务商）</font>
    * 点金计划管理：`client.V3GoldPlanManage()`
    * 商家小票管理：`client.V3GoldPlanBillManage()`
    * 同业过滤标签管理：`client.V3GoldPlanFilterManage()`
    * 开通广告展示：`client.V3GoldPlanOpenAdShow()`
    * 关闭广告展示：`client.V3GoldPlanCloseAdShow()`
* <font color='#07C160' size='4'>电商收付通（商户进件）</font>
    * 二级商户进件：`client.V3EcommerceApply()`
    * 查询申请状态：`client.V3EcommerceApplyStatus()`
* <font color='#07C160' size='4'>电商收付通（分账）</font>
    * 请求分账：`client.V3EcommerceProfitShare()`
    * 查询分账结果：`client.V3EcommerceProfitShareResult()`
    * 请求分账回退：`client.V3EcommerceProfitShareReturn()`
    * 查询分账回退结果：`client.V3EcommerceProfitShareReturnResult()`
    * 完结分账：`client.V3EcommerceProfitShareFinish()`
    * 查询订单剩余待分金额：`client.V3EcommerceProfitShareUnsplitAmount()`
    * 添加分账接收方：`client.V3EcommerceProfitShareAddReceiver()`
    * 删除分账接收方：`client.V3EcommerceProfitShareDeleteReceiver()`
* <font color='#07C160' size='4'>电商收付通（补差）</font>
    * 请求补差：`client.V3EcommerceProfitShare()`
    * 请求补差回退：`client.V3EcommerceSubsidiesReturn()`
    * 取消补差：`client.V3EcommerceSubsidiesCancel()`
* <font color='#07C160' size='4'>电商收付通（退款）</font>
    * 申请退款：`client.V3EcommerceRefund()`
    * 查询单笔退款（通过微信支付退款号）：`client.V3EcommerceRefundQueryById()`
    * 查询单笔退款（通过商户退款单号）：`client.V3EcommerceRefundQueryByNo()`
    * 垫付退款回补：`client.V3EcommerceRefundAdvance()`
    * 查询垫付回补结果：`client.V3EcommerceRefundAdvanceResult()`
* <font color='#07C160' size='4'>银行组件（服务商）</font>
    * 获取对私银行卡号开户银行：`client.V3BankSearchBank()`
    * 查询支持个人业务的银行列表：`client.V3BankSearchPersonalList()`
    * 查询支持对公业务的银行列表：`client.V3BankSearchCorporateList()`
    * 查询省份列表：`client.V3BankSearchProvinceList()`
    * 查询城市列表：`client.V3BankSearchCityList()`
    * 查询支行列表：`client.V3BankSearchBranchList()`
* <font color='#07C160' size='4'>扣费服务（预约扣费）</font>
    * 小程序预签约：`client.V3ScheduledDeductPreSignMiniProgram()`
    * APP 预签约：`client.V3ScheduledDeductPreSignApp()`
    * H5 预签约：`client.V3ScheduledDeductPreSignH5()`
    * JSAPI 预签约：`client.V3ScheduledDeductPreSignJsapi()`
    * 通过商户协议号查询签约：`client.V3ScheduledDeductContractQuery()`
    * 通过商户协议号解约：`client.V3ScheduledDeductContractTerminate()`
    * 创建预约扣费：`client.V3ScheduledDeductSchedule()`
    * 查询预约扣费结果：`client.V3ScheduledDeductScheduleQuery()`
    * 受理扣款：`client.V3ScheduledDeductApply()`
    * 回调通知载荷：`PapayScheduledSignNotifyResource`、`PapayScheduledPayNotifyResource`（配合 `wechat.V3DecryptNotifyCipherTextToStruct` 使用）
* <font color='#07C160' size='4'>掌纹支付</font>
    * 用户自主录掌&预授权：`client.V3PalmServicePreAuthorize()`
    * 预授权状态查询：`client.V3PalmServiceOpenidQuery()`
* <font color='#07C160' size='4'>医保支付</font>
    * 医保自费混合收款下单：`client.V3MedInsOrder()`
    * 使用医保自费混合订单号查看下单结果：`client.V3MedInsOrderQueryByMixNo()`
    * 使用商户订单号查看下单结果：`client.V3MedInsOrderQueryByOutNo()`


### 微信v3公共 API

* `wechat.GetPlatformCerts()` => 获取微信平台证书公钥
* `wechat.GetPlatformRSACerts()` => 获取平台RSA证书列表
* `wechat.GetPlatformSM2Certs()` => 获取国密平台证书
* `client.GetAndSelectNewestCert()` => 获取证书Map集并选择最新的有效证书序列号（默认RSA证书）
* `client.GetAndSelectNewestCertRSA()` => 获取证书Map集并选择最新的有效RSA证书序列号
* `client.GetAndSelectNewestCertSM2()` => 获取证书Map集并选择最新的有效SM2证书序列号
* `client.GetAndSelectNewestCertALL()` => 获取证书Map集并选择最新的有效RSA+SM2证书序列号
* `client.WxPublicKey()` => 获取最新的有效证书
* `client.WxPublicKeyMap()` => 获取有效证书 Map
* `wechat.V3ParseNotify()` => 解析微信回调请求的参数到 V3NotifyReq 结构体
* `notify.VerifySignByPKMap()` => 微信V3 异步通知验签
* `client.V3EncryptText()` => 敏感参数信息加密
* `client.V3DecryptText()` =>  敏感参数信息解密
* `wechat.V3EncryptText()` => 敏感参数信息加密
* `wechat.V3DecryptText()` =>  敏感参数信息解密
* `wechat.V3DecryptNotifyCipherTextToStruct()` =>  解密 统一数据 到指针结构体对象（推荐统一使用此方法）
* `wechat.V3DecryptNotifyCipherTextToBytes()` =>  解密 统一数据 到 []byte
* `wechat.V3DecryptPayNotifyCipherText()` => 解密 普通支付 回调中的加密信息
* `wechat.V3DecryptPartnerPayNotifyCipherText()` => 解密 服务商普通支付 回调中的加密信息
* `wechat.V3DecryptRefundNotifyCipherText()` => 解密 普通退款 回调中的加密信息
* `wechat.V3DecryptCombineNotifyCipherText()` => 解密 合单支付 回调中的加密信息
* `wechat.V3DecryptScoreNotifyCipherText()` => 解密 支付分确认订单 回调中的加密信息
* `wechat.V3DecryptScorePermissionNotifyCipherText()` => 解密 支付分开启/解除授权服务 回调中的加密信息
* `wechat.V3DecryptBusifavorNotifyCipherText()` => 解密 领券事件 回调中的加密信息
* `wechat.V3DecryptParkingInNotifyCipherText()` => 解密 停车入场状态变更 回调中的加密信息
* `wechat.V3DecryptParkingPayNotifyCipherText()` => 解密 停车支付结果 回调中的加密信息
* `wechat.V3DecryptCouponUseNotifyCipherText()` => 解密 代金券核销 回调中的加密信息
* `wechat.V3DecryptInvoiceTitleNotifyCipherText()` => 解密 用户发票抬头填写完成 回调中的加密信息
* `wechat.V3DecryptInvoiceNotifyCipherText()` => 解密 发票卡券作废/发票开具成功/发票冲红成功/发票插入用户卡包成功 回调中的加密信息
* `client.PaySignOfJSAPI()` => 获取 JSAPI 支付 paySign
* `client.PaySignOfApp()` => 获取 APP 支付 paySign
* `client.PaySignOfApplet()` => 获取 小程序 支付 paySign

---

--- METRICS ---
- Files Extracted: 14
- Estimated Token Budget: ~25620 tokens
- Canonical Reference: https://codewiki.google/github.com/go-pay/gopay
