Add WeChat Pay local skills

This commit is contained in:
2026-05-15 03:35:30 +08:00
parent 2eded08bc7
commit 6672867c6f
535 changed files with 114971 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# 商户开户意愿确认
商户开户意愿确认是微信支付的风控要求,商户入网后需完成开户意愿确认,确保商户主体名称不被冒用。渠道商(银行、支付机构、普通服务商)可通过两种方式协助商户完成确认。
## 两种确认方式
| 方式 | 说明 |
|------|------|
| "商家注册"小程序 | 渠道商下载拓展二维码,商家扫码在小程序中提交资料并完成确认 |
| 商户开户意愿确认 API | 渠道商通过 API 提交商家资料,联系人扫小程序码确认信息并完成验证 |
> API 方式仅减少商家在小程序提交资料的环节,联系人仍需扫描小程序码进行确认。
## API 流程
```
1. 渠道商获取商户号(通过进件或已有商户号)
2. 渠道商创建开户意愿申请单
├── 调用「提交申请单」接口,提交商家资料 + 商户号
└── 在补充材料 - 待确认商户号列表中传入商户号,联系人确认时可同步完成授权
3. 微信支付审核1-3 个工作日)
├── 审核通过 → 状态变为"待联系人确认"
└── 审核驳回 → 根据驳回原因修改资料,调用「撤销申请单」后重新提交
4. 联系人确认(扫描申请单小程序码)
├── 核对联系信息(可修改手机号),完成短信验证
└── 核实商家资质信息,点击确认
5. 商家授权商户号
├── 若创建申请单时已传入商户号列表 → 联系人在确认流程中直接授权
└── 若未传入 → 联系人后续通过小程序码或公众号消息进入授权页面
⚠️ 只有商户全称与注册商家名称一致的商户号才能授权
6. 账户验证(按主体类型和联系人身份判断)
├── 个体工商户(法人/经营者)→ 无需验证
├── 个体工商户(负责人)→ 法人扫码验证
├── 企业(法人/经营者)→ 无需验证
├── 企业(负责人)→ 汇款验证或法人扫码10天有效
├── 党政/事业单位 → 无需验证
├── 其他组织 → 汇款验证10天有效
└── 小微 → 法人/经营者验证
7. 渠道商确认完成
├── 查询申请单状态为"审核通过"APPLYMENT_STATE_PASSED
└── 查询授权状态为"已授权"
```
## API 接口
| 接口 | 方法 | 路径 | 备注 |
|------|------|------|------|
| 提交申请单 | POST | `/v3/apply4subject/applyment/` | 频率限制5QPS商户号维度 |
| 查询申请单审核结果 | GET | `/v3/apply4subject/applyment` | 通过 applyment_id 或 business_code 查询,频率 20QPS |
| 撤销申请单 | POST | `/v3/apply4subject/applyment/{business_code}/cancel``{applyment_id}/cancel` | 驳回后修改前须先撤销 |
| 获取商户开户意愿确认状态 | GET | `/v3/apply4subject/applyment/merchants/{sub_mchid}/state` | 确认商户是否已完成授权 |
> 敏感信息加密:联系人姓名、手机号、身份证号等敏感字段须使用微信支付公钥(推荐)或平台证书公钥加密,请求 Header 须携带 `Wechatpay-Serial`。
## 申请单状态流转
| 状态 | 含义 | 后续操作 |
|------|------|---------|
| APPLYMENT_STATE_EDITTING | 编辑中 | 提交可能发生错误,可用同一 business_code 重新提交 |
| APPLYMENT_STATE_WAITTING_FOR_AUDIT | 审核中 | 等待 1-2 个工作日 |
| APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT | 待联系人确认 | 获取小程序码,引导联系人扫码确认联系信息 |
| APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON | 待账户验证 | 引导联系人扫码完成账户验证 |
| APPLYMENT_STATE_PASSED | 审核通过(终态) | 引导联系人扫码完成授权商户号 |
| APPLYMENT_STATE_REJECTED | 审核驳回(终态) | 根据驳回原因修改,调用撤销接口后重新提交 |
| APPLYMENT_STATE_FREEZED | 已冻结(终态) | 主体已完成过入驻,查看驳回原因,通知指定联系人扫码完成授权 |
| APPLYMENT_STATE_CANCELED | 已作废(终态) | 申请单已被撤销或超 720 小时未完成 |
## 与特约商户进件的关系
| 维度 | 特约商户进件 | 商户开户意愿确认 |
|------|-----------|----------------|
| 目的 | 商户入驻微信支付,获取商户号 | 确认商户开户意愿,防止主体被冒用 |
| 使用方 | 普通服务商 | 渠道商(银行、支付机构、普通服务商) |
| API 前缀 | `/v3/applyment4sub/` | `/v3/apply4subject/` |
| 是否必须 | 服务商拓展子商户时必须 | 根据风控要求,部分商户入网后需完成 |
| 流程 | 服务商提交全部资料 → 审核 → 签约 | 渠道商提交基础资料 → 审核 → 联系人扫码确认 |
## 重要参数说明
| 参数 | 说明 |
|------|------|
| `business_code` | 业务申请编号,服务商自定义唯一编号,每个编号对应一个申请单 |
| `subject_type` | 主体类型枚举:`SUBJECT_TYPE_ENTERPRISE`(企业)、`SUBJECT_TYPE_INDIVIDUAL`(个体工商户)、`SUBJECT_TYPE_INSTITUTIONS_CLONED`(事业单位)、`SUBJECT_TYPE_OTHERS`(其他组织)、`SUBJECT_TYPE_MICRO`(小微商户) |
| `licence_number` | 营业执照注册号,个体工商户或企业须为 15 位数字或 18 位数字/大写字母 |
| `merchant_name` | 商户名称须与营业执照一致;个体工商户不能以"公司"结尾;营业执照名称为空时填"个体户+经营者姓名" |
| `confirm_mchid_list` | 补充材料中的待确认商户号列表,传入后联系人确认时可同步完成授权,无需二次授权 |
| 敏感字段 | 联系人姓名、手机号、身份证号须加密Header 须携带 `Wechatpay-Serial` |
## 常见问题
### 业务规则
| 问题 | 答案 |
|------|------|
| 一个微信号可同时提交多个申请单吗? | 不可以,一个微信只能有一个流程中的申请单 |
| 申请单有效期多长? | 720 小时30 天),超期自动作废 |
| 账户验证需要多长时间? | 汇款后 2 小时内获知结果;法人扫码后立即完成 |
| 审核驳回后怎么重新提交? | 须先调用「撤销申请单」接口,再用新的 business_code 重新提交 |
| 商户名称有什么要求? | 必须与营业执照上的商户名称一致 |
| "审核通过"是最终状态吗? | 是,"审核通过""已冻结""已作废"均为终态 |
| 联系人微信号有什么要求? | 联系人微信实名的身份证号需与申请单填写的联系人身份证号一致 |
| 什么是"已冻结"状态? | 该主体已完成过入驻,需查看驳回原因,通知指定联系人扫码完成授权 |
| 进行开户意愿确认前是否需要先绑定 sub_mchid 与 sub_appid 的关系? | 不需要,需要先完成开户意愿确认 |
| 查询申请单审核结果接口返回的 qrcode_data小程序码图片有效期是多久 | 有效期 30 天,超过 30 天后需要先撤销申请单,再重新提交 |
| 申请单状态为 APPLYMENT_STATE_PASSED 但返回的二维码已过期怎么办? | 二维码有效期 30 天,过期后可撤销申请单再重新提交,也可调用「获取商户开户意愿确认状态」接口查询商户是否已完成授权 |
| 授权完成后,申请单返回的二维码还有使用场景吗? | 已完成授权后,二维码一般不再有使用场景 |
| 商户名称中的"特殊符号"怎么定义? | @#$%° 等均算特殊字符;商户名称不能使用纯数字或纯特殊字符,但名称中可以包含数字和特殊字符,按照营业执照上的正确名称填写即可 |
| 商户名称字段规则中"不能为纯数字"和"可以包含数字"是否冲突? | 不冲突,规则含义是商户名称不能是纯数字或纯特殊字符,但名称中允许包含数字和特殊字符 |
| 获取商户开户意愿确认状态接口有限频吗? | 有,限频为 10QPS |
### 常见报错
| 报错信息 | 原因与解决 |
|---------|-----------|
| "暂未查询到该营业执照注册号" | `licence_number` 填写错误,个体工商户/企业须为 15 位数字或 18 位数字/大写字母 |
| "系统繁忙,请稍后重试" | ① 系统异常稍后重试;② 参数大小写/格式与文档不一致;③ 请求头 `mchid` 填写错误 |
| "查询申请单不存在" | `applyment_id` 填写错误或未填写,申请单编号和业务申请编号至少传一个 |
| "Authorization不合法" | ① 认证类型须为 `WECHATPAY2-SHA256-RSA2048`;② `mchid` 须为渠道商商户号;③ 检查证书序列号、签名值;④ Authorization 头不能有换行 |
| "商户未申请过证书" | 须到商户平台申请下载 API 证书并正确使用 |
| "无法将传入参数'申请单编号'转换为uint64类型" | `applyment_id` 参数类型错误,须为 uint64 |
| "注册号/证书号填写错误或与证书类型不匹配" | 检查 `licence_number``cert_number` 是否与所选的证书类型(`cert_type`)匹配,确认格式和内容正确 |
| "生成小程序二维码失败,请稍后再试[40001]" | 已知偶发问题,直接重试即可 |
| "请填写有效身份证居住地址" | `identification_address` 字段填写有误,需填写身份证上的有效居住地址 |
| "请选择门店所在省市区范围" | `store_address_code` 字段填写有误,需选择正确的门店所在省市区行政区划代码 |

View File

@@ -0,0 +1,80 @@
# 开发必要参数说明(服务商模式)
> 两种接入模式的参数、API路径等核心差异见 `接入模式说明.md`,本文仅补充服务商模式的落地细节。
> 未配置 `sub_appid` 时只能传 `openid`(即 sp_appid 下的用户标识)。
## 权限申请(各支付方式流程一致)
1. **服务商申请开通**:登录服务商平台 → 产品中心 → 特约商户授权产品 → 对应支付产品 → 申请开通(审核 7 个工作日)
2. **子商户授权**:服务商在特约商户列表中发起邀请 → 子商户登录商户平台 → 产品中心 → 我的授权产品 → 授权
> 子商户需先通过服务商平台或接口入驻。如无服务商商户号,需先申请入驻。
## APPID 绑定
- **sp_appid**:服务商平台 → 产品中心 → APPID授权管理 → 关联 APPID
- **sub_appid**(可选,由服务商操作):服务商平台 → 合作伙伴功能 → 开发参数配置 → 对应子商户 → 特约商户APPID配置
APPID 类型(公众号/小程序/移动应用)与商户模式相同,**三种格式相同但不能混用**。
| 常见报错 | 原因 | 处理 |
|---------|------|------|
| `appid and mchid not match` | sp_appid/sub_appid 与对应商户号未绑定 | 检查服务商平台 APPID 绑定配置 |
| `appid is invalid` | appid 格式错或类型不对 | 确认使用了正确类型的 APPID |
## 各支付方式速查表
> 通用下单参数(各方式相同):`sub_mchid`(收款子商户号)、`time_expire`(默认 7 天)、`profit_sharing`(分账标识)。
> 通用后续流程:查询订单、支付回调通知、下载账单、退款,各支付方式完全一致。
| | JSAPI | APP | H5 | Native | 小程序 |
|--|-------|-----|----|---------|----|
| **适用场景** | 微信内浏览器网页 | 原生APP | 手机浏览器(非微信) | PC端网页 | 微信小程序 |
| **下单API** | `.../jsapi` | `.../app` | `.../h5` | `.../native` | 同JSAPI |
| **下单产物** | prepay_id2h | prepay_id2h | h5_url**5min** | code_url2h | prepay_id2h |
| **调起方式** | WeixinJSBridge | OpenSDK sendReq | 跳转h5_url | code_url转二维码 | wx.requestPayment |
| **需openid** | ✅ | ❌ | ❌ | ❌ | ✅ |
> 下单 API 路径前缀均为 `/v3/pay/partner/transactions`。小程序与 JSAPI **共享权限和下单接口**。
> 付款码支付仅有 V2 接口XML + MD5/HMAC-SHA256不在上表 V3 体系中参考文档https://pay.weixin.qq.com/doc/v2/partner/4011941052
## 各支付方式特殊注意
### JSAPI
- **必须接入点金计划**:服务商模式下 JSAPI 支付完成后,页面会被替换为点金计划官方页面,服务商的 H5/小程序页面会被关闭。不接入商家小票功能则支付后用户无法返回商户页面。详见 `点金计划.md`
- 必须在服务商平台配置授权目录
### APP
- 调起支付的 `appId` 必须与下单参数一致服务商APP中传 `sp_appid`子商户APP中传 `sub_appid``sub_appid` 仅在子商户APP下单时需传
- Android 必须实现 `WXPayEntryActivity`Android 13 需去除其 `intent-filter`
- iOS 务必配置 URL scheme
- 严格遵循 OpenSDK 接入指引(安卓/iOS/鸿蒙)
### H5
- **不能在APP内使用**
- 必须在服务商平台配置 H5 支付域名
- 可在 `h5_url` 后拼接 `redirect_url` 指定支付后返回页面
- **必须实现跨域安全校验**OPTIONS 预检和 GET/POST 请求均需校验 `Origin` 白名单和用户登录态,否则可能被依据《微信支付服务协议》处理
### Native
- 仅支持**扫一扫**,不支持相册识别或长按识别二维码
- 支付完成后**无前端回调**(用户留在微信端),必须依赖回调通知或轮询查单确认状态
### 小程序
- 与 JSAPI 区别仅在调起方式wx.requestPayment和 openid 获取方式wx.login无需配置授权目录
- 小程序内嵌 H5 页面**不能**调用 JSAPI 收款,只能用小程序支付
- 调起支付签名的 `appid` 需与实际调起的小程序一致(服务商小程序用 `sp_appid`,子商户小程序用 `sub_appid`
- 交易类小程序须满足《交易类小程序运营规范》,结算周期受公众平台管控
## 参数与代码示例的对应关系
```
spMchid → 服务商商户号
subMchid → 子商户号
spAppid → 服务商APPID
subAppid → 子商户APPID可选
certificateSerialNo → 服务商API证书序列号
privateKeyFilePath → 服务商API证书私钥文件路径apiclient_key.pem
wechatPayPublicKeyId → 微信支付公钥ID
wechatPayPublicKeyFilePath → 微信支付公钥文件路径wxp_pub.pem
```

View File

@@ -0,0 +1,108 @@
# 点金计划(服务商 JSAPI 支付必接)
## 什么是点金计划
点金计划是微信支付官方提供的支付后页面升级能力。服务商为子商户开通后,子商户的 **JSAPI 支付完成页**将被替换为点金计划官方页面,同时发起支付的服务商 H5 页面或小程序页面**会被关闭**
**核心影响**:如果服务商不接入商家小票功能,支付后用户将看不到商户的业务内容(取餐码、停车时长、订单详情等),也无法返回商户页面。
## 两种小票模式
| | 官方小票 | 商家小票 |
|--|---------|---------|
| **内容** | 平台自动生成,仅展示订单金额等基础信息 | 商家自定义,可展示取餐码、停车时长等业务内容 |
| **开发成本** | 无需开发,直接开通 | 需开发商家小票页面并完成 iframe 对接 |
| **适用场景** | 无需展示业务信息的子商户 | 需要在支付后展示业务信息的子商户(餐饮、停车等) |
## 开通流程
### 1. 服务商开通点金计划
路径:服务商平台 → 服务商功能 → 点金计划 → 申请开通(签署承诺函 + 填写业务联络人)。
### 2. 为子商户开通官方小票
路径:服务商平台 → 服务商功能 → 点金计划 → 特约商户管理 → 打开"点金计划"开关。
也可通过"默认开通"按钮为全量子商户自动开通(有 JSAPI 支付的子商户会自动开通,无 JSAPI 支付权限的不会)。
> 主动关闭点金计划后,需间隔 **24 小时**方可再次开通。
### 3. 为子商户开通商家小票(可选)
步骤:
1. 配置商家小票链接:服务商平台 → 服务商功能 → 点金计划 → 商家小票链接配置 → 添加链接(须 HTTPS + ICP 备案)→ 下载验证文件放到链接目录下验证所有权
2. 打开商家小票开关:特约商户管理 → 打开"商家小票"开关
3. 打开点金计划开关:特约商户管理 → 打开"点金计划"开关
> 先开商家小票再开点金计划,避免时间差导致部分订单展示官方小票。
> 部分子商户(医院、学校等)可配置独立的商家小票链接。
## 商家小票开发要点
点金计划页面上方提供一个 **iframe 框架**,商家小票页面嵌入其中。核心交互流程:
1. 用户 JSAPI 支付完成 → 点金计划页面加载 → iframe 加载商家小票链接
2. 点金计划页面向 iframe 传递订单信息(通过 postMessage
3. 商家小票页面获取订单信息、校验通过后展示业务内容
4. **必须在 3 秒内调用父页面的 `onIframeReady` JSAPI**,否则提示"无法获取订单信息"
## 小程序左上角返回键管理
小程序支付场景下,可通过 `wx.requestPayment``payCompletedPageOptions` 控制点金计划页面左上角的返回按钮。
**隐藏返回按钮**
```javascript
wx.requestPayment({
payCompletedPageOptions: {
showNavBackButton: false
}
})
```
**自定义返回按钮跳转页面**
```javascript
wx.requestPayment({
payCompletedPageOptions: {
showNavBackButton: true
},
success: res => {
res.payCompletedPage.onUnload(() => {
wx.navigateTo({
url: '/page/index/index'
})
})
}
})
```
> 点击左上角返回按钮会触发支付回调页的 `onUnload` 事件,在该事件中可跳转到指定页面。
## API 接口
| 接口 | 方法 | 路径 | 用途 |
|------|------|------|------|
| 点金计划管理 | POST | `/v3/goldplan/merchants/changegoldplanstatus` | 为子商户开通/关闭点金计划 |
| 商家小票管理 | POST | `/v3/goldplan/merchants/changecustompagestatus` | 为子商户开通/关闭商家小票 |
| 同业过滤标签 | POST | `/v3/goldplan/merchants/set-advertising-industry-filter` | 过滤同行业广告(最多 3 个标签) |
| 开通广告展示 | PATCH | `/v3/goldplan/merchants/open-advertising-show` | 开通广告并设置过滤标签 |
| 关闭广告展示 | POST | `/v3/goldplan/merchants/close-advertising-show` | 关闭广告展示 |
> 所有接口均需传 `sub_mchid`(子商户号)和 `operation_type`OPEN/CLOSE
## 常见问题
| 问题 | 答案 |
|------|------|
| 开通/关闭点金计划后多久生效? | 开通后 **5 分钟**内生效 |
| 看不到"商家小票"开关? | 需先在"商家小票链接配置"中添加链接,开关才会出现 |
| 商家小票调试报"无法获取订单信息" | ① 确认已打开商家小票和点金计划开关;② 页面须在 3 秒内调用 `onIframeReady` JSAPI③ 扫码调试的微信号须与支付订单的微信号一致;④ 商家小票页面须可正常访问 |
| 开通后支付完成页展示什么? | 只展示点金计划页面(含官方/商家小票 + 广告),不再展示服务商的支付回调页 |
| 服务商返佣怎么算? | 返佣(元)= eCPM/ 1000 × 支付后广告曝光量 |
| 如何领取广告收益的技术服务费? | 参考技术服务费结果查询、技术服务费领取指引查询和领取 |
| 自定义页面点按钮弹框"即将打开商家的新页面"能去掉吗? | **不支持**去掉或自定义弹窗内容 |
| jumpOut 跳转公众号时弹窗显示商家简称,能隐藏或修改吗? | **不支持** |
| 商家小票页面支持跳转小程序吗? | 小程序支付场景支持用点金计划 JS 跳转小程序JSAPI 支付场景**不支持** |
| 从业机构号可以开通点金计划吗? | **不支持**,需要从业机构下的渠道商去开通配置 |

View File

@@ -0,0 +1,146 @@
# 特约商户进件
特约商户进件是微信支付面向**普通服务商**开放的接口能力,用于协助各类型商户发起入驻微信支付的申请。从业机构(银行及支付机构)及电商平台不可使用本接口。
## 支持的商户类型
| 类型 | 定义 | 所需资料 |
|------|------|---------|
| 个体工商户 | 营业执照主体类型为个体户/个体工商户/个体经营 | 营业执照、经营者证件、结算银行账户 |
| 企业 | 营业执照主体类型为有限公司/有限责任公司 | 营业执照、法人证件、组织机构代码证(未三证合一)、结算银行账户 |
| 党政/机关及事业单位 | 各级政府机构、事业单位 | 登记证书、法人证件、组织机构代码证(未三证合一)、结算银行账户 |
| 其他组织 | 社会团体、民办非企业、基金会等 | 登记证书、法人证件、组织机构代码证(未三证合一) |
> 不支持进件个人小微商户。
## 进件流程
```
1. 服务商提交进件申请
├── 调用「提交申请单」接口,填写:主体信息、经营信息、结算规则、结算账户、超级管理员
└── 调用「查询申请单状态」获取签约链接(建议转二维码),发给超级管理员
└── 超管扫码后,"微信支付商家助手"公众号推送申请进展通知
2. 微信支付审核(约 1-3 个工作日)
3. 特约商户账户验证(审核通过后,按主体类型判断是否需要)
├── 个体工商户:超管为法人/经营者 → 无需验证;超管为负责人 → 法人扫码验证10天有效
├── 企业:超管为法人/经营者 → 无需验证;超管为负责人 → 汇款验证或法人扫码验证10天有效
├── 党政/事业单位:上传盖章证明函 → 无需验证;汇款验证 → 指定账户汇款10天有效
└── 其他组织:汇款账户验证
⚠️ 10天内未完成验证申请单自动驳回
4. 特约商户签约
├── 服务商通过查询接口获取签约链接,发给超管
└── 超管扫码完成签约
5. 开通权限(签约后约 30 分钟自动完成)
├── 根据进件时选择的经营场景授权支付权限:
│ ├── 线下门店 → 付款码、JSAPI、刷脸
│ ├── 公众号 → JSAPI
│ ├── 小程序 → JSAPI
│ ├── App → App支付
│ └── 互联网网站 → JSAPI、Native
└── 默认授权 API 退款权限
6. 完成入驻(申请单状态为"已完成"
└── 首笔交易后,微信支付汇款 0.01 元至结算银行卡验证账户信息
```
## API 接口
| 接口 | 方法 | 路径 | 备注 |
|------|------|------|------|
| 提交申请单 | POST | `/v3/applyment4sub/applyment/` | 频率限制15QPS服务商维度 |
| 通过业务申请编号查询申请状态 | GET | `/v3/applyment4sub/applyment/business_code/{business_code}` | |
| 通过申请单ID查询申请状态 | GET | `/v3/applyment4sub/applyment/applyment_id/{applyment_id}` | |
| 修改结算账户 | POST | `/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement` | 每天最多 5 次,频率限制 20/min |
| 查询结算账户 | GET | `/v3/apply4sub/sub_merchants/{sub_mchid}/settlement` | |
| 查询结算账户修改申请状态 | GET | `/v3/apply4sub/sub_merchants/{sub_mchid}/application/{application_no}` | |
| 图片上传 | POST | `/v3/merchant/media/upload` | 进件资料中的图片需先上传获取 MediaID |
> 敏感信息加密:进件请求中的姓名、身份证号、手机号、邮箱等敏感字段需使用**微信支付公钥**(推荐)或平台证书公钥加密,请求 Header 须携带 `Wechatpay-Serial`公钥ID 或证书序列号)。
## 提交申请单核心参数结构
| 模块 | 必填 | 主要字段 |
|------|------|---------|
| `business_code` | 是 | 业务申请编号,服务商自定义唯一编号。若申请单被驳回,可填相同编号覆盖修改原申请单 |
| `contact_info` | 是 | 超级管理员信息类型LEGAL 法人/SUPER 经办人)、姓名🔐、手机🔐、邮箱🔐 |
| `subject_info` | 是 | 主体资料:主体类型、营业执照/登记证书、法人身份证件(姓名🔐、证件号🔐) |
| `business_info` | 是 | 经营资料:商户简称、经营场景(线下/公众号/小程序/App/网站、AppID |
| `settlement_info` | 是 | 结算规则:结算账户类型(对公/对私)、开户银行、银行账号 |
| `bank_account_info` | 是 | 结算银行账户:开户名称🔐、银行账号🔐、开户银行 |
| `addition_info` | 否 | 补充材料:业务流程截图、业务合同等 |
> 🔐 标记的字段为敏感信息需使用微信支付公钥或平台证书公钥加密HTTP 头须上送 `Wechatpay-Serial`。
>
> 超级管理员类型为 `SUPER`(经办人)时,需额外上传经办人身份证件和业务办理授权函。
### 重要参数说明
| 参数 | 说明 |
|------|------|
| `business_code` | 服务商自定义唯一编号,建议前缀为服务商商户号。每个编号对应一个申请单,审核通过后生成微信支付商户号。被驳回可用相同编号覆盖修改 |
| `bank_account_type` | 账户类型。企业/党政/事业/其他组织:`BANK_ACCOUNT_TYPE_CORPORATE`(对公)。个体户可选对公或 `BANK_ACCOUNT_TYPE_PERSONAL`(经营者个人银行卡) |
| `account_name` | 开户名称。选"经营者个人银行卡"时须与经营者证件姓名一致;选"对公银行账户"时须与营业执照/登记证书的商户名称一致 |
| `subject_type` | 主体类型枚举:`SUBJECT_TYPE_INDIVIDUAL`(个体户)、`SUBJECT_TYPE_ENTERPRISE`(企业)、`SUBJECT_TYPE_GOVERNMENT`(政府机关)、`SUBJECT_TYPE_INSTITUTIONS`(事业单位)、`SUBJECT_TYPE_OTHERS`(社会组织) |
| 不需要的参数 | **不要传空值**,不需要的字段直接不上传,否则可能报"系统繁忙" |
## 申请单状态流转
| 状态 | 含义 | 后续操作 |
|------|------|---------|
| APPLYMENT_STATE_EDITTING | 编辑中 | — |
| APPLYMENT_STATE_AUDITING | 审核中 | 等待审核结果1-3个工作日 |
| APPLYMENT_STATE_REJECTED | 已驳回 | 根据驳回原因修改后重新提交 |
| APPLYMENT_STATE_TO_BE_CONFIRMED | 待账户验证 | 发送验证链接给超管 |
| APPLYMENT_STATE_TO_BE_SIGNED | 待签约 | 发送签约链接给超管 |
| APPLYMENT_STATE_SIGNING | 开通权限中 | 约30分钟自动完成 |
| APPLYMENT_STATE_FINISHED | 已完成 | 入驻成功 |
| APPLYMENT_STATE_CANCELED | 已作废 | 超30天未签约自动作废 |
## 常见问题
### 业务规则
| 问题 | 答案 |
|------|------|
| 服务商可以入驻成为自己的特约商户吗? | 不可以 |
| 普通商户号可以和服务商号建立绑定关系吗? | 不支持,需重新在该服务商下进件 |
| 特约商户能否变更为普通服务商? | 不支持 |
| 申请单已审核通过但想修改信息? | 没有撤销接口可更换进件单号重新提交。原申请单30天后自动作废 |
| 重新提交进件返回的申请单号不变? | 需更换 `business_code`(业务申请编号),否则复用旧申请单 |
| 提交申请单接口频率限制? | 服务商维度 15QPS |
| 修改结算银行卡频率限制? | 每天最多提交 5 次,次日 0 点后可重新发起 |
| 法人与营业执照上不一致? | 需先完成工商信息变更,确保一致后再进件 |
| 查询结算账户不返回 `verify_result` 字段? | 入驻后若没修改过银行卡,除非汇款失败,否则不返回该字段 |
### 常见报错
| 报错信息 | 原因与解决 |
|---------|-----------|
| "暂无权限" / "NO_AUTH" | ① 服务商商户号被处罚,进入合作伙伴平台 → 合作伙伴功能 → 风险处理 → 功能限制记录,找到对应单据处理;② 请求头 `mchid` 填写错误,只能填普通服务商商户号;③ 不允许进件小微商户 |
| "进件特约商户的权限已被受限" | 服务商进件权限被风控限制,登录服务商平台查看受限原因,解除限制后再调用接口 |
| "身份证号码,与营业执照不匹配" | `id_card_number` 需填写营业执照上法人/经营者的身份证号,格式为 17位数字+1位数字/X且须加密 |
| "请填写法人证件姓名" | `id_card_name` 字段未传或传值有误,确认填写后重新提交 |
| "经营者/负责人证件类型取值不在有效范围内" | 未传 `contact_type` 字段,需传入 `LEGAL``SUPER` |
| "参数'组织机构代码证照片'是必填项" | 不需要的参数结构不要传入,去掉 `organization_info` 结构 |
| "系统繁忙,请稍后重试" | ① 系统繁忙稍后重试;② `mchid` 填写错误;③ 不需要的参数不要上传,不能传空值 |
| "开户银行取值有误" | 开户银行全称和联行号须匹配(如联行号 310290097606 对应"上海浦东发展银行股份有限公司三林支行"),调用「查询支持个人/对公业务的银行列表」接口获取正确值 |
| "证书图片内容无效" | 调用图片上传接口重新获取 MediaID |
| 命中敏感词INVALID_REQUEST | 商户名称或简称含敏感词(如"慈善""基金""医疗"等),修改后重新提交。具体敏感词不对外公开,需逐步排查 |
| "商户号数量超过上限" | 系统基于已有商户号经营情况动态评估上限,注销闲置商户号后需等系统重新评估,评估标准为黑盒 |
### 线上高频问题(来自真实工单)
| 问题 | 答案 |
|------|------|
| 电商服务商调进件接口报错? | 电商服务商无权限调用特约商户进件接口,需先接入为**普通服务商**,参考特约商户进件文档 |
| 进件时 AppID 填什么? | 填写与商家主体一致且已认证的应用 AppID需是已认证的 App在"经营信息"模块按指引填写 |
| 申请单一直"资料校验中"不变? | 可能单据已驳回或已作废,调用查询申请单状态接口确认实际状态及驳回原因 |
| 状态为 ACCOUNT_NEED_VERIFY 但未返回 `legal_validation_url` | 接口根据商户当前所需操作返回对应链接,当天商户应先操作账户验证 |
| 申请单卡在"待确认"无法取消或删除? | 没有取消/删除接口,审核需 1-3 个工作日30 天不处理自动作废。可更换 `business_code` 重新提交 |
| API 进件的商户如何修改商户简称? | 通过商户平台修改,不支持通过 API 修改 |
| 单个人/主体进件次数有限制吗? | 有限制,系统动态评估,具体以实际返回为准 |
| 商户已存在怎么办? | 根据提示先注销已有商户号,再重新进件 |

View File

@@ -0,0 +1,211 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerApiv3PartnerJsapiPrepayRequest{
SpAppid: wxpay_utility.String("wx8888888888888888"),
SpMchid: wxpay_utility.String("1230000109"),
SubAppid: wxpay_utility.String("wxd678efh567hg6999"),
SubMchid: wxpay_utility.String("1900000109"),
Description: wxpay_utility.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
TimeExpire: wxpay_utility.Time(time.Now()),
Attach: wxpay_utility.String("自定义数据"),
NotifyUrl: wxpay_utility.String(" https://www.weixin.qq.com/wxpay/pay.php"),
GoodsTag: wxpay_utility.String("WXG"),
SettleInfo: &PartnerSettleInfo{
ProfitSharing: wxpay_utility.Bool(true),
},
SupportFapiao: wxpay_utility.Bool(true),
Amount: &CommonAmountInfo{
Total: wxpay_utility.Int64(100),
Currency: wxpay_utility.String("CNY"),
},
Payer: &PartnerJsapiReqPayerInfo{
SpOpenid: wxpay_utility.String("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"),
SubOpenid: wxpay_utility.String("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"),
},
Detail: &CouponInfo{
CostPrice: wxpay_utility.Int64(608800),
InvoiceId: wxpay_utility.String("微信123"),
GoodsDetail: []GoodsDetail{
GoodsDetail{
MerchantGoodsId: wxpay_utility.String("1246464644"),
WechatpayGoodsId: wxpay_utility.String("1001"),
GoodsName: wxpay_utility.String("iPhoneX 256G"),
Quantity: wxpay_utility.Int64(1),
UnitPrice: wxpay_utility.Int64(528800),
},
},
},
SceneInfo: &CommonSceneInfo{
PayerClientIp: wxpay_utility.String("14.23.150.211"),
DeviceId: wxpay_utility.String("013467007045764"),
StoreInfo: &StoreInfo{
Id: wxpay_utility.String("0001"),
Name: wxpay_utility.String("腾讯大厦分店"),
AreaCode: wxpay_utility.String("440305"),
Address: wxpay_utility.String("广东省深圳市南山区科技中一道10000号"),
},
},
}
response, err := PartnerJsapiPrepay(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerJsapiPrepay(config *wxpay_utility.MchConfig, request *PartnerApiv3PartnerJsapiPrepayRequest) (response *PartnerApiv3PartnerJsapiPrepayResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/pay/partner/transactions/jsapi"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &PartnerApiv3PartnerJsapiPrepayResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type PartnerApiv3PartnerJsapiPrepayRequest struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
Description *string `json:"description,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TimeExpire *time.Time `json:"time_expire,omitempty"`
Attach *string `json:"attach,omitempty"`
NotifyUrl *string `json:"notify_url,omitempty"`
GoodsTag *string `json:"goods_tag,omitempty"`
SettleInfo *PartnerSettleInfo `json:"settle_info,omitempty"`
SupportFapiao *bool `json:"support_fapiao,omitempty"`
Amount *CommonAmountInfo `json:"amount,omitempty"`
Payer *PartnerJsapiReqPayerInfo `json:"payer,omitempty"`
Detail *CouponInfo `json:"detail,omitempty"`
SceneInfo *CommonSceneInfo `json:"scene_info,omitempty"`
}
type PartnerApiv3PartnerJsapiPrepayResponse struct {
PrepayId *string `json:"prepay_id,omitempty"`
}
type PartnerSettleInfo struct {
ProfitSharing *bool `json:"profit_sharing,omitempty"`
}
type CommonAmountInfo struct {
Total *int64 `json:"total,omitempty"`
Currency *string `json:"currency,omitempty"`
}
type PartnerJsapiReqPayerInfo struct {
SpOpenid *string `json:"sp_openid,omitempty"`
SubOpenid *string `json:"sub_openid,omitempty"`
}
type CouponInfo struct {
CostPrice *int64 `json:"cost_price,omitempty"`
InvoiceId *string `json:"invoice_id,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type CommonSceneInfo struct {
PayerClientIp *string `json:"payer_client_ip,omitempty"`
DeviceId *string `json:"device_id,omitempty"`
StoreInfo *StoreInfo `json:"store_info,omitempty"`
}
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
}
type StoreInfo struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
AreaCode *string `json:"area_code,omitempty"`
Address *string `json:"address,omitempty"`
}

View File

@@ -0,0 +1,168 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetTradeBillRequest{
BillDate: wxpay_utility.String("2019-06-11"),
SubMchid: wxpay_utility.String("19000000001"),
BillType: BILLTYPE_ALL.Ptr(),
TarType: TARTYPE_GZIP.Ptr(),
}
response, err := GetTradeBill(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func GetTradeBill(config *wxpay_utility.MchConfig, request *GetTradeBillRequest) (response *QueryBillEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/bill/tradebill"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
query := reqUrl.Query()
query.Add("bill_date", *request.BillDate)
query.Add("sub_mchid", *request.SubMchid)
query.Add("bill_type", fmt.Sprintf("%v", *request.BillType))
query.Add("tar_type", fmt.Sprintf("%v", *request.TarType))
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &QueryBillEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type GetTradeBillRequest struct {
BillDate *string `json:"bill_date,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
BillType *BillType `json:"bill_type,omitempty"`
TarType *TarType `json:"tar_type,omitempty"`
}
func (o *GetTradeBillRequest) MarshalJSON() ([]byte, error) {
type Alias GetTradeBillRequest
a := &struct {
BillDate *string `json:"bill_date,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
BillType *BillType `json:"bill_type,omitempty"`
TarType *TarType `json:"tar_type,omitempty"`
*Alias
}{
BillDate: nil,
SubMchid: nil,
BillType: nil,
TarType: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryBillEntity struct {
HashType *HashType `json:"hash_type,omitempty"`
HashValue *string `json:"hash_value,omitempty"`
DownloadUrl *string `json:"download_url,omitempty"`
}
type BillType string
func (e BillType) Ptr() *BillType {
return &e
}
const (
BILLTYPE_ALL BillType = "ALL"
BILLTYPE_SUCCESS BillType = "SUCCESS"
BILLTYPE_REFUND BillType = "REFUND"
)
type TarType string
func (e TarType) Ptr() *TarType {
return &e
}
const (
TARTYPE_GZIP TarType = "GZIP"
)
type HashType string
func (e HashType) Ptr() *HashType {
return &e
}
const (
HASHTYPE_SHA1 HashType = "SHA1"
)

View File

@@ -0,0 +1,163 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetFundFlowBillRequest{
BillDate: wxpay_utility.String("2019-06-11"),
AccountType: FUNDFLOWBILLACCOUNTTYPE_BASIC.Ptr(),
TarType: TARTYPE_GZIP.Ptr(),
}
response, err := GetFundFlowBill(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func GetFundFlowBill(config *wxpay_utility.MchConfig, request *GetFundFlowBillRequest) (response *QueryBillEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/bill/fundflowbill"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
query := reqUrl.Query()
query.Add("bill_date", *request.BillDate)
query.Add("account_type", fmt.Sprintf("%v", *request.AccountType))
query.Add("tar_type", fmt.Sprintf("%v", *request.TarType))
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &QueryBillEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type GetFundFlowBillRequest struct {
BillDate *string `json:"bill_date,omitempty"`
AccountType *FundFlowBillAccountType `json:"account_type,omitempty"`
TarType *TarType `json:"tar_type,omitempty"`
}
func (o *GetFundFlowBillRequest) MarshalJSON() ([]byte, error) {
type Alias GetFundFlowBillRequest
a := &struct {
BillDate *string `json:"bill_date,omitempty"`
AccountType *FundFlowBillAccountType `json:"account_type,omitempty"`
TarType *TarType `json:"tar_type,omitempty"`
*Alias
}{
BillDate: nil,
AccountType: nil,
TarType: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryBillEntity struct {
HashType *HashType `json:"hash_type,omitempty"`
HashValue *string `json:"hash_value,omitempty"`
DownloadUrl *string `json:"download_url,omitempty"`
}
type FundFlowBillAccountType string
func (e FundFlowBillAccountType) Ptr() *FundFlowBillAccountType {
return &e
}
const (
FUNDFLOWBILLACCOUNTTYPE_BASIC FundFlowBillAccountType = "BASIC"
FUNDFLOWBILLACCOUNTTYPE_OPERATION FundFlowBillAccountType = "OPERATION"
FUNDFLOWBILLACCOUNTTYPE_FEES FundFlowBillAccountType = "FEES"
)
type TarType string
func (e TarType) Ptr() *TarType {
return &e
}
const (
TARTYPE_GZIP TarType = "GZIP"
)
type HashType string
func (e HashType) Ptr() *HashType {
return &e
}
const (
HASHTYPE_SHA1 HashType = "SHA1"
)

View File

@@ -0,0 +1,123 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &ChangeCustomPageStatusRequest{
SubMchid: wxpay_utility.String("1900000109"),
OperationType: OPERATIONTYPE_OPEN.Ptr(),
}
response, err := ChangeCustomPageStatus(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func ChangeCustomPageStatus(config *wxpay_utility.MchConfig, request *ChangeCustomPageStatusRequest) (response *ChangeCustomPageStatusResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/goldplan/merchants/changecustompagestatus"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &ChangeCustomPageStatusResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type ChangeCustomPageStatusRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
OperationType *OperationType `json:"operation_type,omitempty"`
}
type ChangeCustomPageStatusResponse struct {
SubMchid *string `json:"sub_mchid,omitempty"`
}
type OperationType string
func (e OperationType) Ptr() *OperationType {
return &e
}
const (
OPERATIONTYPE_OPEN OperationType = "OPEN"
OPERATIONTYPE_CLOSE OperationType = "CLOSE"
)

View File

@@ -0,0 +1,137 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &ChangeGoldPlanStatusRequest{
SubMchid: wxpay_utility.String("1900000109"),
OperationType: OPERATIONTYPE_OPEN.Ptr(),
OperationPayScene: OPERATIONPAYSCENE_JSAPI_AND_MINIPROGRAM.Ptr(),
}
response, err := ChangeGoldPlanStatus(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func ChangeGoldPlanStatus(config *wxpay_utility.MchConfig, request *ChangeGoldPlanStatusRequest) (response *ChangeGoldPlanStatusResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/goldplan/merchants/changegoldplanstatus"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &ChangeGoldPlanStatusResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type ChangeGoldPlanStatusRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
OperationType *OperationType `json:"operation_type,omitempty"`
OperationPayScene *OperationPayScene `json:"operation_pay_scene,omitempty"`
}
type ChangeGoldPlanStatusResponse struct {
SubMchid *string `json:"sub_mchid,omitempty"`
}
type OperationType string
func (e OperationType) Ptr() *OperationType {
return &e
}
const (
OPERATIONTYPE_OPEN OperationType = "OPEN"
OPERATIONTYPE_CLOSE OperationType = "CLOSE"
)
type OperationPayScene string
func (e OperationPayScene) Ptr() *OperationPayScene {
return &e
}
const (
OPERATIONPAYSCENE_JSAPI_AND_MINIPROGRAM OperationPayScene = "JSAPI_AND_MINIPROGRAM"
OPERATIONPAYSCENE_JSAPI OperationPayScene = "JSAPI"
OPERATIONPAYSCENE_MINIPROGRAM OperationPayScene = "MINIPROGRAM"
)

View File

@@ -0,0 +1,88 @@
package main
import (
"bytes"
"demo/wxpay_utility"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &CloseAdvertisingShowRequest{
SubMchid: wxpay_utility.String("1900000109"),
}
err = CloseAdvertisingShow(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Println("请求成功")
}
func CloseAdvertisingShow(config *wxpay_utility.MchConfig, request *CloseAdvertisingShowRequest) (err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/goldplan/merchants/close-advertising-show"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return err
}
reqBody, err := json.Marshal(request)
if err != nil {
return err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return err
}
return nil
} else {
return wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type CloseAdvertisingShowRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
}

View File

@@ -0,0 +1,133 @@
package main
import (
"bytes"
"demo/wxpay_utility"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &OpenAdvertisingShowRequest{
SubMchid: wxpay_utility.String("1900000109"),
AdvertisingIndustryFilters: []IndustryType{INDUSTRYTYPE_E_COMMERCE},
}
err = OpenAdvertisingShow(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Println("请求成功")
}
func OpenAdvertisingShow(config *wxpay_utility.MchConfig, request *OpenAdvertisingShowRequest) (err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "PATCH"
path = "/v3/goldplan/merchants/open-advertising-show"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return err
}
reqBody, err := json.Marshal(request)
if err != nil {
return err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return err
}
return nil
} else {
return wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type OpenAdvertisingShowRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
AdvertisingIndustryFilters []IndustryType `json:"advertising_industry_filters,omitempty"`
}
type IndustryType string
func (e IndustryType) Ptr() *IndustryType { return &e }
const (
INDUSTRYTYPE_E_COMMERCE IndustryType = "E_COMMERCE"
INDUSTRYTYPE_LOVE_MARRIAGE IndustryType = "LOVE_MARRIAGE"
INDUSTRYTYPE_POTOGRAPHY IndustryType = "POTOGRAPHY"
INDUSTRYTYPE_EDUCATION IndustryType = "EDUCATION"
INDUSTRYTYPE_FINANCE IndustryType = "FINANCE"
INDUSTRYTYPE_TOURISM IndustryType = "TOURISM"
INDUSTRYTYPE_SKINCARE IndustryType = "SKINCARE"
INDUSTRYTYPE_FOOD IndustryType = "FOOD"
INDUSTRYTYPE_SPORT IndustryType = "SPORT"
INDUSTRYTYPE_JEWELRY_WATCH IndustryType = "JEWELRY_WATCH"
INDUSTRYTYPE_HEALTHCARE IndustryType = "HEALTHCARE"
INDUSTRYTYPE_BUSSINESS IndustryType = "BUSSINESS"
INDUSTRYTYPE_PARENTING IndustryType = "PARENTING"
INDUSTRYTYPE_CATERING IndustryType = "CATERING"
INDUSTRYTYPE_RETAIL IndustryType = "RETAIL"
INDUSTRYTYPE_SERVICES IndustryType = "SERVICES"
INDUSTRYTYPE_LAW IndustryType = "LAW"
INDUSTRYTYPE_ESTATE IndustryType = "ESTATE"
INDUSTRYTYPE_TRANSPORTATION IndustryType = "TRANSPORTATION"
INDUSTRYTYPE_ENERGY_SAVING IndustryType = "ENERGY_SAVING"
INDUSTRYTYPE_SECURITY IndustryType = "SECURITY"
INDUSTRYTYPE_BUILDING_MATERIAL IndustryType = "BUILDING_MATERIAL"
INDUSTRYTYPE_COMMUNICATION IndustryType = "COMMUNICATION"
INDUSTRYTYPE_MERCHANDISE IndustryType = "MERCHANDISE"
INDUSTRYTYPE_ASSOCIATION IndustryType = "ASSOCIATION"
INDUSTRYTYPE_COMMUNITY IndustryType = "COMMUNITY"
INDUSTRYTYPE_ONLINE_AVR IndustryType = "ONLINE_AVR"
INDUSTRYTYPE_WE_MEDIA IndustryType = "WE_MEDIA"
INDUSTRYTYPE_CAR IndustryType = "CAR"
INDUSTRYTYPE_SOFTWARE IndustryType = "SOFTWARE"
INDUSTRYTYPE_GAME IndustryType = "GAME"
INDUSTRYTYPE_CLOTHING IndustryType = "CLOTHING"
INDUSTRYTYPE_INDUSTY IndustryType = "INDUSTY"
INDUSTRYTYPE_AGRICULTURE IndustryType = "AGRICULTURE"
INDUSTRYTYPE_PUBLISHING_MEDIA IndustryType = "PUBLISHING_MEDIA"
INDUSTRYTYPE_HOME_DIGITAL IndustryType = "HOME_DIGITAL"
)

View File

@@ -0,0 +1,133 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &SetAdvertisingIndustryFilterRequest{
SubMchid: wxpay_utility.String("1900000109"),
AdvertisingIndustryFilters: []IndustryType{INDUSTRYTYPE_E_COMMERCE},
}
err = SetAdvertisingIndustryFilter(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Println("请求成功")
}
func SetAdvertisingIndustryFilter(config *wxpay_utility.MchConfig, request *SetAdvertisingIndustryFilterRequest) (err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/goldplan/merchants/set-advertising-industry-filter"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return err
}
reqBody, err := json.Marshal(request)
if err != nil {
return err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return err
}
return nil
} else {
return wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type SetAdvertisingIndustryFilterRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
AdvertisingIndustryFilters []IndustryType `json:"advertising_industry_filters,omitempty"`
}
type IndustryType string
func (e IndustryType) Ptr() *IndustryType { return &e }
const (
INDUSTRYTYPE_E_COMMERCE IndustryType = "E_COMMERCE"
INDUSTRYTYPE_LOVE_MARRIAGE IndustryType = "LOVE_MARRIAGE"
INDUSTRYTYPE_POTOGRAPHY IndustryType = "POTOGRAPHY"
INDUSTRYTYPE_EDUCATION IndustryType = "EDUCATION"
INDUSTRYTYPE_FINANCE IndustryType = "FINANCE"
INDUSTRYTYPE_TOURISM IndustryType = "TOURISM"
INDUSTRYTYPE_SKINCARE IndustryType = "SKINCARE"
INDUSTRYTYPE_FOOD IndustryType = "FOOD"
INDUSTRYTYPE_SPORT IndustryType = "SPORT"
INDUSTRYTYPE_JEWELRY_WATCH IndustryType = "JEWELRY_WATCH"
INDUSTRYTYPE_HEALTHCARE IndustryType = "HEALTHCARE"
INDUSTRYTYPE_BUSSINESS IndustryType = "BUSSINESS"
INDUSTRYTYPE_PARENTING IndustryType = "PARENTING"
INDUSTRYTYPE_CATERING IndustryType = "CATERING"
INDUSTRYTYPE_RETAIL IndustryType = "RETAIL"
INDUSTRYTYPE_SERVICES IndustryType = "SERVICES"
INDUSTRYTYPE_LAW IndustryType = "LAW"
INDUSTRYTYPE_ESTATE IndustryType = "ESTATE"
INDUSTRYTYPE_TRANSPORTATION IndustryType = "TRANSPORTATION"
INDUSTRYTYPE_ENERGY_SAVING IndustryType = "ENERGY_SAVING"
INDUSTRYTYPE_SECURITY IndustryType = "SECURITY"
INDUSTRYTYPE_BUILDING_MATERIAL IndustryType = "BUILDING_MATERIAL"
INDUSTRYTYPE_COMMUNICATION IndustryType = "COMMUNICATION"
INDUSTRYTYPE_MERCHANDISE IndustryType = "MERCHANDISE"
INDUSTRYTYPE_ASSOCIATION IndustryType = "ASSOCIATION"
INDUSTRYTYPE_COMMUNITY IndustryType = "COMMUNITY"
INDUSTRYTYPE_ONLINE_AVR IndustryType = "ONLINE_AVR"
INDUSTRYTYPE_WE_MEDIA IndustryType = "WE_MEDIA"
INDUSTRYTYPE_CAR IndustryType = "CAR"
INDUSTRYTYPE_SOFTWARE IndustryType = "SOFTWARE"
INDUSTRYTYPE_GAME IndustryType = "GAME"
INDUSTRYTYPE_CLOTHING IndustryType = "CLOTHING"
INDUSTRYTYPE_INDUSTY IndustryType = "INDUSTY"
INDUSTRYTYPE_AGRICULTURE IndustryType = "AGRICULTURE"
INDUSTRYTYPE_PUBLISHING_MEDIA IndustryType = "PUBLISHING_MEDIA"
INDUSTRYTYPE_HOME_DIGITAL IndustryType = "HOME_DIGITAL"
)

View File

@@ -0,0 +1,142 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &AddReceiverRequest{
SubMchid: wxpay_utility.String("1900000109"),
Appid: wxpay_utility.String("wx8888888888888888"),
SubAppid: wxpay_utility.String("wx8888888888888889"),
Type: RECEIVERTYPE_MERCHANT_ID.Ptr(),
Account: wxpay_utility.String("86693852"),
Name: wxpay_utility.String("hu89ohu89ohu89o"), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
RelationType: RECEIVERRELATIONTYPE_STORE.Ptr(),
CustomRelation: wxpay_utility.String("代理商"),
}
response, err := AddReceiver(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func AddReceiver(config *wxpay_utility.MchConfig, request *AddReceiverRequest) (response *AddReceiverResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/profitsharing/receivers/add"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &AddReceiverResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type AddReceiverRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
Appid *string `json:"appid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Name *string `json:"name,omitempty"`
RelationType *ReceiverRelationType `json:"relation_type,omitempty"`
CustomRelation *string `json:"custom_relation,omitempty"`
}
type AddReceiverResponse struct {
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Name *string `json:"name,omitempty"`
RelationType *ReceiverRelationType `json:"relation_type,omitempty"`
CustomRelation *string `json:"custom_relation,omitempty"`
}
type ReceiverType string
func (e ReceiverType) Ptr() *ReceiverType { return &e }
const (
RECEIVERTYPE_MERCHANT_ID ReceiverType = "MERCHANT_ID"
RECEIVERTYPE_PERSONAL_OPENID ReceiverType = "PERSONAL_OPENID"
RECEIVERTYPE_PERSONAL_SUB_OPENID ReceiverType = "PERSONAL_SUB_OPENID"
)
type ReceiverRelationType string
func (e ReceiverRelationType) Ptr() *ReceiverRelationType { return &e }
const (
RECEIVERRELATIONTYPE_STORE ReceiverRelationType = "STORE"
RECEIVERRELATIONTYPE_STAFF ReceiverRelationType = "STAFF"
RECEIVERRELATIONTYPE_STORE_OWNER ReceiverRelationType = "STORE_OWNER"
RECEIVERRELATIONTYPE_PARTNER ReceiverRelationType = "PARTNER"
RECEIVERRELATIONTYPE_HEADQUARTER ReceiverRelationType = "HEADQUARTER"
RECEIVERRELATIONTYPE_BRAND ReceiverRelationType = "BRAND"
RECEIVERRELATIONTYPE_DISTRIBUTOR ReceiverRelationType = "DISTRIBUTOR"
RECEIVERRELATIONTYPE_USER ReceiverRelationType = "USER"
RECEIVERRELATIONTYPE_SUPPLIER ReceiverRelationType = "SUPPLIER"
RECEIVERRELATIONTYPE_CUSTOM ReceiverRelationType = "CUSTOM"
RECEIVERRELATIONTYPE_SERVICE_PROVIDER ReceiverRelationType = "SERVICE_PROVIDER"
)

View File

@@ -0,0 +1,184 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &CreateOrderRequest{
SubMchid: wxpay_utility.String("1900000109"),
Appid: wxpay_utility.String("wx8888888888888888"),
SubAppid: wxpay_utility.String("wx8888888888888889"),
TransactionId: wxpay_utility.String("4208450740201411110007820472"),
OutOrderNo: wxpay_utility.String("P20150806125346"),
Receivers: []CreateOrderReceiver{CreateOrderReceiver{
Type: wxpay_utility.String("MERCHANT_ID"),
Account: wxpay_utility.String("86693852"),
Name: wxpay_utility.String("hu89ohu89ohu89o"), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
Amount: wxpay_utility.Int64(888),
Description: wxpay_utility.String("分给商户A"),
}},
UnfreezeUnsplit: wxpay_utility.Bool(true),
}
response, err := CreateOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func CreateOrder(config *wxpay_utility.MchConfig, request *CreateOrderRequest) (response *OrdersEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/profitsharing/orders"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &OrdersEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type CreateOrderRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
Appid *string `json:"appid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
Receivers []CreateOrderReceiver `json:"receivers,omitempty"`
UnfreezeUnsplit *bool `json:"unfreeze_unsplit,omitempty"`
}
type OrdersEntity struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OrderId *string `json:"order_id,omitempty"`
State *OrderStatus `json:"state,omitempty"`
Receivers []OrderReceiverDetail `json:"receivers,omitempty"`
}
type CreateOrderReceiver struct {
Type *string `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Name *string `json:"name,omitempty"`
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
}
type OrderStatus string
func (e OrderStatus) Ptr() *OrderStatus { return &e }
const (
ORDERSTATUS_PROCESSING OrderStatus = "PROCESSING"
ORDERSTATUS_FINISHED OrderStatus = "FINISHED"
)
type OrderReceiverDetail struct {
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Result *DetailStatus `json:"result,omitempty"`
FailReason *DetailFailReason `json:"fail_reason,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
DetailId *string `json:"detail_id,omitempty"`
}
type ReceiverType string
func (e ReceiverType) Ptr() *ReceiverType { return &e }
const (
RECEIVERTYPE_MERCHANT_ID ReceiverType = "MERCHANT_ID"
RECEIVERTYPE_PERSONAL_OPENID ReceiverType = "PERSONAL_OPENID"
RECEIVERTYPE_PERSONAL_SUB_OPENID ReceiverType = "PERSONAL_SUB_OPENID"
)
type DetailStatus string
func (e DetailStatus) Ptr() *DetailStatus { return &e }
const (
DETAILSTATUS_PENDING DetailStatus = "PENDING"
DETAILSTATUS_SUCCESS DetailStatus = "SUCCESS"
DETAILSTATUS_CLOSED DetailStatus = "CLOSED"
)
type DetailFailReason string
func (e DetailFailReason) Ptr() *DetailFailReason { return &e }
const (
DETAILFAILREASON_ACCOUNT_ABNORMAL DetailFailReason = "ACCOUNT_ABNORMAL"
DETAILFAILREASON_NO_RELATION DetailFailReason = "NO_RELATION"
DETAILFAILREASON_RECEIVER_HIGH_RISK DetailFailReason = "RECEIVER_HIGH_RISK"
DETAILFAILREASON_RECEIVER_REAL_NAME_NOT_VERIFIED DetailFailReason = "RECEIVER_REAL_NAME_NOT_VERIFIED"
DETAILFAILREASON_NO_AUTH DetailFailReason = "NO_AUTH"
DETAILFAILREASON_RECEIVER_RECEIPT_LIMIT DetailFailReason = "RECEIVER_RECEIPT_LIMIT"
DETAILFAILREASON_PAYER_ACCOUNT_ABNORMAL DetailFailReason = "PAYER_ACCOUNT_ABNORMAL"
DETAILFAILREASON_INVALID_REQUEST DetailFailReason = "INVALID_REQUEST"
)

View File

@@ -0,0 +1,142 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &CreateReturnOrderRequest{
SubMchid: wxpay_utility.String("1900000109"),
OrderId: wxpay_utility.String("3008450740201411110007820472"),
OutOrderNo: wxpay_utility.String("P20150806125346"),
OutReturnNo: wxpay_utility.String("R20190516001"),
ReturnMchid: wxpay_utility.String("86693852"),
Amount: wxpay_utility.Int64(10),
Description: wxpay_utility.String("用户退款"),
}
response, err := CreateReturnOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func CreateReturnOrder(config *wxpay_utility.MchConfig, request *CreateReturnOrderRequest) (response *ReturnOrdersEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/profitsharing/return-orders"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &ReturnOrdersEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type CreateReturnOrderRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
OrderId *string `json:"order_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OutReturnNo *string `json:"out_return_no,omitempty"`
ReturnMchid *string `json:"return_mchid,omitempty"`
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
}
type ReturnOrdersEntity struct {
SubMchid *string `json:"sub_mchid,omitempty"`
OrderId *string `json:"order_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OutReturnNo *string `json:"out_return_no,omitempty"`
ReturnId *string `json:"return_id,omitempty"`
ReturnMchid *string `json:"return_mchid,omitempty"`
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
Result *ReturnOrderStatus `json:"result,omitempty"`
FailReason *ReturnOrderFailReason `json:"fail_reason,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
}
type ReturnOrderStatus string
func (e ReturnOrderStatus) Ptr() *ReturnOrderStatus { return &e }
const (
RETURNORDERSTATUS_PROCESSING ReturnOrderStatus = "PROCESSING"
RETURNORDERSTATUS_SUCCESS ReturnOrderStatus = "SUCCESS"
RETURNORDERSTATUS_FAILED ReturnOrderStatus = "FAILED"
)
type ReturnOrderFailReason string
func (e ReturnOrderFailReason) Ptr() *ReturnOrderFailReason { return &e }
const (
RETURNORDERFAILREASON_ACCOUNT_ABNORMAL ReturnOrderFailReason = "ACCOUNT_ABNORMAL"
RETURNORDERFAILREASON_BALANCE_NOT_ENOUGH ReturnOrderFailReason = "BALANCE_NOT_ENOUGH"
RETURNORDERFAILREASON_TIME_OUT_CLOSED ReturnOrderFailReason = "TIME_OUT_CLOSED"
RETURNORDERFAILREASON_PAYER_ACCOUNT_ABNORMAL ReturnOrderFailReason = "PAYER_ACCOUNT_ABNORMAL"
RETURNORDERFAILREASON_INVALID_REQUEST ReturnOrderFailReason = "INVALID_REQUEST"
)

View File

@@ -0,0 +1,115 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &DeleteReceiverRequest{
SubMchid: wxpay_utility.String("1900000109"),
Appid: wxpay_utility.String("wx8888888888888888"),
SubAppid: wxpay_utility.String("wx8888888888888889"),
Type: RECEIVERTYPE_MERCHANT_ID.Ptr(),
Account: wxpay_utility.String("1900000109"),
}
response, err := DeleteReceiver(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func DeleteReceiver(config *wxpay_utility.MchConfig, request *DeleteReceiverRequest) (response *DeleteReceiverResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/profitsharing/receivers/delete"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &DeleteReceiverResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type DeleteReceiverRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
Appid *string `json:"appid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
}
type DeleteReceiverResponse struct {
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
}
type ReceiverType string
func (e ReceiverType) Ptr() *ReceiverType { return &e }
const (
RECEIVERTYPE_MERCHANT_ID ReceiverType = "MERCHANT_ID"
RECEIVERTYPE_PERSONAL_OPENID ReceiverType = "PERSONAL_OPENID"
RECEIVERTYPE_PERSONAL_SUB_OPENID ReceiverType = "PERSONAL_SUB_OPENID"
)

View File

@@ -0,0 +1,105 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryMerchantRatioRequest{
SubMchid: wxpay_utility.String("1900000109"),
}
response, err := QueryMerchantRatio(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryMerchantRatio(config *wxpay_utility.MchConfig, request *QueryMerchantRatioRequest) (response *QueryMerchantRatioResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/profitsharing/merchant-configs/{sub_mchid}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{sub_mchid}", url.PathEscape(*request.SubMchid), -1)
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &QueryMerchantRatioResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryMerchantRatioRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
}
func (o *QueryMerchantRatioRequest) MarshalJSON() ([]byte, error) {
type Alias QueryMerchantRatioRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
*Alias
}{
SubMchid: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryMerchantRatioResponse struct {
SubMchid *string `json:"sub_mchid,omitempty"`
MaxRatio *int64 `json:"max_ratio,omitempty"`
}

View File

@@ -0,0 +1,182 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryOrderRequest{
SubMchid: wxpay_utility.String("1900000109"),
TransactionId: wxpay_utility.String("4208450740201411110007820472"),
OutOrderNo: wxpay_utility.String("P20150806125346"),
}
response, err := QueryOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryOrder(config *wxpay_utility.MchConfig, request *QueryOrderRequest) (response *OrdersEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/profitsharing/orders/{out_order_no}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{out_order_no}", url.PathEscape(*request.OutOrderNo), -1)
query := reqUrl.Query()
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
if request.TransactionId != nil {
query.Add("transaction_id", *request.TransactionId)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &OrdersEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryOrderRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
}
func (o *QueryOrderRequest) MarshalJSON() ([]byte, error) {
type Alias QueryOrderRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
*Alias
}{
SubMchid: nil,
TransactionId: nil,
OutOrderNo: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type OrdersEntity struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OrderId *string `json:"order_id,omitempty"`
State *OrderStatus `json:"state,omitempty"`
Receivers []OrderReceiverDetail `json:"receivers,omitempty"`
}
type OrderStatus string
func (e OrderStatus) Ptr() *OrderStatus { return &e }
const (
ORDERSTATUS_PROCESSING OrderStatus = "PROCESSING"
ORDERSTATUS_FINISHED OrderStatus = "FINISHED"
)
type OrderReceiverDetail struct {
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Result *DetailStatus `json:"result,omitempty"`
FailReason *DetailFailReason `json:"fail_reason,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
DetailId *string `json:"detail_id,omitempty"`
}
type ReceiverType string
func (e ReceiverType) Ptr() *ReceiverType { return &e }
const (
RECEIVERTYPE_MERCHANT_ID ReceiverType = "MERCHANT_ID"
RECEIVERTYPE_PERSONAL_OPENID ReceiverType = "PERSONAL_OPENID"
RECEIVERTYPE_PERSONAL_SUB_OPENID ReceiverType = "PERSONAL_SUB_OPENID"
)
type DetailStatus string
func (e DetailStatus) Ptr() *DetailStatus { return &e }
const (
DETAILSTATUS_PENDING DetailStatus = "PENDING"
DETAILSTATUS_SUCCESS DetailStatus = "SUCCESS"
DETAILSTATUS_CLOSED DetailStatus = "CLOSED"
)
type DetailFailReason string
func (e DetailFailReason) Ptr() *DetailFailReason { return &e }
const (
DETAILFAILREASON_ACCOUNT_ABNORMAL DetailFailReason = "ACCOUNT_ABNORMAL"
DETAILFAILREASON_NO_RELATION DetailFailReason = "NO_RELATION"
DETAILFAILREASON_RECEIVER_HIGH_RISK DetailFailReason = "RECEIVER_HIGH_RISK"
DETAILFAILREASON_RECEIVER_REAL_NAME_NOT_VERIFIED DetailFailReason = "RECEIVER_REAL_NAME_NOT_VERIFIED"
DETAILFAILREASON_NO_AUTH DetailFailReason = "NO_AUTH"
DETAILFAILREASON_RECEIVER_RECEIPT_LIMIT DetailFailReason = "RECEIVER_RECEIPT_LIMIT"
DETAILFAILREASON_PAYER_ACCOUNT_ABNORMAL DetailFailReason = "PAYER_ACCOUNT_ABNORMAL"
DETAILFAILREASON_INVALID_REQUEST DetailFailReason = "INVALID_REQUEST"
)

View File

@@ -0,0 +1,105 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryOrderAmountRequest{
TransactionId: wxpay_utility.String("4208450740201411110007820472"),
}
response, err := QueryOrderAmount(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryOrderAmount(config *wxpay_utility.MchConfig, request *QueryOrderAmountRequest) (response *QueryOrderAmountResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/profitsharing/transactions/{transaction_id}/amounts"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{transaction_id}", url.PathEscape(*request.TransactionId), -1)
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &QueryOrderAmountResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryOrderAmountRequest struct {
TransactionId *string `json:"transaction_id,omitempty"`
}
func (o *QueryOrderAmountRequest) MarshalJSON() ([]byte, error) {
type Alias QueryOrderAmountRequest
a := &struct {
TransactionId *string `json:"transaction_id,omitempty"`
*Alias
}{
TransactionId: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryOrderAmountResponse struct {
TransactionId *string `json:"transaction_id,omitempty"`
UnsplitAmount *int64 `json:"unsplit_amount,omitempty"`
}

View File

@@ -0,0 +1,154 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryReturnOrderRequest{
OutReturnNo: wxpay_utility.String("R20190516001"),
SubMchid: wxpay_utility.String("1900000109"),
OutOrderNo: wxpay_utility.String("P20190806125346"),
}
response, err := QueryReturnOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryReturnOrder(config *wxpay_utility.MchConfig, request *QueryReturnOrderRequest) (response *ReturnOrdersEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/profitsharing/return-orders/{out_return_no}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{out_return_no}", url.PathEscape(*request.OutReturnNo), -1)
query := reqUrl.Query()
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
if request.OutOrderNo != nil {
query.Add("out_order_no", *request.OutOrderNo)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &ReturnOrdersEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryReturnOrderRequest struct {
OutReturnNo *string `json:"out_return_no,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
}
func (o *QueryReturnOrderRequest) MarshalJSON() ([]byte, error) {
type Alias QueryReturnOrderRequest
a := &struct {
OutReturnNo *string `json:"out_return_no,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
*Alias
}{
OutReturnNo: nil,
SubMchid: nil,
OutOrderNo: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type ReturnOrdersEntity struct {
SubMchid *string `json:"sub_mchid,omitempty"`
OrderId *string `json:"order_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OutReturnNo *string `json:"out_return_no,omitempty"`
ReturnId *string `json:"return_id,omitempty"`
ReturnMchid *string `json:"return_mchid,omitempty"`
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
Result *ReturnOrderStatus `json:"result,omitempty"`
FailReason *ReturnOrderFailReason `json:"fail_reason,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
}
type ReturnOrderStatus string
func (e ReturnOrderStatus) Ptr() *ReturnOrderStatus { return &e }
const (
RETURNORDERSTATUS_PROCESSING ReturnOrderStatus = "PROCESSING"
RETURNORDERSTATUS_SUCCESS ReturnOrderStatus = "SUCCESS"
RETURNORDERSTATUS_FAILED ReturnOrderStatus = "FAILED"
)
type ReturnOrderFailReason string
func (e ReturnOrderFailReason) Ptr() *ReturnOrderFailReason { return &e }
const (
RETURNORDERFAILREASON_ACCOUNT_ABNORMAL ReturnOrderFailReason = "ACCOUNT_ABNORMAL"
RETURNORDERFAILREASON_BALANCE_NOT_ENOUGH ReturnOrderFailReason = "BALANCE_NOT_ENOUGH"
RETURNORDERFAILREASON_TIME_OUT_CLOSED ReturnOrderFailReason = "TIME_OUT_CLOSED"
RETURNORDERFAILREASON_PAYER_ACCOUNT_ABNORMAL ReturnOrderFailReason = "PAYER_ACCOUNT_ABNORMAL"
RETURNORDERFAILREASON_INVALID_REQUEST ReturnOrderFailReason = "INVALID_REQUEST"
)

View File

@@ -0,0 +1,139 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &SplitBillRequest{
SubMchid: wxpay_utility.String("1900000109"),
BillDate: wxpay_utility.String("2019-06-11"),
TarType: SPLITBILLTARTYPE_GZIP.Ptr(),
}
response, err := SplitBill(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func SplitBill(config *wxpay_utility.MchConfig, request *SplitBillRequest) (response *SplitBillResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/profitsharing/bills"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
query := reqUrl.Query()
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
if request.BillDate != nil {
query.Add("bill_date", *request.BillDate)
}
if request.TarType != nil {
query.Add("tar_type", fmt.Sprintf("%v", *request.TarType))
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &SplitBillResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type SplitBillRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
BillDate *string `json:"bill_date,omitempty"`
TarType *SplitBillTarType `json:"tar_type,omitempty"`
}
func (o *SplitBillRequest) MarshalJSON() ([]byte, error) {
type Alias SplitBillRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
BillDate *string `json:"bill_date,omitempty"`
TarType *SplitBillTarType `json:"tar_type,omitempty"`
*Alias
}{
SubMchid: nil,
BillDate: nil,
TarType: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type SplitBillResponse struct {
HashType *SplitBillHashType `json:"hash_type,omitempty"`
HashValue *string `json:"hash_value,omitempty"`
DownloadUrl *string `json:"download_url,omitempty"`
}
type SplitBillTarType string
func (e SplitBillTarType) Ptr() *SplitBillTarType { return &e }
const (
SPLITBILLTARTYPE_GZIP SplitBillTarType = "GZIP"
)
type SplitBillHashType string
func (e SplitBillHashType) Ptr() *SplitBillHashType { return &e }
const (
SPLITBILLHASHTYPE_SHA1 SplitBillHashType = "SHA1"
)

View File

@@ -0,0 +1,164 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &UnfreezeOrderRequest{
SubMchid: wxpay_utility.String("1900000109"),
TransactionId: wxpay_utility.String("4208450740201411110007820472"),
OutOrderNo: wxpay_utility.String("P20150806125346"),
Description: wxpay_utility.String("解冻全部剩余资金"),
}
response, err := UnfreezeOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func UnfreezeOrder(config *wxpay_utility.MchConfig, request *UnfreezeOrderRequest) (response *OrdersEntity, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/profitsharing/orders/unfreeze"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &OrdersEntity{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type UnfreezeOrderRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
Description *string `json:"description,omitempty"`
}
type OrdersEntity struct {
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutOrderNo *string `json:"out_order_no,omitempty"`
OrderId *string `json:"order_id,omitempty"`
State *OrderStatus `json:"state,omitempty"`
Receivers []OrderReceiverDetail `json:"receivers,omitempty"`
}
type OrderStatus string
func (e OrderStatus) Ptr() *OrderStatus { return &e }
const (
ORDERSTATUS_PROCESSING OrderStatus = "PROCESSING"
ORDERSTATUS_FINISHED OrderStatus = "FINISHED"
)
type OrderReceiverDetail struct {
Amount *int64 `json:"amount,omitempty"`
Description *string `json:"description,omitempty"`
Type *ReceiverType `json:"type,omitempty"`
Account *string `json:"account,omitempty"`
Result *DetailStatus `json:"result,omitempty"`
FailReason *DetailFailReason `json:"fail_reason,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
DetailId *string `json:"detail_id,omitempty"`
}
type ReceiverType string
func (e ReceiverType) Ptr() *ReceiverType { return &e }
const (
RECEIVERTYPE_MERCHANT_ID ReceiverType = "MERCHANT_ID"
RECEIVERTYPE_PERSONAL_OPENID ReceiverType = "PERSONAL_OPENID"
RECEIVERTYPE_PERSONAL_SUB_OPENID ReceiverType = "PERSONAL_SUB_OPENID"
)
type DetailStatus string
func (e DetailStatus) Ptr() *DetailStatus { return &e }
const (
DETAILSTATUS_PENDING DetailStatus = "PENDING"
DETAILSTATUS_SUCCESS DetailStatus = "SUCCESS"
DETAILSTATUS_CLOSED DetailStatus = "CLOSED"
)
type DetailFailReason string
func (e DetailFailReason) Ptr() *DetailFailReason { return &e }
const (
DETAILFAILREASON_ACCOUNT_ABNORMAL DetailFailReason = "ACCOUNT_ABNORMAL"
DETAILFAILREASON_NO_RELATION DetailFailReason = "NO_RELATION"
DETAILFAILREASON_RECEIVER_HIGH_RISK DetailFailReason = "RECEIVER_HIGH_RISK"
DETAILFAILREASON_RECEIVER_REAL_NAME_NOT_VERIFIED DetailFailReason = "RECEIVER_REAL_NAME_NOT_VERIFIED"
DETAILFAILREASON_NO_AUTH DetailFailReason = "NO_AUTH"
DETAILFAILREASON_RECEIVER_RECEIPT_LIMIT DetailFailReason = "RECEIVER_RECEIPT_LIMIT"
DETAILFAILREASON_PAYER_ACCOUNT_ABNORMAL DetailFailReason = "PAYER_ACCOUNT_ABNORMAL"
DETAILFAILREASON_INVALID_REQUEST DetailFailReason = "INVALID_REQUEST"
)

View File

@@ -0,0 +1,152 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// 查询结算账户修改申请状态
// 调用频率限制100/秒。
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetApplicationRequest{
SubMchid: wxpay_utility.String("1511101111"),
ApplicationNo: wxpay_utility.String("102329389XXXX"),
AccountNumberRule: ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V1.Ptr(),
}
response, err := GetApplication(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func GetApplication(config *wxpay_utility.MchConfig, request *GetApplicationRequest) (response *SubMerchantsGetApplicationResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/apply4sub/sub_merchants/{sub_mchid}/application/{application_no}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{sub_mchid}", url.PathEscape(*request.SubMchid), -1)
reqUrl.Path = strings.Replace(reqUrl.Path, "{application_no}", url.PathEscape(*request.ApplicationNo), -1)
query := reqUrl.Query()
if request.AccountNumberRule != nil {
query.Add("account_number_rule", fmt.Sprintf("%v", *request.AccountNumberRule))
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &SubMerchantsGetApplicationResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type GetApplicationRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
ApplicationNo *string `json:"application_no,omitempty"`
AccountNumberRule *AccountNumberRule `json:"account_number_rule,omitempty"`
}
func (o *GetApplicationRequest) MarshalJSON() ([]byte, error) {
type Alias GetApplicationRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
ApplicationNo *string `json:"application_no,omitempty"`
AccountNumberRule *AccountNumberRule `json:"account_number_rule,omitempty"`
*Alias
}{
SubMchid: nil,
ApplicationNo: nil,
AccountNumberRule: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type SubMerchantsGetApplicationResponse struct {
AccountName *string `json:"account_name,omitempty"`
AccountType *BankAccountType `json:"account_type,omitempty"`
AccountBank *string `json:"account_bank,omitempty"`
BankName *string `json:"bank_name,omitempty"`
BankBranchId *string `json:"bank_branch_id,omitempty"`
AccountNumber *string `json:"account_number,omitempty"`
VerifyResult *AuditResult `json:"verify_result,omitempty"`
VerifyFailReason *string `json:"verify_fail_reason,omitempty"`
VerifyFinishTime *string `json:"verify_finish_time,omitempty"`
}
type AccountNumberRule string
func (e AccountNumberRule) Ptr() *AccountNumberRule { return &e }
const (
ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V1 AccountNumberRule = "ACCOUNT_NUMBER_RULE_MASK_V1"
ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V2 AccountNumberRule = "ACCOUNT_NUMBER_RULE_MASK_V2"
)
type BankAccountType string
func (e BankAccountType) Ptr() *BankAccountType { return &e }
const (
BANKACCOUNTTYPE_ACCOUNT_TYPE_BUSINESS BankAccountType = "ACCOUNT_TYPE_BUSINESS"
BANKACCOUNTTYPE_ACCOUNT_TYPE_PRIVATE BankAccountType = "ACCOUNT_TYPE_PRIVATE"
)
type AuditResult string
func (e AuditResult) Ptr() *AuditResult { return &e }
const (
AUDITRESULT_AUDIT_SUCCESS AuditResult = "AUDIT_SUCCESS"
AUDITRESULT_AUDITING AuditResult = "AUDITING"
AUDITRESULT_AUDIT_FAIL AuditResult = "AUDIT_FAIL"
)

View File

@@ -0,0 +1,145 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// 查询结算账户
// 调用频率限制100/秒。
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetSettlementRequest{
SubMchid: wxpay_utility.String("1900006491"),
AccountNumberRule: ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V1.Ptr(),
}
response, err := GetSettlement(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func GetSettlement(config *wxpay_utility.MchConfig, request *GetSettlementRequest) (response *Settlement, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/apply4sub/sub_merchants/{sub_mchid}/settlement"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{sub_mchid}", url.PathEscape(*request.SubMchid), -1)
query := reqUrl.Query()
if request.AccountNumberRule != nil {
query.Add("account_number_rule", fmt.Sprintf("%v", *request.AccountNumberRule))
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &Settlement{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type GetSettlementRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
AccountNumberRule *AccountNumberRule `json:"account_number_rule,omitempty"`
}
func (o *GetSettlementRequest) MarshalJSON() ([]byte, error) {
type Alias GetSettlementRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
AccountNumberRule *AccountNumberRule `json:"account_number_rule,omitempty"`
*Alias
}{
SubMchid: nil,
AccountNumberRule: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type Settlement struct {
AccountType *BankAccountType `json:"account_type,omitempty"`
AccountBank *string `json:"account_bank,omitempty"`
BankName *string `json:"bank_name,omitempty"`
BankBranchId *string `json:"bank_branch_id,omitempty"`
AccountNumber *string `json:"account_number,omitempty"`
VerifyResult *VerifyResult `json:"verify_result,omitempty"`
VerifyFailReason *string `json:"verify_fail_reason,omitempty"`
}
type AccountNumberRule string
func (e AccountNumberRule) Ptr() *AccountNumberRule { return &e }
const (
ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V1 AccountNumberRule = "ACCOUNT_NUMBER_RULE_MASK_V1"
ACCOUNTNUMBERRULE_ACCOUNT_NUMBER_RULE_MASK_V2 AccountNumberRule = "ACCOUNT_NUMBER_RULE_MASK_V2"
)
type BankAccountType string
func (e BankAccountType) Ptr() *BankAccountType { return &e }
const (
BANKACCOUNTTYPE_ACCOUNT_TYPE_BUSINESS BankAccountType = "ACCOUNT_TYPE_BUSINESS"
BANKACCOUNTTYPE_ACCOUNT_TYPE_PRIVATE BankAccountType = "ACCOUNT_TYPE_PRIVATE"
)
type VerifyResult string
func (e VerifyResult) Ptr() *VerifyResult { return &e }
const (
VERIFYRESULT_VERIFY_SUCCESS VerifyResult = "VERIFY_SUCCESS"
VERIFYRESULT_VERIFY_FAIL VerifyResult = "VERIFY_FAIL"
VERIFYRESULT_VERIFYING VerifyResult = "VERIFYING"
)

View File

@@ -0,0 +1,141 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
// 修改结算账户
//
// 服务商/电商平台(不包括支付机构、银行),可使用本接口,修改其进件且已签约特约商户/二级商户的结算银行账户。
//
// 注意:
// 1、提交结算银行账户修改申请后应答代码为"200"且系统返回申请单号,需通过"查询结算账户修改申请状态API"查询申请单处理结果。
// 申请单状态:① 审核中 ② 审核驳回 ③ 审核成功
// 2、如需查询当前生效中的银行结算账户请使用"查询结算账户API"。
// 3、特约商户/二级商户每天仅能提交5次修改申请如需继续申请请等到次日0点后重新发起。
// 4、修改结算银行卡接口调用频率限制20/min。
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &ModifySettlementRequest{
SubMchid: wxpay_utility.String("1900006491"),
AccountType: BANKACCOUNTTYPE_ACCOUNT_TYPE_BUSINESS.Ptr(),
AccountBank: wxpay_utility.String("工商银行"),
BankName: wxpay_utility.String("中国工商银行股份有限公司北京市分行营业部"),
BankBranchId: wxpay_utility.String("402713354941"),
AccountNumber: wxpay_utility.String("d+xT+MQCvrLHUVDWv/8MR/dB7TkXM2YYZlokmXzFsWs35NXUot7C0NcxIrUF5FnxqCJHkNgKtxa6RxEYyba1+VBRLnqKG2fSy/Y5qDN08Ej9zHCwJjq52Wg1VG8MRugli9YMI1fI83KGBxhuXyemgS/hqFKsfYGiOkJqjTUpgY5VqjtL2N4l4z11T0ECB/aSyVXUysOFGLVfSrUxMPZy6jWWYGvT1+4P633f+R+ki1gT4WF/2KxZOYmli385ZgVhcR30mr4/G3HBcxi13zp7FnEeOsLlvBmI1PHN4C7Rsu3WL8sPndjXTd75kPkyjqnoMRrEEaYQE8ZRGYoeorwC+w=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
AccountName: wxpay_utility.String("VyOMa+SncfM4lLha65dsxZ/xYW1zqBVVp6/W5mNkolESJU9fqgMt0lxjtuiWdhR+qUjnC2dTfuJuCOZs/Qi6kmicogGFjDC9ZxzFpdjR7AidWDuCIId5WRnRN8lGUcVyxctZZ4WcxxL2ADq57h7dZoFxNgyRYR4Y6q37LpYDccmYO5SiCkUP3rMX1CrTwKJysVhHij62HiU/P/yScImgdKrc+/MBWb1O6TT2RgwU3U6IwSZRWx4QH4EmYBLAQTdcEyUz2wuDmPA4nMSeXJVyzKl/WB+QYBh4Yj+BLT0HkA2IbTRyGX1U2wvv3N/w59Xq0pWYSXMHlmxhle2Cqj/7Cw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
}
response, err := ModifySettlement(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func ModifySettlement(config *wxpay_utility.MchConfig, request *ModifySettlementRequest) (response *ModifySettlementResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{sub_mchid}", url.PathEscape(*request.SubMchid), -1)
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &ModifySettlementResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type ModifySettlementRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
AccountType *BankAccountType `json:"account_type,omitempty"`
AccountBank *string `json:"account_bank,omitempty"`
BankName *string `json:"bank_name,omitempty"`
BankBranchId *string `json:"bank_branch_id,omitempty"`
AccountNumber *string `json:"account_number,omitempty"`
AccountName *string `json:"account_name,omitempty"`
}
func (o *ModifySettlementRequest) MarshalJSON() ([]byte, error) {
type Alias ModifySettlementRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
*Alias
}{
SubMchid: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type ModifySettlementResponse struct {
ApplicationNo *string `json:"application_no,omitempty"`
}
type BankAccountType string
func (e BankAccountType) Ptr() *BankAccountType { return &e }
const (
BANKACCOUNTTYPE_ACCOUNT_TYPE_BUSINESS BankAccountType = "ACCOUNT_TYPE_BUSINESS"
BANKACCOUNTTYPE_ACCOUNT_TYPE_PRIVATE BankAccountType = "ACCOUNT_TYPE_PRIVATE"
)

View File

@@ -0,0 +1,130 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryStateRequest{
BusinessCode: wxpay_utility.String("1900013511_10000"),
}
response, err := QueryState(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryState(config *wxpay_utility.MchConfig, request *QueryStateRequest) (response *QueryStateResp, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/applyment4sub/applyment/business_code/{business_code}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{business_code}", url.PathEscape(*request.BusinessCode), -1)
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &QueryStateResp{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryStateRequest struct {
BusinessCode *string `json:"business_code,omitempty"`
}
func (o *QueryStateRequest) MarshalJSON() ([]byte, error) {
type Alias QueryStateRequest
a := &struct {
BusinessCode *string `json:"business_code,omitempty"`
*Alias
}{
BusinessCode: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryStateResp struct {
BusinessCode *string `json:"business_code,omitempty"`
ApplymentId *int64 `json:"applyment_id,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
SignUrl *string `json:"sign_url,omitempty"`
ApplymentState *ApplymentState `json:"applyment_state,omitempty"`
ApplymentStateMsg *string `json:"applyment_state_msg,omitempty"`
AuditDetail []AuditDetail `json:"audit_detail,omitempty"`
}
type ApplymentState string
func (e ApplymentState) Ptr() *ApplymentState { return &e }
const (
APPLYMENTSTATE_APPLYMENT_STATE_EDITTING ApplymentState = "APPLYMENT_STATE_EDITTING"
APPLYMENTSTATE_APPLYMENT_STATE_AUDITING ApplymentState = "APPLYMENT_STATE_AUDITING"
APPLYMENTSTATE_APPLYMENT_STATE_REJECTED ApplymentState = "APPLYMENT_STATE_REJECTED"
APPLYMENTSTATE_APPLYMENT_STATE_TO_BE_CONFIRMED ApplymentState = "APPLYMENT_STATE_TO_BE_CONFIRMED"
APPLYMENTSTATE_APPLYMENT_STATE_TO_BE_SIGNED ApplymentState = "APPLYMENT_STATE_TO_BE_SIGNED"
APPLYMENTSTATE_APPLYMENT_STATE_FINISHED ApplymentState = "APPLYMENT_STATE_FINISHED"
APPLYMENTSTATE_APPLYMENT_STATE_CANCELED ApplymentState = "APPLYMENT_STATE_CANCELED"
APPLYMENTSTATE_APPLYMENT_STATE_SIGNING ApplymentState = "APPLYMENT_STATE_SIGNING"
)
type AuditDetail struct {
Field *string `json:"field,omitempty"`
FieldName *string `json:"field_name,omitempty"`
RejectReason *string `json:"reject_reason,omitempty"`
}

View File

@@ -0,0 +1,130 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryStateByIdRequest{
ApplymentId: wxpay_utility.Int64(2000001234567890),
}
response, err := QueryStateById(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func QueryStateById(config *wxpay_utility.MchConfig, request *QueryStateByIdRequest) (response *QueryStateResp, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/applyment4sub/applyment/applyment_id/{applyment_id}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{applyment_id}", url.PathEscape(fmt.Sprintf("%v", *request.ApplymentId)), -1)
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &QueryStateResp{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type QueryStateByIdRequest struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
}
func (o *QueryStateByIdRequest) MarshalJSON() ([]byte, error) {
type Alias QueryStateByIdRequest
a := &struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
*Alias
}{
ApplymentId: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type QueryStateResp struct {
BusinessCode *string `json:"business_code,omitempty"`
ApplymentId *int64 `json:"applyment_id,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
SignUrl *string `json:"sign_url,omitempty"`
ApplymentState *ApplymentState `json:"applyment_state,omitempty"`
ApplymentStateMsg *string `json:"applyment_state_msg,omitempty"`
AuditDetail []AuditDetail `json:"audit_detail,omitempty"`
}
type ApplymentState string
func (e ApplymentState) Ptr() *ApplymentState { return &e }
const (
APPLYMENTSTATE_APPLYMENT_STATE_EDITTING ApplymentState = "APPLYMENT_STATE_EDITTING"
APPLYMENTSTATE_APPLYMENT_STATE_AUDITING ApplymentState = "APPLYMENT_STATE_AUDITING"
APPLYMENTSTATE_APPLYMENT_STATE_REJECTED ApplymentState = "APPLYMENT_STATE_REJECTED"
APPLYMENTSTATE_APPLYMENT_STATE_TO_BE_CONFIRMED ApplymentState = "APPLYMENT_STATE_TO_BE_CONFIRMED"
APPLYMENTSTATE_APPLYMENT_STATE_TO_BE_SIGNED ApplymentState = "APPLYMENT_STATE_TO_BE_SIGNED"
APPLYMENTSTATE_APPLYMENT_STATE_FINISHED ApplymentState = "APPLYMENT_STATE_FINISHED"
APPLYMENTSTATE_APPLYMENT_STATE_CANCELED ApplymentState = "APPLYMENT_STATE_CANCELED"
APPLYMENTSTATE_APPLYMENT_STATE_SIGNING ApplymentState = "APPLYMENT_STATE_SIGNING"
)
type AuditDetail struct {
Field *string `json:"field,omitempty"`
FieldName *string `json:"field_name,omitempty"`
RejectReason *string `json:"reject_reason,omitempty"`
}

View File

@@ -0,0 +1,463 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &SubmitReq{
BusinessCode: wxpay_utility.String("1900013511_10000"),
ContactInfo: &ContactInfo{
ContactType: IDHOLDERTYPE_LEGAL.Ptr(),
ContactName: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
ContactIdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
ContactIdNumber: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
ContactIdDocCopy: wxpay_utility.String("jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
ContactIdDocCopyBack: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ"),
ContactPeriodBegin: wxpay_utility.String("2019-06-06"),
ContactPeriodEnd: wxpay_utility.String("2026-06-06"),
BusinessAuthorizationLetter: wxpay_utility.String("47ZC6GC-vnrbEny_Ie_An5-tCpqxucuxi-vByf3Gjm7KEIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
Openid: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg== 字段加密: 使用APIv3定义的方式加密"),
MobilePhone: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
ContactEmail: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
},
SubjectInfo: &SubjectInfo{
SubjectType: SUBJECTTYPE_SUBJECT_TYPE_ENTERPRISE.Ptr(),
FinanceInstitution: wxpay_utility.Bool(true),
BusinessLicenseInfo: &BusinessLicense{
LicenseCopy: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
LicenseNumber: wxpay_utility.String("123456789012345678"),
MerchantName: wxpay_utility.String("腾讯科技有限公司"),
LegalPerson: wxpay_utility.String("张三"),
LicenseAddress: wxpay_utility.String("广东省深圳市南山区xx路xx号"),
PeriodBegin: wxpay_utility.String("2019-08-01"),
PeriodEnd: wxpay_utility.String("2029-08-01"),
},
CertificateInfo: &CertificateInfo{
CertCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
CertType: CERTIFICATETYPE_CERTIFICATE_TYPE_2388.Ptr(),
CertNumber: wxpay_utility.String("111111111111"),
MerchantName: wxpay_utility.String("xx公益团体"),
CompanyAddress: wxpay_utility.String("广东省深圳市南山区xx路xx号"),
LegalPerson: wxpay_utility.String("李四"),
PeriodBegin: wxpay_utility.String("2019-08-01"),
PeriodEnd: wxpay_utility.String("2019-08-01"),
},
CertificateLetterCopy: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
FinanceInstitutionInfo: &FinanceInstitutionInfo{
FinanceType: FINANCETYPE_BANK_AGENT.Ptr(),
FinanceLicensePics: []string{"0P3ng6KTIW4-Q_l2FjmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"},
},
IdentityInfo: &IdentityInfo{
IdHolderType: IDHOLDERTYPE_LEGAL.Ptr(),
IdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
AuthorizeLetterCopy: wxpay_utility.String("47ZC6GC-vnrbEny_Ie_An5-tCpqxucuxi-vByf3Gjm7KEIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
IdCardInfo: &IdCardInfo{
IdCardCopy: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
IdCardNational: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
IdCardName: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdCardNumber: wxpay_utility.String("AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdCardAddress: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
CardPeriodBegin: wxpay_utility.String("2026-06-06"),
CardPeriodEnd: wxpay_utility.String("2026-06-06"),
},
IdDocInfo: &IdDocInfo{
IdDocCopy: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
IdDocCopyBack: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ"),
IdDocName: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdDocNumber: wxpay_utility.String("AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdDocAddress: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
DocPeriodBegin: wxpay_utility.String("2019-06-06"),
DocPeriodEnd: wxpay_utility.String("2026-06-06"),
},
Owner: wxpay_utility.Bool(true),
},
UboInfoList: []UboInfoList{UboInfoList{
UboIdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
UboIdDocCopy: wxpay_utility.String("jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdDocCopyBack: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdDocName: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdDocNumber: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdDocAddress: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboPeriodBegin: wxpay_utility.String("2019-06-06"),
UboPeriodEnd: wxpay_utility.String("2026-06-06"),
}},
},
BusinessInfo: &BusinessInfo{
MerchantShortname: wxpay_utility.String("张三餐饮店"),
ServicePhone: wxpay_utility.String("0758XXXXX"),
SalesInfo: &SalesInfo{
SalesScenesType: []SalesScenesType{SALESSCENESTYPE_SALES_SCENES_STORE},
BizStoreInfo: &StoreInfo{
BizStoreName: wxpay_utility.String("大郎烧饼"),
BizAddressCode: wxpay_utility.String("440305"),
BizStoreAddress: wxpay_utility.String("南山区xx大厦x层xxxx室"),
StoreEntrancePic: []string{"0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"},
IndoorPic: []string{"0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"},
BizSubAppid: wxpay_utility.String("wx1234567890123456"),
},
MpInfo: &MpInfo{
MpAppid: wxpay_utility.String("wx1234567890123456"),
MpSubAppid: wxpay_utility.String("wx1234567890123456"),
MpPics: []string{"example_MpPics"},
},
MiniProgramInfo: &MiniProgramInfo{
MiniProgramAppid: wxpay_utility.String("wx1234567890123456"),
MiniProgramSubAppid: wxpay_utility.String("wx1234567890123456"),
MiniProgramPics: []string{"example_MiniProgramPics"},
},
AppInfo: &AppInfo{
AppAppid: wxpay_utility.String("wx1234567890123456"),
AppSubAppid: wxpay_utility.String("wx1234567890123456"),
AppPics: []string{"example_AppPics"},
},
WebInfo: &WebInfo{
Domain: wxpay_utility.String("http://www.qq.com"),
WebAuthorisation: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
WebAppid: wxpay_utility.String("wx1234567890123456"),
},
WeworkInfo: &WeworkInfo{
SubCorpId: wxpay_utility.String("wx1234567890123456"),
WeworkPics: []string{"example_WeworkPics"},
},
},
},
SettlementInfo: &SettlementInfo{
SettlementId: wxpay_utility.String("719"),
QualificationType: wxpay_utility.String("餐饮"),
Qualifications: []string{"example_Qualifications"},
ActivitiesId: wxpay_utility.String("716"),
ActivitiesRate: wxpay_utility.String("0.6"),
ActivitiesAdditions: []string{"example_ActivitiesAdditions"},
DebitActivitiesRate: wxpay_utility.String("0.54"),
CreditActivitiesRate: wxpay_utility.String("0.54"),
},
BankAccountInfo: &BankAccountInfo{
BankAccountType: BANKACCOUNTTYPE_BANK_ACCOUNT_TYPE_CORPORATE.Ptr(),
AccountName: wxpay_utility.String("AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
AccountBank: wxpay_utility.String("工商银行"),
BankAddressCode: wxpay_utility.String("110000"),
BankBranchId: wxpay_utility.String("402713354941"),
BankName: wxpay_utility.String("施秉县农村信用合作联社城关信用社"),
AccountNumber: wxpay_utility.String("d+xT+MQCvrLHUVDWv/8MR/dB7TkXM2YYZlokmXzFsWs35NXUot7C0NcxIrUF5FnxqCJHkNgKtxa6RxEYyba1+VBRLnqKG2fSy/Y5qDN08Ej9zHCwJjq52Wg1VG8MRugli9YMI1fI83KGBxhuXyemgS/hqFKsfYGiOkJqjTUpgY5VqjtL2N4l4z11T0ECB/aSyVXUysOFGLVfSrUxMPZy6jWWYGvT1+4P633f+R+ki1gT4WF/2KxZOYmli385ZgVhcR30mr4/G3HBcxi13zp7FnEeOsLlvBmI1PHN4C7Rsu3WL8sPndjXTd75kPkyjqnoMRrEEaYQE8ZRGYoeorwC+w=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
},
AdditionInfo: &AdditionInfo{
LegalPersonCommitment: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
LegalPersonVideo: wxpay_utility.String("47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4"),
BusinessAdditionPics: []string{"example_BusinessAdditionPics"},
BusinessAdditionMsg: wxpay_utility.String("特殊情况,说明原因"),
},
}
response, err := Submit(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func Submit(config *wxpay_utility.MchConfig, request *SubmitReq) (response *SubmitResp, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/applyment4sub/applyment/"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &SubmitResp{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type SubmitReq struct {
BusinessCode *string `json:"business_code,omitempty"`
ContactInfo *ContactInfo `json:"contact_info,omitempty"`
SubjectInfo *SubjectInfo `json:"subject_info,omitempty"`
BusinessInfo *BusinessInfo `json:"business_info,omitempty"`
SettlementInfo *SettlementInfo `json:"settlement_info,omitempty"`
BankAccountInfo *BankAccountInfo `json:"bank_account_info,omitempty"`
AdditionInfo *AdditionInfo `json:"addition_info,omitempty"`
}
type SubmitResp struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
}
type ContactInfo struct {
ContactType *IdHolderType `json:"contact_type,omitempty"`
ContactName *string `json:"contact_name,omitempty"`
ContactIdDocType *IdentificationType `json:"contact_id_doc_type,omitempty"`
ContactIdNumber *string `json:"contact_id_number,omitempty"`
ContactIdDocCopy *string `json:"contact_id_doc_copy,omitempty"`
ContactIdDocCopyBack *string `json:"contact_id_doc_copy_back,omitempty"`
ContactPeriodBegin *string `json:"contact_period_begin,omitempty"`
ContactPeriodEnd *string `json:"contact_period_end,omitempty"`
BusinessAuthorizationLetter *string `json:"business_authorization_letter,omitempty"`
Openid *string `json:"openid,omitempty"`
MobilePhone *string `json:"mobile_phone,omitempty"`
ContactEmail *string `json:"contact_email,omitempty"`
}
type SubjectInfo struct {
SubjectType *SubjectType `json:"subject_type,omitempty"`
FinanceInstitution *bool `json:"finance_institution,omitempty"`
BusinessLicenseInfo *BusinessLicense `json:"business_license_info,omitempty"`
CertificateInfo *CertificateInfo `json:"certificate_info,omitempty"`
CertificateLetterCopy *string `json:"certificate_letter_copy,omitempty"`
FinanceInstitutionInfo *FinanceInstitutionInfo `json:"finance_institution_info,omitempty"`
IdentityInfo *IdentityInfo `json:"identity_info,omitempty"`
UboInfoList []UboInfoList `json:"ubo_info_list,omitempty"`
}
type BusinessInfo struct {
MerchantShortname *string `json:"merchant_shortname,omitempty"`
ServicePhone *string `json:"service_phone,omitempty"`
SalesInfo *SalesInfo `json:"sales_info,omitempty"`
}
type SettlementInfo struct {
SettlementId *string `json:"settlement_id,omitempty"`
QualificationType *string `json:"qualification_type,omitempty"`
Qualifications []string `json:"qualifications,omitempty"`
ActivitiesId *string `json:"activities_id,omitempty"`
ActivitiesRate *string `json:"activities_rate,omitempty"`
ActivitiesAdditions []string `json:"activities_additions,omitempty"`
DebitActivitiesRate *string `json:"debit_activities_rate,omitempty"`
CreditActivitiesRate *string `json:"credit_activities_rate,omitempty"`
}
type BankAccountInfo struct {
BankAccountType *BankAccountType `json:"bank_account_type,omitempty"`
AccountName *string `json:"account_name,omitempty"`
AccountBank *string `json:"account_bank,omitempty"`
BankAddressCode *string `json:"bank_address_code,omitempty"`
BankBranchId *string `json:"bank_branch_id,omitempty"`
BankName *string `json:"bank_name,omitempty"`
AccountNumber *string `json:"account_number,omitempty"`
}
type AdditionInfo struct {
LegalPersonCommitment *string `json:"legal_person_commitment,omitempty"`
LegalPersonVideo *string `json:"legal_person_video,omitempty"`
BusinessAdditionPics []string `json:"business_addition_pics,omitempty"`
BusinessAdditionMsg *string `json:"business_addition_msg,omitempty"`
}
type IdHolderType string
func (e IdHolderType) Ptr() *IdHolderType { return &e }
const (
IDHOLDERTYPE_LEGAL IdHolderType = "LEGAL"
IDHOLDERTYPE_SUPER IdHolderType = "SUPER"
)
type IdentificationType string
func (e IdentificationType) Ptr() *IdentificationType { return &e }
const (
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD IdentificationType = "IDENTIFICATION_TYPE_IDCARD"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_OVERSEA_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_OVERSEA_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_MACAO_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_MACAO_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_FOREIGN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_FOREIGN_RESIDENT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_RESIDENT"
)
type SubjectType string
func (e SubjectType) Ptr() *SubjectType { return &e }
const (
SUBJECTTYPE_SUBJECT_TYPE_ENTERPRISE SubjectType = "SUBJECT_TYPE_ENTERPRISE"
SUBJECTTYPE_SUBJECT_TYPE_INSTITUTIONS SubjectType = "SUBJECT_TYPE_INSTITUTIONS"
SUBJECTTYPE_SUBJECT_TYPE_INDIVIDUAL SubjectType = "SUBJECT_TYPE_INDIVIDUAL"
SUBJECTTYPE_SUBJECT_TYPE_OTHERS SubjectType = "SUBJECT_TYPE_OTHERS"
SUBJECTTYPE_SUBJECT_TYPE_GOVERNMENT SubjectType = "SUBJECT_TYPE_GOVERNMENT"
)
type BusinessLicense struct {
LicenseCopy *string `json:"license_copy,omitempty"`
LicenseNumber *string `json:"license_number,omitempty"`
MerchantName *string `json:"merchant_name,omitempty"`
LegalPerson *string `json:"legal_person,omitempty"`
LicenseAddress *string `json:"license_address,omitempty"`
PeriodBegin *string `json:"period_begin,omitempty"`
PeriodEnd *string `json:"period_end,omitempty"`
}
type CertificateInfo struct {
CertCopy *string `json:"cert_copy,omitempty"`
CertType *CertificateType `json:"cert_type,omitempty"`
CertNumber *string `json:"cert_number,omitempty"`
MerchantName *string `json:"merchant_name,omitempty"`
CompanyAddress *string `json:"company_address,omitempty"`
LegalPerson *string `json:"legal_person,omitempty"`
PeriodBegin *string `json:"period_begin,omitempty"`
PeriodEnd *string `json:"period_end,omitempty"`
}
type FinanceInstitutionInfo struct {
FinanceType *FinanceType `json:"finance_type,omitempty"`
FinanceLicensePics []string `json:"finance_license_pics,omitempty"`
}
type IdentityInfo struct {
IdHolderType *IdHolderType `json:"id_holder_type,omitempty"`
IdDocType *IdentificationType `json:"id_doc_type,omitempty"`
AuthorizeLetterCopy *string `json:"authorize_letter_copy,omitempty"`
IdCardInfo *IdCardInfo `json:"id_card_info,omitempty"`
IdDocInfo *IdDocInfo `json:"id_doc_info,omitempty"`
Owner *bool `json:"owner,omitempty"`
}
type UboInfoList struct {
UboIdDocType *IdentificationType `json:"ubo_id_doc_type,omitempty"`
UboIdDocCopy *string `json:"ubo_id_doc_copy,omitempty"`
UboIdDocCopyBack *string `json:"ubo_id_doc_copy_back,omitempty"`
UboIdDocName *string `json:"ubo_id_doc_name,omitempty"`
UboIdDocNumber *string `json:"ubo_id_doc_number,omitempty"`
UboIdDocAddress *string `json:"ubo_id_doc_address,omitempty"`
UboPeriodBegin *string `json:"ubo_period_begin,omitempty"`
UboPeriodEnd *string `json:"ubo_period_end,omitempty"`
}
type SalesInfo struct {
SalesScenesType []SalesScenesType `json:"sales_scenes_type,omitempty"`
BizStoreInfo *StoreInfo `json:"biz_store_info,omitempty"`
MpInfo *MpInfo `json:"mp_info,omitempty"`
MiniProgramInfo *MiniProgramInfo `json:"mini_program_info,omitempty"`
AppInfo *AppInfo `json:"app_info,omitempty"`
WebInfo *WebInfo `json:"web_info,omitempty"`
WeworkInfo *WeworkInfo `json:"wework_info,omitempty"`
}
type BankAccountType string
func (e BankAccountType) Ptr() *BankAccountType { return &e }
const (
BANKACCOUNTTYPE_BANK_ACCOUNT_TYPE_CORPORATE BankAccountType = "BANK_ACCOUNT_TYPE_CORPORATE"
BANKACCOUNTTYPE_BANK_ACCOUNT_TYPE_PERSONAL BankAccountType = "BANK_ACCOUNT_TYPE_PERSONAL"
)
type CertificateType string
func (e CertificateType) Ptr() *CertificateType { return &e }
const (
CERTIFICATETYPE_CERTIFICATE_TYPE_2388 CertificateType = "CERTIFICATE_TYPE_2388"
CERTIFICATETYPE_CERTIFICATE_TYPE_2389 CertificateType = "CERTIFICATE_TYPE_2389"
CERTIFICATETYPE_CERTIFICATE_TYPE_2394 CertificateType = "CERTIFICATE_TYPE_2394"
CERTIFICATETYPE_CERTIFICATE_TYPE_2395 CertificateType = "CERTIFICATE_TYPE_2395"
CERTIFICATETYPE_CERTIFICATE_TYPE_2396 CertificateType = "CERTIFICATE_TYPE_2396"
CERTIFICATETYPE_CERTIFICATE_TYPE_2399 CertificateType = "CERTIFICATE_TYPE_2399"
CERTIFICATETYPE_CERTIFICATE_TYPE_2400 CertificateType = "CERTIFICATE_TYPE_2400"
CERTIFICATETYPE_CERTIFICATE_TYPE_2391 CertificateType = "CERTIFICATE_TYPE_2391"
CERTIFICATETYPE_CERTIFICATE_TYPE_2520 CertificateType = "CERTIFICATE_TYPE_2520"
CERTIFICATETYPE_CERTIFICATE_TYPE_2521 CertificateType = "CERTIFICATE_TYPE_2521"
CERTIFICATETYPE_CERTIFICATE_TYPE_2522 CertificateType = "CERTIFICATE_TYPE_2522"
)
type FinanceType string
func (e FinanceType) Ptr() *FinanceType { return &e }
const (
FINANCETYPE_BANK_AGENT FinanceType = "BANK_AGENT"
FINANCETYPE_PAYMENT_AGENT FinanceType = "PAYMENT_AGENT"
FINANCETYPE_INSURANCE FinanceType = "INSURANCE"
FINANCETYPE_TRADE_AND_SETTLE FinanceType = "TRADE_AND_SETTLE"
FINANCETYPE_OTHER FinanceType = "OTHER"
)
type IdCardInfo struct {
IdCardCopy *string `json:"id_card_copy,omitempty"`
IdCardNational *string `json:"id_card_national,omitempty"`
IdCardName *string `json:"id_card_name,omitempty"`
IdCardNumber *string `json:"id_card_number,omitempty"`
IdCardAddress *string `json:"id_card_address,omitempty"`
CardPeriodBegin *string `json:"card_period_begin,omitempty"`
CardPeriodEnd *string `json:"card_period_end,omitempty"`
}
type IdDocInfo struct {
IdDocCopy *string `json:"id_doc_copy,omitempty"`
IdDocCopyBack *string `json:"id_doc_copy_back,omitempty"`
IdDocName *string `json:"id_doc_name,omitempty"`
IdDocNumber *string `json:"id_doc_number,omitempty"`
IdDocAddress *string `json:"id_doc_address,omitempty"`
DocPeriodBegin *string `json:"doc_period_begin,omitempty"`
DocPeriodEnd *string `json:"doc_period_end,omitempty"`
}
type SalesScenesType string
func (e SalesScenesType) Ptr() *SalesScenesType { return &e }
const (
SALESSCENESTYPE_SALES_SCENES_STORE SalesScenesType = "SALES_SCENES_STORE"
SALESSCENESTYPE_SALES_SCENES_MP SalesScenesType = "SALES_SCENES_MP"
SALESSCENESTYPE_SALES_SCENES_MINI_PROGRAM SalesScenesType = "SALES_SCENES_MINI_PROGRAM"
SALESSCENESTYPE_SALES_SCENES_WEB SalesScenesType = "SALES_SCENES_WEB"
SALESSCENESTYPE_SALES_SCENES_APP SalesScenesType = "SALES_SCENES_APP"
SALESSCENESTYPE_SALES_SCENES_WEWORK SalesScenesType = "SALES_SCENES_WEWORK"
)
type StoreInfo struct {
BizStoreName *string `json:"biz_store_name,omitempty"`
BizAddressCode *string `json:"biz_address_code,omitempty"`
BizStoreAddress *string `json:"biz_store_address,omitempty"`
StoreEntrancePic []string `json:"store_entrance_pic,omitempty"`
IndoorPic []string `json:"indoor_pic,omitempty"`
BizSubAppid *string `json:"biz_sub_appid,omitempty"`
}
type MpInfo struct {
MpAppid *string `json:"mp_appid,omitempty"`
MpSubAppid *string `json:"mp_sub_appid,omitempty"`
MpPics []string `json:"mp_pics,omitempty"`
}
type MiniProgramInfo struct {
MiniProgramAppid *string `json:"mini_program_appid,omitempty"`
MiniProgramSubAppid *string `json:"mini_program_sub_appid,omitempty"`
MiniProgramPics []string `json:"mini_program_pics,omitempty"`
}
type AppInfo struct {
AppAppid *string `json:"app_appid,omitempty"`
AppSubAppid *string `json:"app_sub_appid,omitempty"`
AppPics []string `json:"app_pics,omitempty"`
}
type WebInfo struct {
Domain *string `json:"domain,omitempty"`
WebAuthorisation *string `json:"web_authorisation,omitempty"`
WebAppid *string `json:"web_appid,omitempty"`
}
type WeworkInfo struct {
SubCorpId *string `json:"sub_corp_id,omitempty"`
WeworkPics []string `json:"wework_pics,omitempty"`
}

View File

@@ -0,0 +1,197 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerApiv3CommonPrepayRequest{
SpAppid: wxpay_utility.String("wx8888888888888888"),
SpMchid: wxpay_utility.String("1230000109"),
SubAppid: wxpay_utility.String("wxd678efh567hg6999"),
SubMchid: wxpay_utility.String("1900000109"),
Description: wxpay_utility.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
TimeExpire: wxpay_utility.Time(time.Now()),
Attach: wxpay_utility.String("自定义数据说明"),
NotifyUrl: wxpay_utility.String(" https://www.weixin.qq.com/wxpay/pay.php"),
GoodsTag: wxpay_utility.String("WXG"),
SettleInfo: &PartnerSettleInfo{
ProfitSharing: wxpay_utility.Bool(true),
},
SupportFapiao: wxpay_utility.Bool(false),
Amount: &CommonAmountInfo{
Total: wxpay_utility.Int64(100),
Currency: wxpay_utility.String("CNY"),
},
Detail: &CouponInfo{
CostPrice: wxpay_utility.Int64(608800),
InvoiceId: wxpay_utility.String("微信123"),
GoodsDetail: []GoodsDetail{
GoodsDetail{
MerchantGoodsId: wxpay_utility.String("1246464644"),
WechatpayGoodsId: wxpay_utility.String("1001"),
GoodsName: wxpay_utility.String("iPhoneX 256G"),
Quantity: wxpay_utility.Int64(1),
UnitPrice: wxpay_utility.Int64(528800),
},
},
},
SceneInfo: &CommonSceneInfo{
PayerClientIp: wxpay_utility.String("14.23.150.211"),
DeviceId: wxpay_utility.String("013467007045764"),
StoreInfo: &StoreInfo{
Id: wxpay_utility.String("0001"),
Name: wxpay_utility.String("腾讯大厦分店"),
AreaCode: wxpay_utility.String("440305"),
Address: wxpay_utility.String("广东省深圳市南山区科技中一道10000号"),
},
},
}
response, err := PartnerAppPrepay(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerAppPrepay(config *wxpay_utility.MchConfig, request *PartnerApiv3CommonPrepayRequest) (response *PartnerApiv3AppPrepayResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/pay/partner/transactions/app"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &PartnerApiv3AppPrepayResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type PartnerApiv3CommonPrepayRequest struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
Description *string `json:"description,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TimeExpire *time.Time `json:"time_expire,omitempty"`
Attach *string `json:"attach,omitempty"`
NotifyUrl *string `json:"notify_url,omitempty"`
GoodsTag *string `json:"goods_tag,omitempty"`
SettleInfo *PartnerSettleInfo `json:"settle_info,omitempty"`
SupportFapiao *bool `json:"support_fapiao,omitempty"`
Amount *CommonAmountInfo `json:"amount,omitempty"`
Detail *CouponInfo `json:"detail,omitempty"`
SceneInfo *CommonSceneInfo `json:"scene_info,omitempty"`
}
type PartnerApiv3AppPrepayResponse struct {
PrepayId *string `json:"prepay_id,omitempty"`
}
type PartnerSettleInfo struct {
ProfitSharing *bool `json:"profit_sharing,omitempty"`
}
type CommonAmountInfo struct {
Total *int64 `json:"total,omitempty"`
Currency *string `json:"currency,omitempty"`
}
type CouponInfo struct {
CostPrice *int64 `json:"cost_price,omitempty"`
InvoiceId *string `json:"invoice_id,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type CommonSceneInfo struct {
PayerClientIp *string `json:"payer_client_ip,omitempty"`
DeviceId *string `json:"device_id,omitempty"`
StoreInfo *StoreInfo `json:"store_info,omitempty"`
}
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
}
type StoreInfo struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
AreaCode *string `json:"area_code,omitempty"`
Address *string `json:"address,omitempty"`
}

View File

@@ -0,0 +1,120 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &CancelApplymentRequest{
ApplymentId: wxpay_utility.Int64(20000011111),
BusinessCode: wxpay_utility.String("1900013511_10000"),
}
err = CancelApplyment(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Println("请求成功")
}
func CancelApplyment(config *wxpay_utility.MchConfig, request *CancelApplymentRequest) (err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/apply4subject/applyment/{business_code}/cancel"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{business_code}", url.PathEscape(*request.BusinessCode), -1)
query := reqUrl.Query()
if request.ApplymentId != nil {
query.Add("applyment_id", fmt.Sprintf("%v", *request.ApplymentId))
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return err
}
return nil
} else {
return wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type CancelApplymentRequest struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
BusinessCode *string `json:"business_code,omitempty"`
}
func (o *CancelApplymentRequest) MarshalJSON() ([]byte, error) {
type Alias CancelApplymentRequest
a := &struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
BusinessCode *string `json:"business_code,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
ApplymentId: nil,
BusinessCode: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}

View File

@@ -0,0 +1,149 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetAuditResultRequest{
ApplymentId: wxpay_utility.Int64(20000011111),
BusinessCode: wxpay_utility.String("1900013511_10000"),
}
response, err := GetAuditResult(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func GetAuditResult(config *wxpay_utility.MchConfig, request *GetAuditResultRequest) (response *GetAuditResultResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/apply4subject/applyment"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
query := reqUrl.Query()
if request.ApplymentId != nil {
query.Add("applyment_id", fmt.Sprintf("%v", *request.ApplymentId))
}
if request.BusinessCode != nil {
query.Add("business_code", *request.BusinessCode)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &GetAuditResultResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type GetAuditResultRequest struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
BusinessCode *string `json:"business_code,omitempty"`
}
func (o *GetAuditResultRequest) MarshalJSON() ([]byte, error) {
type Alias GetAuditResultRequest
a := &struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
BusinessCode *string `json:"business_code,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
ApplymentId: nil,
BusinessCode: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type GetAuditResultResponse struct {
ApplymentState *ApplymentState `json:"applyment_state,omitempty"`
QrcodeData *string `json:"qrcode_data,omitempty"`
RejectParam *string `json:"reject_param,omitempty"`
RejectReason *string `json:"reject_reason,omitempty"`
}
type ApplymentState string
func (e ApplymentState) Ptr() *ApplymentState {
return &e
}
const (
APPLYMENTSTATE_APPLYMENT_STATE_EDITTING ApplymentState = "APPLYMENT_STATE_EDITTING"
APPLYMENTSTATE_APPLYMENT_STATE_WAITTING_FOR_AUDIT ApplymentState = "APPLYMENT_STATE_WAITTING_FOR_AUDIT"
APPLYMENTSTATE_APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT ApplymentState = "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT"
APPLYMENTSTATE_APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON ApplymentState = "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON"
APPLYMENTSTATE_APPLYMENT_STATE_PASSED ApplymentState = "APPLYMENT_STATE_PASSED"
APPLYMENTSTATE_APPLYMENT_STATE_REJECTED ApplymentState = "APPLYMENT_STATE_REJECTED"
APPLYMENTSTATE_APPLYMENT_STATE_FREEZED ApplymentState = "APPLYMENT_STATE_FREEZED"
APPLYMENTSTATE_APPLYMENT_STATE_CANCELED ApplymentState = "APPLYMENT_STATE_CANCELED"
)

View File

@@ -0,0 +1,130 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &GetAuthorizeStateRequest{
SubMchid: wxpay_utility.String("20001111"),
}
response, err := GetAuthorizeState(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func GetAuthorizeState(config *wxpay_utility.MchConfig, request *GetAuthorizeStateRequest) (response *GetAuthorizeStateResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/apply4subject/applyment/merchants/{sub_mchid}/state"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{sub_mchid}", url.PathEscape(*request.SubMchid), -1)
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &GetAuthorizeStateResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type GetAuthorizeStateRequest struct {
SubMchid *string `json:"sub_mchid,omitempty"`
}
func (o *GetAuthorizeStateRequest) MarshalJSON() ([]byte, error) {
type Alias GetAuthorizeStateRequest
a := &struct {
SubMchid *string `json:"sub_mchid,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
SubMchid: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type GetAuthorizeStateResponse struct {
AuthorizeState *AuthorizeState `json:"authorize_state,omitempty"`
}
type AuthorizeState string
func (e AuthorizeState) Ptr() *AuthorizeState {
return &e
}
const (
AUTHORIZESTATE_AUTHORIZE_STATE_UNAUTHORIZED AuthorizeState = "AUTHORIZE_STATE_UNAUTHORIZED"
AUTHORIZESTATE_AUTHORIZE_STATE_AUTHORIZED AuthorizeState = "AUTHORIZE_STATE_AUTHORIZED"
)

View File

@@ -0,0 +1,394 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &SubmitApplymentRequest{
ChannelId: wxpay_utility.String("20001111"),
BusinessCode: wxpay_utility.String("1900013511_10000"),
ContactInfo: &ContactInfo{
Name: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3IdGdbDnuC4Eelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
Mobile: wxpay_utility.String("Oiw4DS+QVyZKC3eTd7CGvGQ1/sidmLm8mdsohkuR9jSiwXyHyVQD1OA1t+6Pb+Xn0q2HAJYLsNjh8O4S1iQgMrFohyaNms4IlDxJzujb9VA=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdCardNumber: wxpay_utility.String("pVd1HJ6zmty7/mYNxLMpRSvMRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
ContactType: IDHOLDERTYPE_LEGAL.Ptr(),
ContactIdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
ContactIdDocCopy: wxpay_utility.String("jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
ContactIdDocCopyBack: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ"),
ContactPeriodBegin: wxpay_utility.String("2019-06-06"),
ContactPeriodEnd: wxpay_utility.String("2026-06-06"),
},
SubjectInfo: &SubjectInfo{
SubjectType: SUBJECTTYPE_SUBJECT_TYPE_ENTERPRISE.Ptr(),
IsFinanceInstitution: wxpay_utility.Bool(false),
BusinessLicenceInfo: &BusinessLicenceInfo{
LicenceNumber: wxpay_utility.String("914201123033363296"),
LicenceCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
MerchantName: wxpay_utility.String("李四网络有限公司"),
LegalPerson: wxpay_utility.String("李四"),
CompanyAddress: wxpay_utility.String("广东省深圳市南山区xx路xx号"),
LicenceValidDate: wxpay_utility.String("[\"2017-10-28\",\"2037-10-28\"]"),
},
CertificateInfo: &CertificateInfo{
CertType: CERTIFICATETYPE_CERTIFICATE_TYPE_2388.Ptr(),
CertNumber: wxpay_utility.String("111111111111"),
CertCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
MerchantName: wxpay_utility.String("xx公益团体"),
LegalPerson: wxpay_utility.String("李四"),
CompanyAddress: wxpay_utility.String("广东省深圳市南山区xx路xx号"),
CertValidDate: wxpay_utility.String("[\"2017-10-28\",\"2037-10-28\"]"),
},
CompanyProveCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
AssistProveInfo: &AssitProveInfo{
MicroBizType: MICROBIZTYPE_MICRO_TYPE_STORE.Ptr(),
StoreName: wxpay_utility.String("大郎烧饼"),
StoreAddressCode: wxpay_utility.String("440305"),
StoreAddress: wxpay_utility.String("广东省深圳市南山区xx大厦x层xxxx室"),
StoreHeaderCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
StoreIndoorCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
},
SpecialOperationList: []SpecialOperation{SpecialOperation{
CategoryId: wxpay_utility.Int64(100),
OperationCopyList: []string{"0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"},
}},
FinanceInstitutionInfo: &FinanceInstitutionInfo{
FinanceType: FINANCETYPE_BANK_AGENT.Ptr(),
FinanceLicensePics: []string{"0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"},
},
},
IdentificationInfo: &IdentificationInfo{
IdHolderType: IDHOLDERTYPE_LEGAL.Ptr(),
IdentificationType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
IdentificationName: wxpay_utility.String("MZnwEx6zotwIz6ctW2/iQL5z94odwP9sKiF74RPCPztcJOScaXsaGs82HJNU3K+46ndk7pMrENiPDw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdentificationNumber: wxpay_utility.String("ZTnn5dKGCvP4csw4XTLug/+VLB+4R6nxSPQwqSpmPVZtXmye+/3s9O+y32w=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
IdentificationValidDate: wxpay_utility.String("[\"2017-10-28\",\"2037-10-28\"]"),
IdentificationFrontCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
IdentificationBackCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
AuthorizeLetterCopy: wxpay_utility.String("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo"),
Owner: wxpay_utility.Bool(false),
IdentificationAddress: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
},
UboInfo: &UboInfo{
UboIdType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
UboIdCardCopy: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdCardNational: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdDocCopy: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
UboName: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdNumber: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdCardValidDate: wxpay_utility.String("[\"2017-10-28\",\"2037-10-28\"]"),
},
AdditionInfo: &AdditionInfo{
ConfirmMchidList: []string{"example_ConfirmMchidList"},
},
UboInfoList: []UboInfoList{UboInfoList{
UboIdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(),
UboIdDocCopy: wxpay_utility.String("jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdDocCopyBack: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ"),
UboIdDocName: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdDocNumber: wxpay_utility.String("AOZdYGISxo4y44/Ug4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboIdDocAddress: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
UboPeriodBegin: wxpay_utility.String("2019-06-06"),
UboPeriodEnd: wxpay_utility.String("2026-06-06"),
}},
}
response, err := SubmitApplyment(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func SubmitApplyment(config *wxpay_utility.MchConfig, request *SubmitApplymentRequest) (response *SubmitApplymentResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/apply4subject/applyment"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &SubmitApplymentResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type SubmitApplymentRequest struct {
ChannelId *string `json:"channel_id,omitempty"`
BusinessCode *string `json:"business_code,omitempty"`
ContactInfo *ContactInfo `json:"contact_info,omitempty"`
SubjectInfo *SubjectInfo `json:"subject_info,omitempty"`
IdentificationInfo *IdentificationInfo `json:"identification_info,omitempty"`
UboInfo *UboInfo `json:"ubo_info,omitempty"`
AdditionInfo *AdditionInfo `json:"addition_info,omitempty"`
UboInfoList []UboInfoList `json:"ubo_info_list,omitempty"`
}
type SubmitApplymentResponse struct {
ApplymentId *int64 `json:"applyment_id,omitempty"`
}
type ContactInfo struct {
Name *string `json:"name,omitempty"`
Mobile *string `json:"mobile,omitempty"`
IdCardNumber *string `json:"id_card_number,omitempty"`
ContactType *IdHolderType `json:"contact_type,omitempty"`
ContactIdDocType *IdentificationType `json:"contact_id_doc_type,omitempty"`
ContactIdDocCopy *string `json:"contact_id_doc_copy,omitempty"`
ContactIdDocCopyBack *string `json:"contact_id_doc_copy_back,omitempty"`
ContactPeriodBegin *string `json:"contact_period_begin,omitempty"`
ContactPeriodEnd *string `json:"contact_period_end,omitempty"`
}
type SubjectInfo struct {
SubjectType *SubjectType `json:"subject_type,omitempty"`
IsFinanceInstitution *bool `json:"is_finance_institution,omitempty"`
BusinessLicenceInfo *BusinessLicenceInfo `json:"business_licence_info,omitempty"`
CertificateInfo *CertificateInfo `json:"certificate_info,omitempty"`
CompanyProveCopy *string `json:"company_prove_copy,omitempty"`
AssistProveInfo *AssitProveInfo `json:"assist_prove_info,omitempty"`
SpecialOperationList []SpecialOperation `json:"special_operation_list,omitempty"`
FinanceInstitutionInfo *FinanceInstitutionInfo `json:"finance_institution_info,omitempty"`
}
type IdentificationInfo struct {
IdHolderType *IdHolderType `json:"id_holder_type,omitempty"`
IdentificationType *IdentificationType `json:"identification_type,omitempty"`
IdentificationName *string `json:"identification_name,omitempty"`
IdentificationNumber *string `json:"identification_number,omitempty"`
IdentificationValidDate *string `json:"identification_valid_date,omitempty"`
IdentificationFrontCopy *string `json:"identification_front_copy,omitempty"`
IdentificationBackCopy *string `json:"identification_back_copy,omitempty"`
AuthorizeLetterCopy *string `json:"authorize_letter_copy,omitempty"`
Owner *bool `json:"owner,omitempty"`
IdentificationAddress *string `json:"identification_address,omitempty"`
}
type UboInfo struct {
UboIdType *IdentificationType `json:"ubo_id_type,omitempty"`
UboIdCardCopy *string `json:"ubo_id_card_copy,omitempty"`
UboIdCardNational *string `json:"ubo_id_card_national,omitempty"`
UboIdDocCopy *string `json:"ubo_id_doc_copy,omitempty"`
UboName *string `json:"ubo_name,omitempty"`
UboIdNumber *string `json:"ubo_id_number,omitempty"`
UboIdCardValidDate *string `json:"ubo_id_card_valid_date,omitempty"`
}
type AdditionInfo struct {
ConfirmMchidList []string `json:"confirm_mchid_list,omitempty"`
}
type UboInfoList struct {
UboIdDocType *IdentificationType `json:"ubo_id_doc_type,omitempty"`
UboIdDocCopy *string `json:"ubo_id_doc_copy,omitempty"`
UboIdDocCopyBack *string `json:"ubo_id_doc_copy_back,omitempty"`
UboIdDocName *string `json:"ubo_id_doc_name,omitempty"`
UboIdDocNumber *string `json:"ubo_id_doc_number,omitempty"`
UboIdDocAddress *string `json:"ubo_id_doc_address,omitempty"`
UboPeriodBegin *string `json:"ubo_period_begin,omitempty"`
UboPeriodEnd *string `json:"ubo_period_end,omitempty"`
}
type IdHolderType string
func (e IdHolderType) Ptr() *IdHolderType {
return &e
}
const (
IDHOLDERTYPE_LEGAL IdHolderType = "LEGAL"
IDHOLDERTYPE_SUPER IdHolderType = "SUPER"
)
type IdentificationType string
func (e IdentificationType) Ptr() *IdentificationType {
return &e
}
const (
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD IdentificationType = "IDENTIFICATION_TYPE_IDCARD"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_OVERSEA_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_OVERSEA_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_MACAO_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_MACAO_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_PASSPORT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_FOREIGN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_FOREIGN_RESIDENT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT"
IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_RESIDENT"
)
type SubjectType string
func (e SubjectType) Ptr() *SubjectType {
return &e
}
const (
SUBJECTTYPE_SUBJECT_TYPE_ENTERPRISE SubjectType = "SUBJECT_TYPE_ENTERPRISE"
SUBJECTTYPE_SUBJECT_TYPE_INSTITUTIONS_CLONED SubjectType = "SUBJECT_TYPE_INSTITUTIONS_CLONED"
SUBJECTTYPE_SUBJECT_TYPE_INDIVIDUAL SubjectType = "SUBJECT_TYPE_INDIVIDUAL"
SUBJECTTYPE_SUBJECT_TYPE_OTHERS SubjectType = "SUBJECT_TYPE_OTHERS"
SUBJECTTYPE_SUBJECT_TYPE_MICRO SubjectType = "SUBJECT_TYPE_MICRO"
SUBJECTTYPE_SUBJECT_TYPE_GOVERNMENT SubjectType = "SUBJECT_TYPE_GOVERNMENT"
)
type BusinessLicenceInfo struct {
LicenceNumber *string `json:"licence_number,omitempty"`
LicenceCopy *string `json:"licence_copy,omitempty"`
MerchantName *string `json:"merchant_name,omitempty"`
LegalPerson *string `json:"legal_person,omitempty"`
CompanyAddress *string `json:"company_address,omitempty"`
LicenceValidDate *string `json:"licence_valid_date,omitempty"`
}
type CertificateInfo struct {
CertType *CertificateType `json:"cert_type,omitempty"`
CertNumber *string `json:"cert_number,omitempty"`
CertCopy *string `json:"cert_copy,omitempty"`
MerchantName *string `json:"merchant_name,omitempty"`
LegalPerson *string `json:"legal_person,omitempty"`
CompanyAddress *string `json:"company_address,omitempty"`
CertValidDate *string `json:"cert_valid_date,omitempty"`
}
type AssitProveInfo struct {
MicroBizType *MicroBizType `json:"micro_biz_type,omitempty"`
StoreName *string `json:"store_name,omitempty"`
StoreAddressCode *string `json:"store_address_code,omitempty"`
StoreAddress *string `json:"store_address,omitempty"`
StoreHeaderCopy *string `json:"store_header_copy,omitempty"`
StoreIndoorCopy *string `json:"store_indoor_copy,omitempty"`
}
type SpecialOperation struct {
CategoryId *int64 `json:"category_id,omitempty"`
OperationCopyList []string `json:"operation_copy_list,omitempty"`
}
type FinanceInstitutionInfo struct {
FinanceType *FinanceType `json:"finance_type,omitempty"`
FinanceLicensePics []string `json:"finance_license_pics,omitempty"`
}
type CertificateType string
func (e CertificateType) Ptr() *CertificateType {
return &e
}
const (
CERTIFICATETYPE_CERTIFICATE_TYPE_2388 CertificateType = "CERTIFICATE_TYPE_2388"
CERTIFICATETYPE_CERTIFICATE_TYPE_2389 CertificateType = "CERTIFICATE_TYPE_2389"
CERTIFICATETYPE_CERTIFICATE_TYPE_2394 CertificateType = "CERTIFICATE_TYPE_2394"
CERTIFICATETYPE_CERTIFICATE_TYPE_2395 CertificateType = "CERTIFICATE_TYPE_2395"
CERTIFICATETYPE_CERTIFICATE_TYPE_2396 CertificateType = "CERTIFICATE_TYPE_2396"
CERTIFICATETYPE_CERTIFICATE_TYPE_2397 CertificateType = "CERTIFICATE_TYPE_2397"
CERTIFICATETYPE_CERTIFICATE_TYPE_2398 CertificateType = "CERTIFICATE_TYPE_2398"
CERTIFICATETYPE_CERTIFICATE_TYPE_2399 CertificateType = "CERTIFICATE_TYPE_2399"
CERTIFICATETYPE_CERTIFICATE_TYPE_2400 CertificateType = "CERTIFICATE_TYPE_2400"
CERTIFICATETYPE_CERTIFICATE_TYPE_2390 CertificateType = "CERTIFICATE_TYPE_2390"
CERTIFICATETYPE_CERTIFICATE_TYPE_2391 CertificateType = "CERTIFICATE_TYPE_2391"
CERTIFICATETYPE_CERTIFICATE_TYPE_2392 CertificateType = "CERTIFICATE_TYPE_2392"
CERTIFICATETYPE_CERTIFICATE_TYPE_2393 CertificateType = "CERTIFICATE_TYPE_2393"
CERTIFICATETYPE_CERTIFICATE_TYPE_2520 CertificateType = "CERTIFICATE_TYPE_2520"
CERTIFICATETYPE_CERTIFICATE_TYPE_2521 CertificateType = "CERTIFICATE_TYPE_2521"
CERTIFICATETYPE_CERTIFICATE_TYPE_2522 CertificateType = "CERTIFICATE_TYPE_2522"
)
type MicroBizType string
func (e MicroBizType) Ptr() *MicroBizType {
return &e
}
const (
MICROBIZTYPE_MICRO_TYPE_STORE MicroBizType = "MICRO_TYPE_STORE"
MICROBIZTYPE_MICRO_TYPE_MOBILE MicroBizType = "MICRO_TYPE_MOBILE"
MICROBIZTYPE_MICRO_TYPE_ONLINE MicroBizType = "MICRO_TYPE_ONLINE"
)
type FinanceType string
func (e FinanceType) Ptr() *FinanceType {
return &e
}
const (
FINANCETYPE_BANK_AGENT FinanceType = "BANK_AGENT"
FINANCETYPE_PAYMENT_AGENT FinanceType = "PAYMENT_AGENT"
FINANCETYPE_INSURANCE FinanceType = "INSURANCE"
FINANCETYPE_TRADE_AND_SETTLE FinanceType = "TRADE_AND_SETTLE"
FINANCETYPE_OTHER FinanceType = "OTHER"
)

View File

@@ -0,0 +1,202 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerApiv3PartnerH5PrepayRequest{
SpAppid: wxpay_utility.String("wx8888888888888888"),
SpMchid: wxpay_utility.String("1230000109"),
SubAppid: wxpay_utility.String("wxd678efh567hg6999"),
SubMchid: wxpay_utility.String("1900000109"),
Description: wxpay_utility.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
TimeExpire: wxpay_utility.Time(time.Now()),
Attach: wxpay_utility.String("自定义数据说明"),
NotifyUrl: wxpay_utility.String(" https://www.weixin.qq.com/wxpay/pay.php"),
GoodsTag: wxpay_utility.String("WXG"),
SettleInfo: &PartnerSettleInfo{
ProfitSharing: wxpay_utility.Bool(true),
},
SupportFapiao: wxpay_utility.Bool(false),
Amount: &CommonAmountInfo{
Total: wxpay_utility.Int64(100),
Currency: wxpay_utility.String("CNY"),
},
Detail: &CouponInfo{
CostPrice: wxpay_utility.Int64(608800),
InvoiceId: wxpay_utility.String("微信123"),
GoodsDetail: []GoodsDetail{
{
MerchantGoodsId: wxpay_utility.String("1246464644"),
WechatpayGoodsId: wxpay_utility.String("1001"),
GoodsName: wxpay_utility.String("iPhoneX 256G"),
Quantity: wxpay_utility.Int64(1),
UnitPrice: wxpay_utility.Int64(528800),
},
},
},
SceneInfo: &H5ReqSceneInfo{
PayerClientIp: wxpay_utility.String("14.23.150.211"),
DeviceId: wxpay_utility.String("013467007045764"),
StoreInfo: &StoreInfo{
Id: wxpay_utility.String("0001"),
Name: wxpay_utility.String("腾讯大厦分店"),
AreaCode: wxpay_utility.String("440305"),
Address: wxpay_utility.String("广东省深圳市南山区科技中一道10000号"),
},
H5Info: &H5Info{
Type: wxpay_utility.String("iOS"),
AppName: wxpay_utility.String("王者荣耀"),
AppUrl: wxpay_utility.String("https://pay.qq.com"),
BundleId: wxpay_utility.String("com.tencent.wzryiOS"),
PackageName: wxpay_utility.String("com.tencent.tmgp.sgame"),
},
},
}
response, err := PartnerH5Prepay(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerH5Prepay(config *wxpay_utility.MchConfig, request *PartnerApiv3PartnerH5PrepayRequest) (response *PartnerApiv3PartnerH5PrepayResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/pay/partner/transactions/h5"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &PartnerApiv3PartnerH5PrepayResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type PartnerApiv3PartnerH5PrepayRequest struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
Description *string `json:"description,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TimeExpire *time.Time `json:"time_expire,omitempty"`
Attach *string `json:"attach,omitempty"`
NotifyUrl *string `json:"notify_url,omitempty"`
GoodsTag *string `json:"goods_tag,omitempty"`
SettleInfo *PartnerSettleInfo `json:"settle_info,omitempty"`
SupportFapiao *bool `json:"support_fapiao,omitempty"`
Amount *CommonAmountInfo `json:"amount,omitempty"`
Detail *CouponInfo `json:"detail,omitempty"`
SceneInfo *H5ReqSceneInfo `json:"scene_info,omitempty"`
}
type PartnerApiv3PartnerH5PrepayResponse struct {
H5Url *string `json:"h5_url,omitempty"`
}
type PartnerSettleInfo struct {
ProfitSharing *bool `json:"profit_sharing,omitempty"`
}
type CommonAmountInfo struct {
Total *int64 `json:"total,omitempty"`
Currency *string `json:"currency,omitempty"`
}
type CouponInfo struct {
CostPrice *int64 `json:"cost_price,omitempty"`
InvoiceId *string `json:"invoice_id,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type H5ReqSceneInfo struct {
PayerClientIp *string `json:"payer_client_ip,omitempty"`
DeviceId *string `json:"device_id,omitempty"`
StoreInfo *StoreInfo `json:"store_info,omitempty"`
H5Info *H5Info `json:"h5_info,omitempty"`
}
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
}
type StoreInfo struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
AreaCode *string `json:"area_code,omitempty"`
Address *string `json:"address,omitempty"`
}
type H5Info struct {
Type *string `json:"type,omitempty"`
AppName *string `json:"app_name,omitempty"`
AppUrl *string `json:"app_url,omitempty"`
BundleId *string `json:"bundle_id,omitempty"`
PackageName *string `json:"package_name,omitempty"`
}

View File

@@ -0,0 +1,186 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem",
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerApiv3CommonPrepayRequest{
SpAppid: wxpay_utility.String("wx8888888888888888"),
SpMchid: wxpay_utility.String("1230000109"),
SubAppid: wxpay_utility.String("wxd678efh567hg6999"),
SubMchid: wxpay_utility.String("1900000109"),
Description: wxpay_utility.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
TimeExpire: wxpay_utility.Time(time.Now()),
Attach: wxpay_utility.String("自定义数据说明"),
NotifyUrl: wxpay_utility.String(" https://www.weixin.qq.com/wxpay/pay.php"),
GoodsTag: wxpay_utility.String("WXG"),
SettleInfo: &PartnerSettleInfo{
ProfitSharing: wxpay_utility.Bool(true),
},
SupportFapiao: wxpay_utility.Bool(false),
Amount: &CommonAmountInfo{
Total: wxpay_utility.Int64(100),
Currency: wxpay_utility.String("CNY"),
},
Detail: &CouponInfo{
CostPrice: wxpay_utility.Int64(608800),
InvoiceId: wxpay_utility.String("微信123"),
GoodsDetail: []GoodsDetail{
{
MerchantGoodsId: wxpay_utility.String("1246464644"),
WechatpayGoodsId: wxpay_utility.String("1001"),
GoodsName: wxpay_utility.String("iPhoneX 256G"),
Quantity: wxpay_utility.Int64(1),
UnitPrice: wxpay_utility.Int64(528800),
},
},
},
SceneInfo: &CommonSceneInfo{
PayerClientIp: wxpay_utility.String("14.23.150.211"),
DeviceId: wxpay_utility.String("013467007045764"),
StoreInfo: &StoreInfo{
Id: wxpay_utility.String("0001"),
Name: wxpay_utility.String("腾讯大厦分店"),
AreaCode: wxpay_utility.String("440305"),
Address: wxpay_utility.String("广东省深圳市南山区科技中一道10000号"),
},
},
}
response, err := PartnerNativePrepay(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
return
}
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerNativePrepay(config *wxpay_utility.MchConfig, request *PartnerApiv3CommonPrepayRequest) (response *PartnerApiv3PartnerNativePrepayResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/pay/partner/transactions/native"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
err = wxpay_utility.ValidateResponse(config.WechatPayPublicKeyId(), config.WechatPayPublicKey(), &httpResponse.Header, respBody)
if err != nil {
return nil, err
}
response := &PartnerApiv3PartnerNativePrepayResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(httpResponse.StatusCode, httpResponse.Header, respBody)
}
}
type PartnerApiv3CommonPrepayRequest struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
Description *string `json:"description,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TimeExpire *time.Time `json:"time_expire,omitempty"`
Attach *string `json:"attach,omitempty"`
NotifyUrl *string `json:"notify_url,omitempty"`
GoodsTag *string `json:"goods_tag,omitempty"`
SettleInfo *PartnerSettleInfo `json:"settle_info,omitempty"`
SupportFapiao *bool `json:"support_fapiao,omitempty"`
Amount *CommonAmountInfo `json:"amount,omitempty"`
Detail *CouponInfo `json:"detail,omitempty"`
SceneInfo *CommonSceneInfo `json:"scene_info,omitempty"`
}
type PartnerApiv3PartnerNativePrepayResponse struct {
CodeUrl *string `json:"code_url,omitempty"`
}
type PartnerSettleInfo struct {
ProfitSharing *bool `json:"profit_sharing,omitempty"`
}
type CommonAmountInfo struct {
Total *int64 `json:"total,omitempty"`
Currency *string `json:"currency,omitempty"`
}
type CouponInfo struct {
CostPrice *int64 `json:"cost_price,omitempty"`
InvoiceId *string `json:"invoice_id,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type CommonSceneInfo struct {
PayerClientIp *string `json:"payer_client_ip,omitempty"`
DeviceId *string `json:"device_id,omitempty"`
StoreInfo *StoreInfo `json:"store_info,omitempty"`
}
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
}
type StoreInfo struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
AreaCode *string `json:"area_code,omitempty"`
Address *string `json:"address,omitempty"`
}

View File

@@ -0,0 +1,188 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerQueryByOutTradeNoRequest{
SpMchid: wxpay_utility.String("1230000109"),
SubMchid: wxpay_utility.String("1900000109"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
}
response, err := PartnerQueryByOutTradeNo(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerQueryByOutTradeNo(config *wxpay_utility.MchConfig, request *PartnerQueryByOutTradeNoRequest) (response *PartnerApiv3PartnerQueryResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/pay/partner/transactions/out-trade-no/{out_trade_no}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{out_trade_no}", url.PathEscape(*request.OutTradeNo), -1)
query := reqUrl.Query()
if request.SpMchid != nil {
query.Add("sp_mchid", *request.SpMchid)
}
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &PartnerApiv3PartnerQueryResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type PartnerQueryByOutTradeNoRequest struct {
SpMchid *string `json:"sp_mchid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
}
func (o *PartnerQueryByOutTradeNoRequest) MarshalJSON() ([]byte, error) {
type Alias PartnerQueryByOutTradeNoRequest
a := &struct {
SpMchid *string `json:"sp_mchid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
SpMchid: nil,
SubMchid: nil,
OutTradeNo: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type PartnerApiv3PartnerQueryResponse struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
TradeType *string `json:"trade_type,omitempty"`
TradeState *string `json:"trade_state,omitempty"`
TradeStateDesc *string `json:"trade_state_desc,omitempty"`
BankType *string `json:"bank_type,omitempty"`
Attach *string `json:"attach,omitempty"`
SuccessTime *string `json:"success_time,omitempty"`
Payer *PartnerCommRespPayerInfo `json:"payer,omitempty"`
Amount *CommRespAmountInfo `json:"amount,omitempty"`
SceneInfo *CommRespSceneInfo `json:"scene_info,omitempty"`
PromotionDetail []PromotionDetail `json:"promotion_detail,omitempty"`
}
type PartnerCommRespPayerInfo struct {
SpOpenid *string `json:"sp_openid,omitempty"`
SubOpenid *string `json:"sub_openid,omitempty"`
}
type CommRespAmountInfo struct {
Total *int64 `json:"total,omitempty"`
PayerTotal *int64 `json:"payer_total,omitempty"`
Currency *string `json:"currency,omitempty"`
PayerCurrency *string `json:"payer_currency,omitempty"`
}
type CommRespSceneInfo struct {
DeviceId *string `json:"device_id,omitempty"`
}
type PromotionDetail struct {
CouponId *string `json:"coupon_id,omitempty"`
Name *string `json:"name,omitempty"`
Scope *string `json:"scope,omitempty"`
Type *string `json:"type,omitempty"`
Amount *int64 `json:"amount,omitempty"`
StockId *string `json:"stock_id,omitempty"`
WechatpayContribute *int64 `json:"wechatpay_contribute,omitempty"`
MerchantContribute *int64 `json:"merchant_contribute,omitempty"`
OtherContribute *int64 `json:"other_contribute,omitempty"`
Currency *string `json:"currency,omitempty"`
GoodsDetail []GoodsDetailInPromotion `json:"goods_detail,omitempty"`
}
type GoodsDetailInPromotion struct {
GoodsId *string `json:"goods_id,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
DiscountAmount *int64 `json:"discount_amount,omitempty"`
GoodsRemark *string `json:"goods_remark,omitempty"`
}

View File

@@ -0,0 +1,188 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerQueryByWxTradeNoRequest{
SpMchid: wxpay_utility.String("1230000109"),
SubMchid: wxpay_utility.String("1900000109"),
TransactionId: wxpay_utility.String("1217752501201407033233368018"),
}
response, err := PartnerQueryByWxTradeNo(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func PartnerQueryByWxTradeNo(config *wxpay_utility.MchConfig, request *PartnerQueryByWxTradeNoRequest) (response *PartnerApiv3PartnerQueryResponse, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/pay/partner/transactions/id/{transaction_id}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{transaction_id}", url.PathEscape(*request.TransactionId), -1)
query := reqUrl.Query()
if request.SpMchid != nil {
query.Add("sp_mchid", *request.SpMchid)
}
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &PartnerApiv3PartnerQueryResponse{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type PartnerQueryByWxTradeNoRequest struct {
SpMchid *string `json:"sp_mchid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
}
func (o *PartnerQueryByWxTradeNoRequest) MarshalJSON() ([]byte, error) {
type Alias PartnerQueryByWxTradeNoRequest
a := &struct {
SpMchid *string `json:"sp_mchid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
SpMchid: nil,
SubMchid: nil,
TransactionId: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type PartnerApiv3PartnerQueryResponse struct {
SpAppid *string `json:"sp_appid,omitempty"`
SpMchid *string `json:"sp_mchid,omitempty"`
SubAppid *string `json:"sub_appid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
TradeType *string `json:"trade_type,omitempty"`
TradeState *string `json:"trade_state,omitempty"`
TradeStateDesc *string `json:"trade_state_desc,omitempty"`
BankType *string `json:"bank_type,omitempty"`
Attach *string `json:"attach,omitempty"`
SuccessTime *string `json:"success_time,omitempty"`
Payer *PartnerCommRespPayerInfo `json:"payer,omitempty"`
Amount *CommRespAmountInfo `json:"amount,omitempty"`
SceneInfo *CommRespSceneInfo `json:"scene_info,omitempty"`
PromotionDetail []PromotionDetail `json:"promotion_detail,omitempty"`
}
type PartnerCommRespPayerInfo struct {
SpOpenid *string `json:"sp_openid,omitempty"`
SubOpenid *string `json:"sub_openid,omitempty"`
}
type CommRespAmountInfo struct {
Total *int64 `json:"total,omitempty"`
PayerTotal *int64 `json:"payer_total,omitempty"`
Currency *string `json:"currency,omitempty"`
PayerCurrency *string `json:"payer_currency,omitempty"`
}
type CommRespSceneInfo struct {
DeviceId *string `json:"device_id,omitempty"`
}
type PromotionDetail struct {
CouponId *string `json:"coupon_id,omitempty"`
Name *string `json:"name,omitempty"`
Scope *string `json:"scope,omitempty"`
Type *string `json:"type,omitempty"`
Amount *int64 `json:"amount,omitempty"`
StockId *string `json:"stock_id,omitempty"`
WechatpayContribute *int64 `json:"wechatpay_contribute,omitempty"`
MerchantContribute *int64 `json:"merchant_contribute,omitempty"`
OtherContribute *int64 `json:"other_contribute,omitempty"`
Currency *string `json:"currency,omitempty"`
GoodsDetail []GoodsDetailInPromotion `json:"goods_detail,omitempty"`
}
type GoodsDetailInPromotion struct {
GoodsId *string `json:"goods_id,omitempty"`
Quantity *int64 `json:"quantity,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
DiscountAmount *int64 `json:"discount_amount,omitempty"`
GoodsRemark *string `json:"goods_remark,omitempty"`
}

View File

@@ -0,0 +1,120 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &PartnerCloseOrderRequest{
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
SpMchid: wxpay_utility.String("1230000109"),
SubMchid: wxpay_utility.String("1900000109"),
}
err = PartnerCloseOrder(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Println("请求成功")
}
func PartnerCloseOrder(config *wxpay_utility.MchConfig, request *PartnerCloseOrderRequest) (err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{out_trade_no}", url.PathEscape(*request.OutTradeNo), -1)
reqBody, err := json.Marshal(request)
if err != nil {
return err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return err
}
return nil
} else {
return wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type PartnerCloseOrderRequest struct {
SpMchid *string `json:"sp_mchid,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
}
func (o *PartnerCloseOrderRequest) MarshalJSON() ([]byte, error) {
type Alias PartnerCloseOrderRequest
a := &struct {
OutTradeNo *string `json:"out_trade_no,omitempty"`
*Alias
}{
// 序列化时移除非 Body 字段
OutTradeNo: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}

View File

@@ -0,0 +1,283 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &CreateAbnormalRefundRequest{
RefundId: wxpay_utility.String("50000000382019052709732678859"),
SubMchid: wxpay_utility.String("1900000109"),
OutRefundNo: wxpay_utility.String("1217752501201407033233368018"),
Type: ABNORMALRECEIVETYPE_MERCHANT_BANK_CARD.Ptr(),
BankType: wxpay_utility.String("ICBC_DEBIT"),
BankAccount: wxpay_utility.String("d+xT+MQCvrLHUVDWv/8MR/dB7TkXLVfSrUxMPZy6jWWYzpRrEEaYQE8ZRGYoeorwC+w=="), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
RealName: wxpay_utility.String("UPgQcZSdq3zOayJwZ5XLrHY2dZU1W2Cd"), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/
}
response, err := CreateAbnormalRefund(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func CreateAbnormalRefund(config *wxpay_utility.MchConfig, request *CreateAbnormalRefundRequest) (response *Refund, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/refund/domestic/refunds/{refund_id}/apply-abnormal-refund"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{refund_id}", url.PathEscape(*request.RefundId), -1)
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &Refund{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type CreateAbnormalRefundRequest struct {
RefundId *string `json:"refund_id,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
OutRefundNo *string `json:"out_refund_no,omitempty"`
Type *AbnormalReceiveType `json:"type,omitempty"`
BankType *string `json:"bank_type,omitempty"`
BankAccount *string `json:"bank_account,omitempty"`
RealName *string `json:"real_name,omitempty"`
}
func (o *CreateAbnormalRefundRequest) MarshalJSON() ([]byte, error) {
type Alias CreateAbnormalRefundRequest
a := &struct {
RefundId *string `json:"refund_id,omitempty"`
*Alias
}{
RefundId: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type Refund struct {
RefundId *string `json:"refund_id,omitempty"`
OutRefundNo *string `json:"out_refund_no,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
Channel *Channel `json:"channel,omitempty"`
UserReceivedAccount *string `json:"user_received_account,omitempty"`
SuccessTime *time.Time `json:"success_time,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
Status *Status `json:"status,omitempty"`
FundsAccount *FundsAccount `json:"funds_account,omitempty"`
Amount *Amount `json:"amount,omitempty"`
PromotionDetail []Promotion `json:"promotion_detail,omitempty"`
RefundAccount *RefundAccount `json:"refund_account,omitempty"`
}
type AbnormalReceiveType string
func (e AbnormalReceiveType) Ptr() *AbnormalReceiveType {
return &e
}
const (
ABNORMALRECEIVETYPE_USER_BANK_CARD AbnormalReceiveType = "USER_BANK_CARD"
ABNORMALRECEIVETYPE_MERCHANT_BANK_CARD AbnormalReceiveType = "MERCHANT_BANK_CARD"
)
type Channel string
func (e Channel) Ptr() *Channel {
return &e
}
const (
CHANNEL_ORIGINAL Channel = "ORIGINAL"
CHANNEL_BALANCE Channel = "BALANCE"
CHANNEL_OTHER_BALANCE Channel = "OTHER_BALANCE"
CHANNEL_OTHER_BANKCARD Channel = "OTHER_BANKCARD"
)
type Status string
func (e Status) Ptr() *Status {
return &e
}
const (
STATUS_SUCCESS Status = "SUCCESS"
STATUS_CLOSED Status = "CLOSED"
STATUS_PROCESSING Status = "PROCESSING"
STATUS_ABNORMAL Status = "ABNORMAL"
)
type FundsAccount string
func (e FundsAccount) Ptr() *FundsAccount {
return &e
}
const (
FUNDSACCOUNT_UNSETTLED FundsAccount = "UNSETTLED"
FUNDSACCOUNT_AVAILABLE FundsAccount = "AVAILABLE"
FUNDSACCOUNT_UNAVAILABLE FundsAccount = "UNAVAILABLE"
FUNDSACCOUNT_OPERATION FundsAccount = "OPERATION"
FUNDSACCOUNT_BASIC FundsAccount = "BASIC"
FUNDSACCOUNT_ECNY_BASIC FundsAccount = "ECNY_BASIC"
)
type Amount struct {
Total *int64 `json:"total,omitempty"`
Refund *int64 `json:"refund,omitempty"`
From []FundsFromItem `json:"from,omitempty"`
PayerTotal *int64 `json:"payer_total,omitempty"`
PayerRefund *int64 `json:"payer_refund,omitempty"`
SettlementRefund *int64 `json:"settlement_refund,omitempty"`
SettlementTotal *int64 `json:"settlement_total,omitempty"`
DiscountRefund *int64 `json:"discount_refund,omitempty"`
Currency *string `json:"currency,omitempty"`
RefundFee *int64 `json:"refund_fee,omitempty"`
Advance *int64 `json:"advance,omitempty"`
}
type Promotion struct {
PromotionId *string `json:"promotion_id,omitempty"`
Scope *PromotionScope `json:"scope,omitempty"`
Type *PromotionType `json:"type,omitempty"`
Amount *int64 `json:"amount,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type RefundAccount string
func (e RefundAccount) Ptr() *RefundAccount {
return &e
}
const (
REFUNDACCOUNT_REFUND_SOURCE_PARTNER_ADVANCE RefundAccount = "REFUND_SOURCE_PARTNER_ADVANCE"
REFUNDACCOUNT_REFUND_SOURCE_SUB_MERCHANT RefundAccount = "REFUND_SOURCE_SUB_MERCHANT"
REFUNDACCOUNT_REFUND_SOURCE_SUB_MERCHANT_ADVANCE RefundAccount = "REFUND_SOURCE_SUB_MERCHANT_ADVANCE"
)
type FundsFromItem struct {
Account *Account `json:"account,omitempty"`
Amount *int64 `json:"amount,omitempty"`
}
type PromotionScope string
func (e PromotionScope) Ptr() *PromotionScope {
return &e
}
const (
PROMOTIONSCOPE_GLOBAL PromotionScope = "GLOBAL"
PROMOTIONSCOPE_SINGLE PromotionScope = "SINGLE"
)
type PromotionType string
func (e PromotionType) Ptr() *PromotionType {
return &e
}
const (
PROMOTIONTYPE_COUPON PromotionType = "COUPON"
PROMOTIONTYPE_DISCOUNT PromotionType = "DISCOUNT"
)
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
RefundQuantity *int64 `json:"refund_quantity,omitempty"`
}
type Account string
func (e Account) Ptr() *Account {
return &e
}
const (
ACCOUNT_AVAILABLE Account = "AVAILABLE"
ACCOUNT_UNAVAILABLE Account = "UNAVAILABLE"
)

View File

@@ -0,0 +1,279 @@
package main
import (
"bytes"
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/merchant/4015119334
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/merchant/4013070756
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &CreateRequest{
TransactionId: wxpay_utility.String("1217752501201407033233368018"),
OutTradeNo: wxpay_utility.String("1217752501201407033233368018"),
OutRefundNo: wxpay_utility.String("1217752501201407033233368018"),
Reason: wxpay_utility.String("商品已售完"),
NotifyUrl: wxpay_utility.String("https://weixin.qq.com"),
FundsAccount: REQFUNDSACCOUNT_AVAILABLE.Ptr(),
Amount: &AmountReq{
Refund: wxpay_utility.Int64(888),
From: []FundsFromItem{FundsFromItem{
Account: ACCOUNT_AVAILABLE.Ptr(),
Amount: wxpay_utility.Int64(444),
}},
Total: wxpay_utility.Int64(888),
Currency: wxpay_utility.String("CNY"),
},
GoodsDetail: []GoodsDetail{GoodsDetail{
MerchantGoodsId: wxpay_utility.String("1217752501201407033233368018"),
WechatpayGoodsId: wxpay_utility.String("1001"),
GoodsName: wxpay_utility.String("iPhone6s 16G"),
UnitPrice: wxpay_utility.Int64(528800),
RefundAmount: wxpay_utility.Int64(528800),
RefundQuantity: wxpay_utility.Int64(1),
}},
}
response, err := Create(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func Create(config *wxpay_utility.MchConfig, request *CreateRequest) (response *Refund, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "POST"
path = "/v3/refund/domestic/refunds"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqBody, err := json.Marshal(request)
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
httpRequest.Header.Set("Content-Type", "application/json")
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &Refund{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type CreateRequest struct {
TransactionId *string `json:"transaction_id,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
OutRefundNo *string `json:"out_refund_no,omitempty"`
Reason *string `json:"reason,omitempty"`
NotifyUrl *string `json:"notify_url,omitempty"`
FundsAccount *ReqFundsAccount `json:"funds_account,omitempty"`
Amount *AmountReq `json:"amount,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type Refund struct {
RefundId *string `json:"refund_id,omitempty"`
OutRefundNo *string `json:"out_refund_no,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
Channel *Channel `json:"channel,omitempty"`
UserReceivedAccount *string `json:"user_received_account,omitempty"`
SuccessTime *time.Time `json:"success_time,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
Status *Status `json:"status,omitempty"`
FundsAccount *FundsAccount `json:"funds_account,omitempty"`
Amount *Amount `json:"amount,omitempty"`
PromotionDetail []Promotion `json:"promotion_detail,omitempty"`
}
type ReqFundsAccount string
func (e ReqFundsAccount) Ptr() *ReqFundsAccount {
return &e
}
const (
REQFUNDSACCOUNT_AVAILABLE ReqFundsAccount = "AVAILABLE"
REQFUNDSACCOUNT_UNSETTLED ReqFundsAccount = "UNSETTLED"
)
type AmountReq struct {
Refund *int64 `json:"refund,omitempty"`
From []FundsFromItem `json:"from,omitempty"`
Total *int64 `json:"total,omitempty"`
Currency *string `json:"currency,omitempty"`
}
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
RefundQuantity *int64 `json:"refund_quantity,omitempty"`
}
type Channel string
func (e Channel) Ptr() *Channel {
return &e
}
const (
CHANNEL_ORIGINAL Channel = "ORIGINAL"
CHANNEL_BALANCE Channel = "BALANCE"
CHANNEL_OTHER_BALANCE Channel = "OTHER_BALANCE"
CHANNEL_OTHER_BANKCARD Channel = "OTHER_BANKCARD"
)
type Status string
func (e Status) Ptr() *Status {
return &e
}
const (
STATUS_SUCCESS Status = "SUCCESS"
STATUS_CLOSED Status = "CLOSED"
STATUS_PROCESSING Status = "PROCESSING"
STATUS_ABNORMAL Status = "ABNORMAL"
)
type FundsAccount string
func (e FundsAccount) Ptr() *FundsAccount {
return &e
}
const (
FUNDSACCOUNT_UNSETTLED FundsAccount = "UNSETTLED"
FUNDSACCOUNT_AVAILABLE FundsAccount = "AVAILABLE"
FUNDSACCOUNT_UNAVAILABLE FundsAccount = "UNAVAILABLE"
FUNDSACCOUNT_OPERATION FundsAccount = "OPERATION"
FUNDSACCOUNT_BASIC FundsAccount = "BASIC"
FUNDSACCOUNT_ECNY_BASIC FundsAccount = "ECNY_BASIC"
)
type Amount struct {
Total *int64 `json:"total,omitempty"`
Refund *int64 `json:"refund,omitempty"`
From []FundsFromItem `json:"from,omitempty"`
PayerTotal *int64 `json:"payer_total,omitempty"`
PayerRefund *int64 `json:"payer_refund,omitempty"`
SettlementRefund *int64 `json:"settlement_refund,omitempty"`
SettlementTotal *int64 `json:"settlement_total,omitempty"`
DiscountRefund *int64 `json:"discount_refund,omitempty"`
Currency *string `json:"currency,omitempty"`
RefundFee *int64 `json:"refund_fee,omitempty"`
}
type Promotion struct {
PromotionId *string `json:"promotion_id,omitempty"`
Scope *PromotionScope `json:"scope,omitempty"`
Type *PromotionType `json:"type,omitempty"`
Amount *int64 `json:"amount,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type FundsFromItem struct {
Account *Account `json:"account,omitempty"`
Amount *int64 `json:"amount,omitempty"`
}
type PromotionScope string
func (e PromotionScope) Ptr() *PromotionScope {
return &e
}
const (
PROMOTIONSCOPE_GLOBAL PromotionScope = "GLOBAL"
PROMOTIONSCOPE_SINGLE PromotionScope = "SINGLE"
)
type PromotionType string
func (e PromotionType) Ptr() *PromotionType {
return &e
}
const (
PROMOTIONTYPE_CASH PromotionType = "CASH"
PROMOTIONTYPE_NOCASH PromotionType = "NOCASH"
)
type Account string
func (e Account) Ptr() *Account {
return &e
}
const (
ACCOUNT_AVAILABLE Account = "AVAILABLE"
ACCOUNT_UNAVAILABLE Account = "UNAVAILABLE"
)

View File

@@ -0,0 +1,263 @@
package main
import (
"demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
config, err := wxpay_utility.CreateMchConfig(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径
)
if err != nil {
fmt.Println(err)
return
}
request := &QueryByOutRefundNoRequest{
OutRefundNo: wxpay_utility.String("1217752501201407033233368018"),
SubMchid: wxpay_utility.String("1900000109"),
}
response, err := QueryByOutRefundNo(config, request)
if err != nil {
fmt.Printf("请求失败: %+v\n", err)
// TODO: 请求失败,根据状态码执行不同的处理
return
}
// TODO: 请求成功,继续业务逻辑
fmt.Printf("请求成功: %+v\n", response)
}
func QueryByOutRefundNo(config *wxpay_utility.MchConfig, request *QueryByOutRefundNoRequest) (response *Refund, err error) {
const (
host = "https://api.mch.weixin.qq.com"
method = "GET"
path = "/v3/refund/domestic/refunds/{out_refund_no}"
)
reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path))
if err != nil {
return nil, err
}
reqUrl.Path = strings.Replace(reqUrl.Path, "{out_refund_no}", url.PathEscape(*request.OutRefundNo), -1)
query := reqUrl.Query()
if request.SubMchid != nil {
query.Add("sub_mchid", *request.SubMchid)
}
reqUrl.RawQuery = query.Encode()
httpRequest, err := http.NewRequest(method, reqUrl.String(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId())
authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil)
if err != nil {
return nil, err
}
httpRequest.Header.Set("Authorization", authorization)
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
respBody, err := wxpay_utility.ExtractResponseBody(httpResponse)
if err != nil {
return nil, err
}
if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 {
// 2XX 成功,验证应答签名
err = wxpay_utility.ValidateResponse(
config.WechatPayPublicKeyId(),
config.WechatPayPublicKey(),
&httpResponse.Header,
respBody,
)
if err != nil {
return nil, err
}
response := &Refund{}
if err := json.Unmarshal(respBody, response); err != nil {
return nil, err
}
return response, nil
} else {
return nil, wxpay_utility.NewApiException(
httpResponse.StatusCode,
httpResponse.Header,
respBody,
)
}
}
type QueryByOutRefundNoRequest struct {
OutRefundNo *string `json:"out_refund_no,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
}
func (o *QueryByOutRefundNoRequest) MarshalJSON() ([]byte, error) {
type Alias QueryByOutRefundNoRequest
a := &struct {
OutRefundNo *string `json:"out_refund_no,omitempty"`
SubMchid *string `json:"sub_mchid,omitempty"`
*Alias
}{
OutRefundNo: nil,
SubMchid: nil,
Alias: (*Alias)(o),
}
return json.Marshal(a)
}
type Refund struct {
RefundId *string `json:"refund_id,omitempty"`
OutRefundNo *string `json:"out_refund_no,omitempty"`
TransactionId *string `json:"transaction_id,omitempty"`
OutTradeNo *string `json:"out_trade_no,omitempty"`
Channel *Channel `json:"channel,omitempty"`
UserReceivedAccount *string `json:"user_received_account,omitempty"`
SuccessTime *time.Time `json:"success_time,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
Status *Status `json:"status,omitempty"`
FundsAccount *FundsAccount `json:"funds_account,omitempty"`
Amount *Amount `json:"amount,omitempty"`
PromotionDetail []Promotion `json:"promotion_detail,omitempty"`
RefundAccount *RefundAccount `json:"refund_account,omitempty"`
}
type Channel string
func (e Channel) Ptr() *Channel {
return &e
}
const (
CHANNEL_ORIGINAL Channel = "ORIGINAL"
CHANNEL_BALANCE Channel = "BALANCE"
CHANNEL_OTHER_BALANCE Channel = "OTHER_BALANCE"
CHANNEL_OTHER_BANKCARD Channel = "OTHER_BANKCARD"
)
type Status string
func (e Status) Ptr() *Status {
return &e
}
const (
STATUS_SUCCESS Status = "SUCCESS"
STATUS_CLOSED Status = "CLOSED"
STATUS_PROCESSING Status = "PROCESSING"
STATUS_ABNORMAL Status = "ABNORMAL"
)
type FundsAccount string
func (e FundsAccount) Ptr() *FundsAccount {
return &e
}
const (
FUNDSACCOUNT_UNSETTLED FundsAccount = "UNSETTLED"
FUNDSACCOUNT_AVAILABLE FundsAccount = "AVAILABLE"
FUNDSACCOUNT_UNAVAILABLE FundsAccount = "UNAVAILABLE"
FUNDSACCOUNT_OPERATION FundsAccount = "OPERATION"
FUNDSACCOUNT_BASIC FundsAccount = "BASIC"
FUNDSACCOUNT_ECNY_BASIC FundsAccount = "ECNY_BASIC"
)
type Amount struct {
Total *int64 `json:"total,omitempty"`
Refund *int64 `json:"refund,omitempty"`
From []FundsFromItem `json:"from,omitempty"`
PayerTotal *int64 `json:"payer_total,omitempty"`
PayerRefund *int64 `json:"payer_refund,omitempty"`
SettlementRefund *int64 `json:"settlement_refund,omitempty"`
SettlementTotal *int64 `json:"settlement_total,omitempty"`
DiscountRefund *int64 `json:"discount_refund,omitempty"`
Currency *string `json:"currency,omitempty"`
RefundFee *int64 `json:"refund_fee,omitempty"`
Advance *int64 `json:"advance,omitempty"`
}
type Promotion struct {
PromotionId *string `json:"promotion_id,omitempty"`
Scope *PromotionScope `json:"scope,omitempty"`
Type *PromotionType `json:"type,omitempty"`
Amount *int64 `json:"amount,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
GoodsDetail []GoodsDetail `json:"goods_detail,omitempty"`
}
type RefundAccount string
func (e RefundAccount) Ptr() *RefundAccount {
return &e
}
const (
REFUNDACCOUNT_REFUND_SOURCE_PARTNER_ADVANCE RefundAccount = "REFUND_SOURCE_PARTNER_ADVANCE"
REFUNDACCOUNT_REFUND_SOURCE_SUB_MERCHANT RefundAccount = "REFUND_SOURCE_SUB_MERCHANT"
REFUNDACCOUNT_REFUND_SOURCE_SUB_MERCHANT_ADVANCE RefundAccount = "REFUND_SOURCE_SUB_MERCHANT_ADVANCE"
)
type FundsFromItem struct {
Account *Account `json:"account,omitempty"`
Amount *int64 `json:"amount,omitempty"`
}
type PromotionScope string
func (e PromotionScope) Ptr() *PromotionScope {
return &e
}
const (
PROMOTIONSCOPE_GLOBAL PromotionScope = "GLOBAL"
PROMOTIONSCOPE_SINGLE PromotionScope = "SINGLE"
)
type PromotionType string
func (e PromotionType) Ptr() *PromotionType {
return &e
}
const (
PROMOTIONTYPE_COUPON PromotionType = "COUPON"
PROMOTIONTYPE_DISCOUNT PromotionType = "DISCOUNT"
)
type GoodsDetail struct {
MerchantGoodsId *string `json:"merchant_goods_id,omitempty"`
WechatpayGoodsId *string `json:"wechatpay_goods_id,omitempty"`
GoodsName *string `json:"goods_name,omitempty"`
UnitPrice *int64 `json:"unit_price,omitempty"`
RefundAmount *int64 `json:"refund_amount,omitempty"`
RefundQuantity *int64 `json:"refund_quantity,omitempty"`
}
type Account string
func (e Account) Ptr() *Account {
return &e
}
const (
ACCOUNT_AVAILABLE Account = "AVAILABLE"
ACCOUNT_UNAVAILABLE Account = "UNAVAILABLE"
)

View File

@@ -0,0 +1,34 @@
# JSAPI 调起支付
> 服务商模式与商户模式的调起支付代码完全一致,区别仅在于 `appId` 的取值:
> - 在服务商的公众号/网页中调起支付时,`appId` 传 `sp_appid`
> - 在子商户的公众号/网页中调起支付时,`appId` 传 `sub_appid`
```javascript
function onBridgeReady() {
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId": "wx2421b1c4370ec43b", //公众号ID由商户传入
"timeStamp": "1395712654", //时间戳自1970年以来的秒数
"nonceStr": "e61463f8efa94090b1f366cccfbbb444", //随机串
"package": "prepay_id=wx21201855730335ac86f8c43d1889123400",
"signType": "RSA", //微信签名方式:
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==" //微信签名
},
function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok但并不保证它绝对可靠商户需进一步调用后端查单确认支付结果。
}
});
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
```

View File

@@ -0,0 +1,266 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* JSAPI下单
*/
public class PartnerJsapiPrepay {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/partner/transactions/jsapi";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerJsapiPrepay client = new PartnerJsapiPrepay(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
PartnerAPIv3PartnerJsapiPrepayRequest request = new PartnerAPIv3PartnerJsapiPrepayRequest();
request.spAppid = "wx8888888888888888";
request.spMchid = "1230000109";
request.subAppid = "wxd678efh567hg6999";
request.subMchid = "1900000109";
request.description = "Image形象店-深圳腾大-QQ公仔";
request.outTradeNo = "1217752501201407033233368018";
request.timeExpire = "2018-06-08T10:34:56+08:00";
request.attach = "自定义数据";
request.notifyUrl = " https://www.weixin.qq.com/wxpay/pay.php";
request.goodsTag = "WXG";
request.settleInfo = new PartnerSettleInfo();
request.settleInfo.profitSharing = true;
request.supportFapiao = true;
request.amount = new CommonAmountInfo();
request.amount.total = 100L;
request.amount.currency = "CNY";
request.payer = new PartnerJsapiReqPayerInfo();
request.payer.spOpenid = "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o";
request.payer.subOpenid = "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o";
request.detail = new CouponInfo();
request.detail.costPrice = 608800L;
request.detail.invoiceId = "微信123";
request.detail.goodsDetail = new ArrayList<>();
{
GoodsDetail goodsDetailItem0 = new GoodsDetail();
goodsDetailItem0.merchantGoodsId = "1246464644";
goodsDetailItem0.wechatpayGoodsId = "1001";
goodsDetailItem0.goodsName = "iPhoneX 256G";
goodsDetailItem0.quantity = 1L;
goodsDetailItem0.unitPrice = 528800L;
request.detail.goodsDetail.add(goodsDetailItem0);
};
request.sceneInfo = new CommonSceneInfo();
request.sceneInfo.payerClientIp = "14.23.150.211";
request.sceneInfo.deviceId = "013467007045764";
request.sceneInfo.storeInfo = new StoreInfo();
request.sceneInfo.storeInfo.id = "0001";
request.sceneInfo.storeInfo.name = "腾讯大厦分店";
request.sceneInfo.storeInfo.areaCode = "440305";
request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";
try {
PartnerAPIv3PartnerJsapiPrepayResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public PartnerAPIv3PartnerJsapiPrepayResponse run(PartnerAPIv3PartnerJsapiPrepayRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, PartnerAPIv3PartnerJsapiPrepayResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerJsapiPrepay(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerAPIv3PartnerJsapiPrepayRequest {
@SerializedName("sp_appid")
public String spAppid;
@SerializedName("sp_mchid")
public String spMchid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("description")
public String description;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("time_expire")
public String timeExpire;
@SerializedName("attach")
public String attach;
@SerializedName("notify_url")
public String notifyUrl;
@SerializedName("goods_tag")
public String goodsTag;
@SerializedName("settle_info")
public PartnerSettleInfo settleInfo;
@SerializedName("support_fapiao")
public Boolean supportFapiao;
@SerializedName("amount")
public CommonAmountInfo amount;
@SerializedName("payer")
public PartnerJsapiReqPayerInfo payer;
@SerializedName("detail")
public CouponInfo detail;
@SerializedName("scene_info")
public CommonSceneInfo sceneInfo;
}
public static class PartnerAPIv3PartnerJsapiPrepayResponse {
@SerializedName("prepay_id")
public String prepayId;
}
public static class PartnerSettleInfo {
@SerializedName("profit_sharing")
public Boolean profitSharing;
}
public static class CommonAmountInfo {
@SerializedName("total")
public Long total;
@SerializedName("currency")
public String currency;
}
public static class PartnerJsapiReqPayerInfo {
@SerializedName("sp_openid")
public String spOpenid;
@SerializedName("sub_openid")
public String subOpenid;
}
public static class CouponInfo {
@SerializedName("cost_price")
public Long costPrice;
@SerializedName("invoice_id")
public String invoiceId;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public static class CommonSceneInfo {
@SerializedName("payer_client_ip")
public String payerClientIp;
@SerializedName("device_id")
public String deviceId;
@SerializedName("store_info")
public StoreInfo storeInfo;
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id")
public String merchantGoodsId;
@SerializedName("wechatpay_goods_id")
public String wechatpayGoodsId;
@SerializedName("goods_name")
public String goodsName;
@SerializedName("quantity")
public Long quantity;
@SerializedName("unit_price")
public Long unitPrice;
}
public static class StoreInfo {
@SerializedName("id")
public String id;
@SerializedName("name")
public String name;
@SerializedName("area_code")
public String areaCode;
@SerializedName("address")
public String address;
}
}

View File

@@ -0,0 +1,77 @@
# 退款结果回调通知(服务商模式)
当退款单状态发生变更时(退款成功/退款关闭/退款异常),微信支付会通过 POST 方式向服务商申请退款时传入的 `notify_url` 发送回调通知。
## 回调通知报文
```json
{
"id": "EV-2018022511223320873",
"create_time": "2018-06-08T10:34:56+08:00",
"resource_type": "encrypt-resource",
"event_type": "REFUND.SUCCESS",
"summary": "退款成功",
"resource": {
"algorithm": "AEAD_AES_256_GCM",
"original_type": "refund",
"ciphertext": "...",
"nonce": "...",
"associated_data": ""
}
}
```
## event_type 枚举
| 值 | 含义 |
|----|------|
| `REFUND.SUCCESS` | 退款成功 |
| `REFUND.ABNORMAL` | 退款异常(退款到银行发现卡作废/冻结,原路退款失败) |
| `REFUND.CLOSED` | 退款关闭 |
## 处理步骤
与支付成功回调完全一致:验签 → 应答200/204 → 解密AEAD_AES_256_GCM + APIv3 密钥)。
> 5 秒内未应答视为超时,重试机制同支付回调(最多 15 次)。需做好幂等处理。
## 解密后的业务字段
| 字段 | 说明 |
|------|------|
| `sp_mchid` | 服务商商户号 |
| `sub_mchid` | 子商户号 |
| `out_trade_no` | 商户订单号 |
| `transaction_id` | 微信支付订单号 |
| `out_refund_no` | 商户退款单号 |
| `refund_id` | 微信支付退款单号 |
| `refund_status` | 退款状态:`SUCCESS`/`CLOSED`/`PROCESSING`/`ABNORMAL` |
| `success_time` | 退款成功时间(仅 SUCCESS 时返回) |
| `user_received_account` | 退款入账账户(如"招商银行信用卡0403"、"支付用户零钱"等) |
| `amount.total` | 订单金额(分) |
| `amount.refund` | 退款金额(分) |
| `amount.payer_total` | 用户实际支付金额(分) |
| `amount.payer_refund` | 用户实际收到的现金退款金额(分) |
> 退款异常(`ABNORMAL`)时,可在服务商平台交易中心手动处理,或调用发起异常退款接口处理。
## 解密后示例
```json
{
"mchid": "1900000100",
"transaction_id": "1008450740201411110005820873",
"out_trade_no": "20150806125346",
"refund_id": "50200207182018070300011301001",
"out_refund_no": "7752501201407033233368018",
"refund_status": "SUCCESS",
"success_time": "2018-06-08T10:34:56+08:00",
"user_received_account": "招商银行信用卡0403",
"amount": {
"total": 999,
"refund": 999,
"payer_total": 999,
"payer_refund": 999
}
}
```

View File

@@ -0,0 +1,152 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 申请交易账单API
*/
public class GetTradeBill {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/bill/tradebill";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetTradeBill client = new GetTradeBill(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
GetTradeBillRequest request = new GetTradeBillRequest();
request.billDate = "2019-06-11";
request.subMchid = "19000000001";
request.billType = BillType.ALL;
request.tarType = TarType.GZIP;
try {
QueryBillEntity response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public QueryBillEntity run(GetTradeBillRequest request) {
String uri = PATH;
Map<String, Object> args = new HashMap<>();
args.put("bill_date", request.billDate);
args.put("sub_mchid", request.subMchid);
args.put("bill_type", request.billType);
args.put("tar_type", request.tarType);
uri = uri + "?" + WXPayUtility.urlEncode(args);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, QueryBillEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetTradeBill(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetTradeBillRequest {
@SerializedName("bill_date")
@Expose(serialize = false)
public String billDate;
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("bill_type")
@Expose(serialize = false)
public BillType billType;
@SerializedName("tar_type")
@Expose(serialize = false)
public TarType tarType;
}
public static class QueryBillEntity {
@SerializedName("hash_type")
public HashType hashType;
@SerializedName("hash_value")
public String hashValue;
@SerializedName("download_url")
public String downloadUrl;
}
public enum BillType {
@SerializedName("ALL")
ALL,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("REFUND")
REFUND
}
public enum TarType {
@SerializedName("GZIP")
GZIP
}
public enum HashType {
@SerializedName("SHA1")
SHA1
}
}

View File

@@ -0,0 +1,146 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 申请资金账单API
*/
public class GetFundFlowBill {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/bill/fundflowbill";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetFundFlowBill client = new GetFundFlowBill(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
GetFundFlowBillRequest request = new GetFundFlowBillRequest();
request.billDate = "2019-06-11";
request.accountType = FundFlowBillAccountType.BASIC;
request.tarType = TarType.GZIP;
try {
QueryBillEntity response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public QueryBillEntity run(GetFundFlowBillRequest request) {
String uri = PATH;
Map<String, Object> args = new HashMap<>();
args.put("bill_date", request.billDate);
args.put("account_type", request.accountType);
args.put("tar_type", request.tarType);
uri = uri + "?" + WXPayUtility.urlEncode(args);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, QueryBillEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetFundFlowBill(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetFundFlowBillRequest {
@SerializedName("bill_date")
@Expose(serialize = false)
public String billDate;
@SerializedName("account_type")
@Expose(serialize = false)
public FundFlowBillAccountType accountType;
@SerializedName("tar_type")
@Expose(serialize = false)
public TarType tarType;
}
public static class QueryBillEntity {
@SerializedName("hash_type")
public HashType hashType;
@SerializedName("hash_value")
public String hashValue;
@SerializedName("download_url")
public String downloadUrl;
}
public enum FundFlowBillAccountType {
@SerializedName("BASIC")
BASIC,
@SerializedName("OPERATION")
OPERATION,
@SerializedName("FEES")
FEES
}
public enum TarType {
@SerializedName("GZIP")
GZIP
}
public enum HashType {
@SerializedName("SHA1")
SHA1
}
}

View File

@@ -0,0 +1,164 @@
package com.java.demo;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.java.utils.WXPayUtility; // 引用微信支付工具库 参考:https://pay.weixin.qq.com/doc/v3/partner/4014985777
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.Response;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.codec.digest.DigestUtils;
import java.util.zip.GZIPInputStream;
/**
* 下载账单
*/
public class DownloadBill {
private static String METHOD = "GET";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
DownloadBill client = new DownloadBill(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
DownloadBillRequest request = new DownloadBillRequest();
request.downloadUrl = "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx";
request.localFilePath = "downloaded_bill.csv";
request.expectedHashType = HashType.SHA1;
request.expectedHashValue = "79bb0f45fc4c42234a918000b2668d689e2bde04";
request.tarType = TarType.GZIP;
try {
client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println("File downloaded successfully! Local file path: " + request.localFilePath);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public void run(DownloadBillRequest request) {
Request.Builder reqBuilder = new Request.Builder().url(request.downloadUrl);
String uri = getPathQueryFromUrl(request.downloadUrl);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization",
WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
if (httpResponse.code() < 200 || httpResponse.code() > 300) {
String respBody = WXPayUtility.extractBody(httpResponse);
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
// 2XX 成功,流式下载文件
ResponseBody body = httpResponse.body();
if (body == null) {
throw new IOException("Response body is null");
}
// 读取流
try (InputStream inputStream = (request.tarType == DownloadBill.TarType.GZIP)
? new GZIPInputStream(body.byteStream())
: body.byteStream();
FileOutputStream outputStream = new FileOutputStream(request.localFilePath)) {
byte[] buffer = new byte[8096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
}
// 下载成功后校验文件SHA1
if (request.expectedHashType == HashType.SHA1) {
String sha1 = DigestUtils.sha1Hex(new FileInputStream(request.localFilePath));
if (!sha1.equals(request.expectedHashValue)) {
throw new IOException("SHA1 checksum mismatch");
}
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private String getPathQueryFromUrl(String url) {
try {
URI uri = new URI(url);
String path = uri.getRawPath(); // /v3/billdownload/file
String query = uri.getRawQuery(); // token=xxx&tartype=gzip
return (query == null || query.isEmpty()) ? path : path + "?" + query;
} catch (URISyntaxException e) {
e.printStackTrace();
return "";
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public DownloadBill(String mchid, String certificateSerialNo, String privateKeyFilePath,
String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public enum HashType {
@SerializedName("SHA1")
SHA1
}
public static class DownloadBillRequest {
@SerializedName("download_url")
@Expose(serialize = false)
public String downloadUrl;
@SerializedName("local_file_path")
@Expose(serialize = false)
public String localFilePath;
@SerializedName("expected_hash_type")
@Expose(serialize = false)
public HashType expectedHashType;
@SerializedName("expected_hash_value")
@Expose(serialize = false)
public String expectedHashValue;
@SerializedName("tar_type")
@Expose(serialize = false)
public TarType tarType;
}
public enum TarType {
@SerializedName("GZIP")
GZIP
}
}

View File

@@ -0,0 +1,119 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 商家小票管理
*/
public class ChangeCustomPageStatus {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/goldplan/merchants/changecustompagestatus";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
ChangeCustomPageStatus client = new ChangeCustomPageStatus(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
ChangeCustomPageStatusRequest request = new ChangeCustomPageStatusRequest();
request.subMchid = "1900000109";
request.operationType = OperationType.OPEN;
try {
ChangeCustomPageStatusResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public ChangeCustomPageStatusResponse run(ChangeCustomPageStatusRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, ChangeCustomPageStatusResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public ChangeCustomPageStatus(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class ChangeCustomPageStatusRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("operation_type")
public OperationType operationType;
}
public static class ChangeCustomPageStatusResponse {
@SerializedName("sub_mchid")
public String subMchid;
}
public enum OperationType {
@SerializedName("OPEN")
OPEN,
@SerializedName("CLOSE")
CLOSE
}
}

View File

@@ -0,0 +1,132 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 点金计划管理
*/
public class ChangeGoldPlanStatus {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/goldplan/merchants/changegoldplanstatus";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
ChangeGoldPlanStatus client = new ChangeGoldPlanStatus(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
ChangeGoldPlanStatusRequest request = new ChangeGoldPlanStatusRequest();
request.subMchid = "1900000109";
request.operationType = OperationType.OPEN;
request.operationPayScene = OperationPayScene.JSAPI_AND_MINIPROGRAM;
try {
ChangeGoldPlanStatusResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public ChangeGoldPlanStatusResponse run(ChangeGoldPlanStatusRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, ChangeGoldPlanStatusResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public ChangeGoldPlanStatus(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class ChangeGoldPlanStatusRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("operation_type")
public OperationType operationType;
@SerializedName("operation_pay_scene")
public OperationPayScene operationPayScene;
}
public static class ChangeGoldPlanStatusResponse {
@SerializedName("sub_mchid")
public String subMchid;
}
public enum OperationType {
@SerializedName("OPEN")
OPEN,
@SerializedName("CLOSE")
CLOSE
}
public enum OperationPayScene {
@SerializedName("JSAPI_AND_MINIPROGRAM")
JSAPI_AND_MINIPROGRAM,
@SerializedName("JSAPI")
JSAPI,
@SerializedName("MINIPROGRAM")
MINIPROGRAM
}
}

View File

@@ -0,0 +1,95 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 关闭广告展示
*/
public class CloseAdvertisingShow {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/goldplan/merchants/close-advertising-show";
public static void main(String[] args) {
CloseAdvertisingShow client = new CloseAdvertisingShow(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
CloseAdvertisingShowRequest request = new CloseAdvertisingShowRequest();
request.subMchid = "1900000109";
try {
client.run(request);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public void run(CloseAdvertisingShowRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return;
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public CloseAdvertisingShow(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class CloseAdvertisingShowRequest {
@SerializedName("sub_mchid")
public String subMchid;
}
}

View File

@@ -0,0 +1,141 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 开通广告展示
*/
public class OpenAdvertisingShow {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "PATCH";
private static String PATH = "/v3/goldplan/merchants/open-advertising-show";
public static void main(String[] args) {
OpenAdvertisingShow client = new OpenAdvertisingShow(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
OpenAdvertisingShowRequest request = new OpenAdvertisingShowRequest();
request.subMchid = "1900000109";
request.advertisingIndustryFilters = new ArrayList<>();
{
request.advertisingIndustryFilters.add(IndustryType.E_COMMERCE);
};
try {
client.run(request);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public void run(OpenAdvertisingShowRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return;
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public OpenAdvertisingShow(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class OpenAdvertisingShowRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("advertising_industry_filters")
public List<IndustryType> advertisingIndustryFilters;
}
public enum IndustryType {
@SerializedName("E_COMMERCE") E_COMMERCE,
@SerializedName("LOVE_MARRIAGE") LOVE_MARRIAGE,
@SerializedName("POTOGRAPHY") POTOGRAPHY,
@SerializedName("EDUCATION") EDUCATION,
@SerializedName("FINANCE") FINANCE,
@SerializedName("TOURISM") TOURISM,
@SerializedName("SKINCARE") SKINCARE,
@SerializedName("FOOD") FOOD,
@SerializedName("SPORT") SPORT,
@SerializedName("JEWELRY_WATCH") JEWELRY_WATCH,
@SerializedName("HEALTHCARE") HEALTHCARE,
@SerializedName("BUSSINESS") BUSSINESS,
@SerializedName("PARENTING") PARENTING,
@SerializedName("CATERING") CATERING,
@SerializedName("RETAIL") RETAIL,
@SerializedName("SERVICES") SERVICES,
@SerializedName("LAW") LAW,
@SerializedName("ESTATE") ESTATE,
@SerializedName("TRANSPORTATION") TRANSPORTATION,
@SerializedName("ENERGY_SAVING") ENERGY_SAVING,
@SerializedName("SECURITY") SECURITY,
@SerializedName("BUILDING_MATERIAL") BUILDING_MATERIAL,
@SerializedName("COMMUNICATION") COMMUNICATION,
@SerializedName("MERCHANDISE") MERCHANDISE,
@SerializedName("ASSOCIATION") ASSOCIATION,
@SerializedName("COMMUNITY") COMMUNITY,
@SerializedName("ONLINE_AVR") ONLINE_AVR,
@SerializedName("WE_MEDIA") WE_MEDIA,
@SerializedName("CAR") CAR,
@SerializedName("SOFTWARE") SOFTWARE,
@SerializedName("GAME") GAME,
@SerializedName("CLOTHING") CLOTHING,
@SerializedName("INDUSTY") INDUSTY,
@SerializedName("AGRICULTURE") AGRICULTURE,
@SerializedName("PUBLISHING_MEDIA") PUBLISHING_MEDIA,
@SerializedName("HOME_DIGITAL") HOME_DIGITAL
}
}

View File

@@ -0,0 +1,142 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 同业过滤标签管理
*/
public class SetAdvertisingIndustryFilter {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/goldplan/merchants/set-advertising-industry-filter";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
SetAdvertisingIndustryFilter client = new SetAdvertisingIndustryFilter(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
SetAdvertisingIndustryFilterRequest request = new SetAdvertisingIndustryFilterRequest();
request.subMchid = "1900000109";
request.advertisingIndustryFilters = new ArrayList<>();
{
request.advertisingIndustryFilters.add(IndustryType.E_COMMERCE);
};
try {
client.run(request);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public void run(SetAdvertisingIndustryFilterRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return;
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public SetAdvertisingIndustryFilter(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class SetAdvertisingIndustryFilterRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("advertising_industry_filters")
public List<IndustryType> advertisingIndustryFilters = new ArrayList<IndustryType>();
}
public enum IndustryType {
@SerializedName("E_COMMERCE") E_COMMERCE,
@SerializedName("LOVE_MARRIAGE") LOVE_MARRIAGE,
@SerializedName("POTOGRAPHY") POTOGRAPHY,
@SerializedName("EDUCATION") EDUCATION,
@SerializedName("FINANCE") FINANCE,
@SerializedName("TOURISM") TOURISM,
@SerializedName("SKINCARE") SKINCARE,
@SerializedName("FOOD") FOOD,
@SerializedName("SPORT") SPORT,
@SerializedName("JEWELRY_WATCH") JEWELRY_WATCH,
@SerializedName("HEALTHCARE") HEALTHCARE,
@SerializedName("BUSSINESS") BUSSINESS,
@SerializedName("PARENTING") PARENTING,
@SerializedName("CATERING") CATERING,
@SerializedName("RETAIL") RETAIL,
@SerializedName("SERVICES") SERVICES,
@SerializedName("LAW") LAW,
@SerializedName("ESTATE") ESTATE,
@SerializedName("TRANSPORTATION") TRANSPORTATION,
@SerializedName("ENERGY_SAVING") ENERGY_SAVING,
@SerializedName("SECURITY") SECURITY,
@SerializedName("BUILDING_MATERIAL") BUILDING_MATERIAL,
@SerializedName("COMMUNICATION") COMMUNICATION,
@SerializedName("MERCHANDISE") MERCHANDISE,
@SerializedName("ASSOCIATION") ASSOCIATION,
@SerializedName("COMMUNITY") COMMUNITY,
@SerializedName("ONLINE_AVR") ONLINE_AVR,
@SerializedName("WE_MEDIA") WE_MEDIA,
@SerializedName("CAR") CAR,
@SerializedName("SOFTWARE") SOFTWARE,
@SerializedName("GAME") GAME,
@SerializedName("CLOTHING") CLOTHING,
@SerializedName("INDUSTY") INDUSTY,
@SerializedName("AGRICULTURE") AGRICULTURE,
@SerializedName("PUBLISHING_MEDIA") PUBLISHING_MEDIA,
@SerializedName("HOME_DIGITAL") HOME_DIGITAL
}
}

View File

@@ -0,0 +1,174 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 添加分账接收方(服务商模式)
*/
public class AddReceiver {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/profitsharing/receivers/add";
public static void main(String[] args) {
AddReceiver client = new AddReceiver(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
AddReceiverRequest request = new AddReceiverRequest();
request.subMchid = "1900000109";
request.appid = "wx8888888888888888";
request.subAppid = "wx8888888888888889";
request.type = ReceiverType.MERCHANT_ID;
request.account = "86693852";
request.name = client.encrypt("name");
request.relationType = ReceiverRelationType.STORE;
request.customRelation = "代理商";
try {
AddReceiverResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public AddReceiverResponse run(AddReceiverRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, AddReceiverResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public AddReceiver(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class AddReceiverRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("appid")
public String appid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
@SerializedName("name")
public String name;
@SerializedName("relation_type")
public ReceiverRelationType relationType;
@SerializedName("custom_relation")
public String customRelation;
}
public static class AddReceiverResponse {
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
@SerializedName("name")
public String name;
@SerializedName("relation_type")
public ReceiverRelationType relationType;
@SerializedName("custom_relation")
public String customRelation;
}
public enum ReceiverType {
@SerializedName("MERCHANT_ID")
MERCHANT_ID,
@SerializedName("PERSONAL_OPENID")
PERSONAL_OPENID,
@SerializedName("PERSONAL_SUB_OPENID")
PERSONAL_SUB_OPENID
}
public enum ReceiverRelationType {
@SerializedName("STORE")
STORE,
@SerializedName("STAFF")
STAFF,
@SerializedName("STORE_OWNER")
STORE_OWNER,
@SerializedName("PARTNER")
PARTNER,
@SerializedName("HEADQUARTER")
HEADQUARTER,
@SerializedName("BRAND")
BRAND,
@SerializedName("DISTRIBUTOR")
DISTRIBUTOR,
@SerializedName("USER")
USER,
@SerializedName("SUPPLIER")
SUPPLIER,
@SerializedName("CUSTOM")
CUSTOM,
@SerializedName("SERVICE_PROVIDER")
SERVICE_PROVIDER
}
}

View File

@@ -0,0 +1,177 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 请求分账(服务商模式)
*/
public class CreateOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/profitsharing/orders";
public static void main(String[] args) {
CreateOrder client = new CreateOrder(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
CreateOrderRequest request = new CreateOrderRequest();
request.subMchid = "1900000109";
request.appid = "wx8888888888888888";
request.subAppid = "wx8888888888888889";
request.transactionId = "4208450740201411110007820472";
request.outOrderNo = "P20150806125346";
request.receivers = new ArrayList<>();
{
CreateOrderReceiver receiversItem = new CreateOrderReceiver();
receiversItem.type = "MERCHANT_ID";
receiversItem.account = "86693852";
receiversItem.name = client.encrypt("name");
receiversItem.amount = 888L;
receiversItem.description = "分给商户A";
request.receivers.add(receiversItem);
};
request.unfreezeUnsplit = true;
try {
OrdersEntity response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public OrdersEntity run(CreateOrderRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, OrdersEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public CreateOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class CreateOrderRequest {
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("appid") public String appid;
@SerializedName("sub_appid") public String subAppid;
@SerializedName("transaction_id") public String transactionId;
@SerializedName("out_order_no") public String outOrderNo;
@SerializedName("receivers") public List<CreateOrderReceiver> receivers = new ArrayList<CreateOrderReceiver>();
@SerializedName("unfreeze_unsplit") public Boolean unfreezeUnsplit;
}
public static class OrdersEntity {
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("transaction_id") public String transactionId;
@SerializedName("out_order_no") public String outOrderNo;
@SerializedName("order_id") public String orderId;
@SerializedName("state") public OrderStatus state;
@SerializedName("receivers") public List<OrderReceiverDetail> receivers = new ArrayList<OrderReceiverDetail>();
}
public static class CreateOrderReceiver {
@SerializedName("type") public String type;
@SerializedName("account") public String account;
@SerializedName("name") public String name;
@SerializedName("amount") public Long amount;
@SerializedName("description") public String description;
}
public enum OrderStatus {
@SerializedName("PROCESSING") PROCESSING,
@SerializedName("FINISHED") FINISHED
}
public static class OrderReceiverDetail {
@SerializedName("amount") public Long amount;
@SerializedName("description") public String description;
@SerializedName("type") public ReceiverType type;
@SerializedName("account") public String account;
@SerializedName("result") public DetailStatus result;
@SerializedName("fail_reason") public DetailFailReason failReason;
@SerializedName("create_time") public String createTime;
@SerializedName("finish_time") public String finishTime;
@SerializedName("detail_id") public String detailId;
}
public enum ReceiverType {
@SerializedName("MERCHANT_ID") MERCHANT_ID,
@SerializedName("PERSONAL_OPENID") PERSONAL_OPENID,
@SerializedName("PERSONAL_SUB_OPENID") PERSONAL_SUB_OPENID
}
public enum DetailStatus {
@SerializedName("PENDING") PENDING,
@SerializedName("SUCCESS") SUCCESS,
@SerializedName("CLOSED") CLOSED
}
public enum DetailFailReason {
@SerializedName("ACCOUNT_ABNORMAL") ACCOUNT_ABNORMAL,
@SerializedName("NO_RELATION") NO_RELATION,
@SerializedName("RECEIVER_HIGH_RISK") RECEIVER_HIGH_RISK,
@SerializedName("RECEIVER_REAL_NAME_NOT_VERIFIED") RECEIVER_REAL_NAME_NOT_VERIFIED,
@SerializedName("NO_AUTH") NO_AUTH,
@SerializedName("RECEIVER_RECEIPT_LIMIT") RECEIVER_RECEIPT_LIMIT,
@SerializedName("PAYER_ACCOUNT_ABNORMAL") PAYER_ACCOUNT_ABNORMAL,
@SerializedName("INVALID_REQUEST") INVALID_REQUEST
}
}

View File

@@ -0,0 +1,175 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 请求分账回退(服务商模式)
*/
public class CreateReturnOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/profitsharing/return-orders";
public static void main(String[] args) {
CreateReturnOrder client = new CreateReturnOrder(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
CreateReturnOrderRequest request = new CreateReturnOrderRequest();
request.subMchid = "1900000109";
request.orderId = "3008450740201411110007820472";
request.outOrderNo = "P20150806125346";
request.outReturnNo = "R20190516001";
request.returnMchid = "86693852";
request.amount = 10L;
request.description = "用户退款";
try {
ReturnOrdersEntity response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public ReturnOrdersEntity run(CreateReturnOrderRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, ReturnOrdersEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public CreateReturnOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class CreateReturnOrderRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("order_id")
public String orderId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("out_return_no")
public String outReturnNo;
@SerializedName("return_mchid")
public String returnMchid;
@SerializedName("amount")
public Long amount;
@SerializedName("description")
public String description;
}
public static class ReturnOrdersEntity {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("order_id")
public String orderId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("out_return_no")
public String outReturnNo;
@SerializedName("return_id")
public String returnId;
@SerializedName("return_mchid")
public String returnMchid;
@SerializedName("amount")
public Long amount;
@SerializedName("description")
public String description;
@SerializedName("result")
public ReturnOrderStatus result;
@SerializedName("fail_reason")
public ReturnOrderFailReason failReason;
@SerializedName("create_time")
public String createTime;
@SerializedName("finish_time")
public String finishTime;
}
public enum ReturnOrderStatus {
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("FAILED")
FAILED
}
public enum ReturnOrderFailReason {
@SerializedName("ACCOUNT_ABNORMAL")
ACCOUNT_ABNORMAL,
@SerializedName("BALANCE_NOT_ENOUGH")
BALANCE_NOT_ENOUGH,
@SerializedName("TIME_OUT_CLOSED")
TIME_OUT_CLOSED,
@SerializedName("PAYER_ACCOUNT_ABNORMAL")
PAYER_ACCOUNT_ABNORMAL,
@SerializedName("INVALID_REQUEST")
INVALID_REQUEST
}
}

View File

@@ -0,0 +1,124 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 删除分账接收方(服务商模式)
*/
public class DeleteReceiver {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/profitsharing/receivers/delete";
public static void main(String[] args) {
DeleteReceiver client = new DeleteReceiver(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
DeleteReceiverRequest request = new DeleteReceiverRequest();
request.subMchid = "1900000109";
request.appid = "wx8888888888888888";
request.subAppid = "wx8888888888888889";
request.type = ReceiverType.MERCHANT_ID;
request.account = "1900000109";
try {
DeleteReceiverResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public DeleteReceiverResponse run(DeleteReceiverRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, DeleteReceiverResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public DeleteReceiver(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class DeleteReceiverRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("appid")
public String appid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
}
public static class DeleteReceiverResponse {
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
}
public enum ReceiverType {
@SerializedName("MERCHANT_ID")
MERCHANT_ID,
@SerializedName("PERSONAL_OPENID")
PERSONAL_OPENID,
@SerializedName("PERSONAL_SUB_OPENID")
PERSONAL_SUB_OPENID
}
}

View File

@@ -0,0 +1,97 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 查询最大分账比例(服务商独有)
*/
public class QueryMerchantRatio {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/profitsharing/merchant-configs/{sub_mchid}";
public static void main(String[] args) {
QueryMerchantRatio client = new QueryMerchantRatio(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
QueryMerchantRatioRequest request = new QueryMerchantRatioRequest();
request.subMchid = "1900000109";
try {
QueryMerchantRatioResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public QueryMerchantRatioResponse run(QueryMerchantRatioRequest request) {
String uri = PATH;
uri = uri.replace("{sub_mchid}", WXPayUtility.urlEncode(request.subMchid));
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, QueryMerchantRatioResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryMerchantRatio(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryMerchantRatioRequest {
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
}
public static class QueryMerchantRatioResponse {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("max_ratio")
public Long maxRatio;
}
}

View File

@@ -0,0 +1,203 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询分账结果(服务商模式)
*/
public class QueryOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/profitsharing/orders/{out_order_no}";
public static void main(String[] args) {
QueryOrder client = new QueryOrder(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
QueryOrderRequest request = new QueryOrderRequest();
request.outOrderNo = "P20150806125346";
request.subMchid = "1900000109";
request.transactionId = "4208450740201411110007820472";
try {
OrdersEntity response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public OrdersEntity run(QueryOrderRequest request) {
String uri = PATH;
uri = uri.replace("{out_order_no}", WXPayUtility.urlEncode(request.outOrderNo));
Map<String, Object> args = new HashMap<>();
args.put("sub_mchid", request.subMchid);
args.put("transaction_id", request.transactionId);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, OrdersEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryOrderRequest {
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("transaction_id")
@Expose(serialize = false)
public String transactionId;
@SerializedName("out_order_no")
@Expose(serialize = false)
public String outOrderNo;
}
public static class OrdersEntity {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("order_id")
public String orderId;
@SerializedName("state")
public OrderStatus state;
@SerializedName("receivers")
public List<OrderReceiverDetail> receivers = new ArrayList<OrderReceiverDetail>();
}
public enum OrderStatus {
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("FINISHED")
FINISHED
}
public static class OrderReceiverDetail {
@SerializedName("amount")
public Long amount;
@SerializedName("description")
public String description;
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
@SerializedName("result")
public DetailStatus result;
@SerializedName("fail_reason")
public DetailFailReason failReason;
@SerializedName("create_time")
public String createTime;
@SerializedName("finish_time")
public String finishTime;
@SerializedName("detail_id")
public String detailId;
}
public enum ReceiverType {
@SerializedName("MERCHANT_ID")
MERCHANT_ID,
@SerializedName("PERSONAL_OPENID")
PERSONAL_OPENID,
@SerializedName("PERSONAL_SUB_OPENID")
PERSONAL_SUB_OPENID
}
public enum DetailStatus {
@SerializedName("PENDING")
PENDING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("CLOSED")
CLOSED
}
public enum DetailFailReason {
@SerializedName("ACCOUNT_ABNORMAL")
ACCOUNT_ABNORMAL,
@SerializedName("NO_RELATION")
NO_RELATION,
@SerializedName("RECEIVER_HIGH_RISK")
RECEIVER_HIGH_RISK,
@SerializedName("RECEIVER_REAL_NAME_NOT_VERIFIED")
RECEIVER_REAL_NAME_NOT_VERIFIED,
@SerializedName("NO_AUTH")
NO_AUTH,
@SerializedName("RECEIVER_RECEIPT_LIMIT")
RECEIVER_RECEIPT_LIMIT,
@SerializedName("PAYER_ACCOUNT_ABNORMAL")
PAYER_ACCOUNT_ABNORMAL,
@SerializedName("INVALID_REQUEST")
INVALID_REQUEST
}
}

View File

@@ -0,0 +1,97 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 查询剩余待分金额(服务商模式,与商户模式路径与参数一致)
*/
public class QueryOrderAmount {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/profitsharing/transactions/{transaction_id}/amounts";
public static void main(String[] args) {
QueryOrderAmount client = new QueryOrderAmount(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
QueryOrderAmountRequest request = new QueryOrderAmountRequest();
request.transactionId = "4208450740201411110007820472";
try {
QueryOrderAmountResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public QueryOrderAmountResponse run(QueryOrderAmountRequest request) {
String uri = PATH;
uri = uri.replace("{transaction_id}", WXPayUtility.urlEncode(request.transactionId));
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, QueryOrderAmountResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryOrderAmount(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryOrderAmountRequest {
@SerializedName("transaction_id")
@Expose(serialize = false)
public String transactionId;
}
public static class QueryOrderAmountResponse {
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("unsplit_amount")
public Long unsplitAmount;
}
}

View File

@@ -0,0 +1,168 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
/**
* 查询分账回退结果(服务商模式)
*/
public class QueryReturnOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/profitsharing/return-orders/{out_return_no}";
public static void main(String[] args) {
QueryReturnOrder client = new QueryReturnOrder(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
QueryReturnOrderRequest request = new QueryReturnOrderRequest();
request.outReturnNo = "R20190516001";
request.subMchid = "1900000109";
request.outOrderNo = "P20190806125346";
try {
ReturnOrdersEntity response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public ReturnOrdersEntity run(QueryReturnOrderRequest request) {
String uri = PATH;
uri = uri.replace("{out_return_no}", WXPayUtility.urlEncode(request.outReturnNo));
Map<String, Object> args = new HashMap<>();
args.put("sub_mchid", request.subMchid);
args.put("out_order_no", request.outOrderNo);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, ReturnOrdersEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryReturnOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryReturnOrderRequest {
@SerializedName("out_return_no")
@Expose(serialize = false)
public String outReturnNo;
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("out_order_no")
@Expose(serialize = false)
public String outOrderNo;
}
public static class ReturnOrdersEntity {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("order_id")
public String orderId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("out_return_no")
public String outReturnNo;
@SerializedName("return_id")
public String returnId;
@SerializedName("return_mchid")
public String returnMchid;
@SerializedName("amount")
public Long amount;
@SerializedName("description")
public String description;
@SerializedName("result")
public ReturnOrderStatus result;
@SerializedName("fail_reason")
public ReturnOrderFailReason failReason;
@SerializedName("create_time")
public String createTime;
@SerializedName("finish_time")
public String finishTime;
}
public enum ReturnOrderStatus {
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("FAILED")
FAILED
}
public enum ReturnOrderFailReason {
@SerializedName("ACCOUNT_ABNORMAL")
ACCOUNT_ABNORMAL,
@SerializedName("BALANCE_NOT_ENOUGH")
BALANCE_NOT_ENOUGH,
@SerializedName("TIME_OUT_CLOSED")
TIME_OUT_CLOSED,
@SerializedName("PAYER_ACCOUNT_ABNORMAL")
PAYER_ACCOUNT_ABNORMAL,
@SerializedName("INVALID_REQUEST")
INVALID_REQUEST
}
}

View File

@@ -0,0 +1,129 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
/**
* 申请分账账单(服务商模式)
*/
public class SplitBill {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/profitsharing/bills";
public static void main(String[] args) {
SplitBill client = new SplitBill(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
SplitBillRequest request = new SplitBillRequest();
request.subMchid = "1900000109";
request.billDate = "2019-06-11";
request.tarType = SplitBillTarType.GZIP;
try {
SplitBillResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public SplitBillResponse run(SplitBillRequest request) {
String uri = PATH;
Map<String, Object> args = new HashMap<>();
args.put("sub_mchid", request.subMchid);
args.put("bill_date", request.billDate);
args.put("tar_type", request.tarType);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, SplitBillResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public SplitBill(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class SplitBillRequest {
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("bill_date")
@Expose(serialize = false)
public String billDate;
@SerializedName("tar_type")
@Expose(serialize = false)
public SplitBillTarType tarType;
}
public static class SplitBillResponse {
@SerializedName("hash_type")
public SplitBillHashType hashType;
@SerializedName("hash_value")
public String hashValue;
@SerializedName("download_url")
public String downloadUrl;
}
public enum SplitBillTarType {
@SerializedName("GZIP")
GZIP
}
public enum SplitBillHashType {
@SerializedName("SHA1")
SHA1
}
}

View File

@@ -0,0 +1,198 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
/**
* 解冻剩余资金(服务商模式)
*/
public class UnfreezeOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/profitsharing/orders/unfreeze";
public static void main(String[] args) {
UnfreezeOrder client = new UnfreezeOrder(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
UnfreezeOrderRequest request = new UnfreezeOrderRequest();
request.subMchid = "1900000109";
request.transactionId = "4208450740201411110007820472";
request.outOrderNo = "P20150806125346";
request.description = "解冻全部剩余资金";
try {
OrdersEntity response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public OrdersEntity run(UnfreezeOrderRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, OrdersEntity.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public UnfreezeOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class UnfreezeOrderRequest {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("description")
public String description;
}
public static class OrdersEntity {
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_order_no")
public String outOrderNo;
@SerializedName("order_id")
public String orderId;
@SerializedName("state")
public OrderStatus state;
@SerializedName("receivers")
public List<OrderReceiverDetail> receivers = new ArrayList<OrderReceiverDetail>();
}
public enum OrderStatus {
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("FINISHED")
FINISHED
}
public static class OrderReceiverDetail {
@SerializedName("amount")
public Long amount;
@SerializedName("description")
public String description;
@SerializedName("type")
public ReceiverType type;
@SerializedName("account")
public String account;
@SerializedName("result")
public DetailStatus result;
@SerializedName("fail_reason")
public DetailFailReason failReason;
@SerializedName("create_time")
public String createTime;
@SerializedName("finish_time")
public String finishTime;
@SerializedName("detail_id")
public String detailId;
}
public enum ReceiverType {
@SerializedName("MERCHANT_ID")
MERCHANT_ID,
@SerializedName("PERSONAL_OPENID")
PERSONAL_OPENID,
@SerializedName("PERSONAL_SUB_OPENID")
PERSONAL_SUB_OPENID
}
public enum DetailStatus {
@SerializedName("PENDING")
PENDING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("CLOSED")
CLOSED
}
public enum DetailFailReason {
@SerializedName("ACCOUNT_ABNORMAL")
ACCOUNT_ABNORMAL,
@SerializedName("NO_RELATION")
NO_RELATION,
@SerializedName("RECEIVER_HIGH_RISK")
RECEIVER_HIGH_RISK,
@SerializedName("RECEIVER_REAL_NAME_NOT_VERIFIED")
RECEIVER_REAL_NAME_NOT_VERIFIED,
@SerializedName("NO_AUTH")
NO_AUTH,
@SerializedName("RECEIVER_RECEIPT_LIMIT")
RECEIVER_RECEIPT_LIMIT,
@SerializedName("PAYER_ACCOUNT_ABNORMAL")
PAYER_ACCOUNT_ABNORMAL,
@SerializedName("INVALID_REQUEST")
INVALID_REQUEST
}
}

View File

@@ -0,0 +1,136 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询结算账户修改申请状态
*
* 调用频率限制100/秒。
*/
public class GetApplication {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/apply4sub/sub_merchants/{sub_mchid}/application/{application_no}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetApplication client = new GetApplication(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
GetApplicationRequest request = new GetApplicationRequest();
request.subMchid = "1511101111";
request.applicationNo = "102329389XXXX";
request.accountNumberRule = AccountNumberRule.ACCOUNT_NUMBER_RULE_MASK_V1;
try {
SubMerchantsGetApplicationResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public SubMerchantsGetApplicationResponse run(GetApplicationRequest request) {
String uri = PATH;
uri = uri.replace("{sub_mchid}", WXPayUtility.urlEncode(request.subMchid));
uri = uri.replace("{application_no}", WXPayUtility.urlEncode(request.applicationNo));
Map<String, Object> args = new HashMap<>();
args.put("account_number_rule", request.accountNumberRule);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, SubMerchantsGetApplicationResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetApplication(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetApplicationRequest {
@SerializedName("sub_mchid") @Expose(serialize = false) public String subMchid;
@SerializedName("application_no") @Expose(serialize = false) public String applicationNo;
@SerializedName("account_number_rule") @Expose(serialize = false) public AccountNumberRule accountNumberRule;
}
public static class SubMerchantsGetApplicationResponse {
@SerializedName("account_name") public String accountName;
@SerializedName("account_type") public BankAccountType accountType;
@SerializedName("account_bank") public String accountBank;
@SerializedName("bank_name") public String bankName;
@SerializedName("bank_branch_id") public String bankBranchId;
@SerializedName("account_number") public String accountNumber;
@SerializedName("verify_result") public AuditResult verifyResult;
@SerializedName("verify_fail_reason") public String verifyFailReason;
@SerializedName("verify_finish_time") public String verifyFinishTime;
}
public enum AccountNumberRule {
@SerializedName("ACCOUNT_NUMBER_RULE_MASK_V1") ACCOUNT_NUMBER_RULE_MASK_V1,
@SerializedName("ACCOUNT_NUMBER_RULE_MASK_V2") ACCOUNT_NUMBER_RULE_MASK_V2
}
public enum BankAccountType {
@SerializedName("ACCOUNT_TYPE_BUSINESS") ACCOUNT_TYPE_BUSINESS,
@SerializedName("ACCOUNT_TYPE_PRIVATE") ACCOUNT_TYPE_PRIVATE
}
public enum AuditResult {
@SerializedName("AUDIT_SUCCESS") AUDIT_SUCCESS,
@SerializedName("AUDITING") AUDITING,
@SerializedName("AUDIT_FAIL") AUDIT_FAIL
}
}

View File

@@ -0,0 +1,131 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询结算账户
*
* 调用频率限制100/秒。
*/
public class GetSettlement {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/apply4sub/sub_merchants/{sub_mchid}/settlement";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetSettlement client = new GetSettlement(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
GetSettlementRequest request = new GetSettlementRequest();
request.subMchid = "1900006491";
request.accountNumberRule = AccountNumberRule.ACCOUNT_NUMBER_RULE_MASK_V1;
try {
Settlement response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public Settlement run(GetSettlementRequest request) {
String uri = PATH;
uri = uri.replace("{sub_mchid}", WXPayUtility.urlEncode(request.subMchid));
Map<String, Object> args = new HashMap<>();
args.put("account_number_rule", request.accountNumberRule);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, Settlement.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetSettlement(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetSettlementRequest {
@SerializedName("sub_mchid") @Expose(serialize = false) public String subMchid;
@SerializedName("account_number_rule") @Expose(serialize = false) public AccountNumberRule accountNumberRule;
}
public static class Settlement {
@SerializedName("account_type") public BankAccountType accountType;
@SerializedName("account_bank") public String accountBank;
@SerializedName("bank_name") public String bankName;
@SerializedName("bank_branch_id") public String bankBranchId;
@SerializedName("account_number") public String accountNumber;
@SerializedName("verify_result") public VerifyResult verifyResult;
@SerializedName("verify_fail_reason") public String verifyFailReason;
}
public enum AccountNumberRule {
@SerializedName("ACCOUNT_NUMBER_RULE_MASK_V1") ACCOUNT_NUMBER_RULE_MASK_V1,
@SerializedName("ACCOUNT_NUMBER_RULE_MASK_V2") ACCOUNT_NUMBER_RULE_MASK_V2
}
public enum BankAccountType {
@SerializedName("ACCOUNT_TYPE_BUSINESS") ACCOUNT_TYPE_BUSINESS,
@SerializedName("ACCOUNT_TYPE_PRIVATE") ACCOUNT_TYPE_PRIVATE
}
public enum VerifyResult {
@SerializedName("VERIFY_SUCCESS") VERIFY_SUCCESS,
@SerializedName("VERIFY_FAIL") VERIFY_FAIL,
@SerializedName("VERIFYING") VERIFYING
}
}

View File

@@ -0,0 +1,136 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 修改结算账户
*
* 服务商/电商平台(不包括支付机构、银行),可使用本接口,修改其进件且已签约特约商户/二级商户的结算银行账户。
*
* 注意:
* 1、提交结算银行账户修改申请后应答代码为"200"且系统返回申请单号,需通过"查询结算账户修改申请状态API"查询申请单处理结果。
* 申请单状态存在如下情况:
* ① 审核中:修改的银行结算账户还在审核中、账户尚未生效,需继续等待审核结果,在此期间无法再次提交修改申请;
* 审核过程中系统可能会向结算银行账户付款0.01元进行验证。
* ② 审核驳回:申请已驳回,请检查驳回原因、并重新发起修改。
* ③ 审核成功:银行结算账户更新成功。
* 2、如需查询当前生效中的银行结算账户请使用"查询结算账户API"。
* 3、特约商户/二级商户每天仅能提交5次修改申请如需继续申请请等到次日0点后重新发起。
* 4、修改结算银行卡接口调用频率限制20/min。
*/
public class ModifySettlement {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
ModifySettlement client = new ModifySettlement(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
ModifySettlementRequest request = new ModifySettlementRequest();
request.subMchid = "1900006491";
request.accountType = BankAccountType.ACCOUNT_TYPE_BUSINESS;
request.accountBank = "工商银行";
request.bankName = "中国工商银行股份有限公司北京市分行营业部";
request.bankBranchId = "402713354941";
request.accountNumber = client.encrypt("account_number");
request.accountName = client.encrypt("account_name");
try {
ModifySettlementResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public ModifySettlementResponse run(ModifySettlementRequest request) {
String uri = PATH;
uri = uri.replace("{sub_mchid}", WXPayUtility.urlEncode(request.subMchid));
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, ModifySettlementResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public ModifySettlement(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class ModifySettlementRequest {
@SerializedName("sub_mchid") @Expose(serialize = false) public String subMchid;
@SerializedName("account_type") public BankAccountType accountType;
@SerializedName("account_bank") public String accountBank;
@SerializedName("bank_name") public String bankName;
@SerializedName("bank_branch_id") public String bankBranchId;
@SerializedName("account_number") public String accountNumber;
@SerializedName("account_name") public String accountName;
}
public static class ModifySettlementResponse {
@SerializedName("application_no") public String applicationNo;
}
public enum BankAccountType {
@SerializedName("ACCOUNT_TYPE_BUSINESS") ACCOUNT_TYPE_BUSINESS,
@SerializedName("ACCOUNT_TYPE_PRIVATE") ACCOUNT_TYPE_PRIVATE
}
}

View File

@@ -0,0 +1,124 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询申请单状态
*/
public class QueryState {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/applyment4sub/applyment/business_code/{business_code}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
QueryState client = new QueryState(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
QueryStateRequest request = new QueryStateRequest();
request.businessCode = "1900013511_10000";
try {
QueryStateResp response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public QueryStateResp run(QueryStateRequest request) {
String uri = PATH;
uri = uri.replace("{business_code}", WXPayUtility.urlEncode(request.businessCode));
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, QueryStateResp.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryState(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryStateRequest {
@SerializedName("business_code")
@Expose(serialize = false)
public String businessCode;
}
public static class QueryStateResp {
@SerializedName("business_code") public String businessCode;
@SerializedName("applyment_id") public Long applymentId;
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("sign_url") public String signUrl;
@SerializedName("applyment_state") public ApplymentState applymentState;
@SerializedName("applyment_state_msg") public String applymentStateMsg;
@SerializedName("audit_detail") public List<AuditDetail> auditDetail;
}
public enum ApplymentState {
@SerializedName("APPLYMENT_STATE_EDITTING") APPLYMENT_STATE_EDITTING,
@SerializedName("APPLYMENT_STATE_AUDITING") APPLYMENT_STATE_AUDITING,
@SerializedName("APPLYMENT_STATE_REJECTED") APPLYMENT_STATE_REJECTED,
@SerializedName("APPLYMENT_STATE_TO_BE_CONFIRMED") APPLYMENT_STATE_TO_BE_CONFIRMED,
@SerializedName("APPLYMENT_STATE_TO_BE_SIGNED") APPLYMENT_STATE_TO_BE_SIGNED,
@SerializedName("APPLYMENT_STATE_FINISHED") APPLYMENT_STATE_FINISHED,
@SerializedName("APPLYMENT_STATE_CANCELED") APPLYMENT_STATE_CANCELED,
@SerializedName("APPLYMENT_STATE_SIGNING") APPLYMENT_STATE_SIGNING
}
public static class AuditDetail {
@SerializedName("field") public String field;
@SerializedName("field_name") public String fieldName;
@SerializedName("reject_reason") public String rejectReason;
}
}

View File

@@ -0,0 +1,124 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询申请单状态
*/
public class QueryStateById {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/applyment4sub/applyment/applyment_id/{applyment_id}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
QueryStateById client = new QueryStateById(
"19xxxxxxxx", // 商户号
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径
);
QueryStateByIdRequest request = new QueryStateByIdRequest();
request.applymentId = 2000001234567890L;
try {
QueryStateResp response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public QueryStateResp run(QueryStateByIdRequest request) {
String uri = PATH;
uri = uri.replace("{applyment_id}", WXPayUtility.urlEncode(request.applymentId.toString()));
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, QueryStateResp.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryStateById(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryStateByIdRequest {
@SerializedName("applyment_id")
@Expose(serialize = false)
public Long applymentId;
}
public static class QueryStateResp {
@SerializedName("business_code") public String businessCode;
@SerializedName("applyment_id") public Long applymentId;
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("sign_url") public String signUrl;
@SerializedName("applyment_state") public ApplymentState applymentState;
@SerializedName("applyment_state_msg") public String applymentStateMsg;
@SerializedName("audit_detail") public List<AuditDetail> auditDetail;
}
public enum ApplymentState {
@SerializedName("APPLYMENT_STATE_EDITTING") APPLYMENT_STATE_EDITTING,
@SerializedName("APPLYMENT_STATE_AUDITING") APPLYMENT_STATE_AUDITING,
@SerializedName("APPLYMENT_STATE_REJECTED") APPLYMENT_STATE_REJECTED,
@SerializedName("APPLYMENT_STATE_TO_BE_CONFIRMED") APPLYMENT_STATE_TO_BE_CONFIRMED,
@SerializedName("APPLYMENT_STATE_TO_BE_SIGNED") APPLYMENT_STATE_TO_BE_SIGNED,
@SerializedName("APPLYMENT_STATE_FINISHED") APPLYMENT_STATE_FINISHED,
@SerializedName("APPLYMENT_STATE_CANCELED") APPLYMENT_STATE_CANCELED,
@SerializedName("APPLYMENT_STATE_SIGNING") APPLYMENT_STATE_SIGNING
}
public static class AuditDetail {
@SerializedName("field") public String field;
@SerializedName("field_name") public String fieldName;
@SerializedName("reject_reason") public String rejectReason;
}
}

View File

@@ -0,0 +1,510 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 提交申请单
*/
public class Submit {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/applyment4sub/applyment/";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
Submit client = new Submit(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
SubmitReq request = new SubmitReq();
request.businessCode = "1900013511_10000";
request.contactInfo = new ContactInfo();
request.contactInfo.contactType = IdHolderType.LEGAL;
request.contactInfo.contactName = client.encrypt("contact_name");
request.contactInfo.contactIdDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
request.contactInfo.contactIdNumber = client.encrypt("contact_id_number");
request.contactInfo.contactIdDocCopy = "jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.contactInfo.contactIdDocCopyBack = "jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ";
request.contactInfo.contactPeriodBegin = "2019-06-06";
request.contactInfo.contactPeriodEnd = "2026-06-06";
request.contactInfo.businessAuthorizationLetter = "47ZC6GC-vnrbEny_Ie_An5-tCpqxucuxi-vByf3Gjm7KEIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.contactInfo.openid = "pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg== 字段加密: 使用APIv3定义的方式加密";
request.contactInfo.mobilePhone = client.encrypt("mobile_phone");
request.contactInfo.contactEmail = client.encrypt("contact_email");
request.subjectInfo = new SubjectInfo();
request.subjectInfo.subjectType = SubjectType.SUBJECT_TYPE_ENTERPRISE;
request.subjectInfo.financeInstitution = true;
request.subjectInfo.businessLicenseInfo = new BusinessLicense();
request.subjectInfo.businessLicenseInfo.licenseCopy = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.subjectInfo.businessLicenseInfo.licenseNumber = "123456789012345678";
request.subjectInfo.businessLicenseInfo.merchantName = "腾讯科技有限公司";
request.subjectInfo.businessLicenseInfo.legalPerson = "张三";
request.subjectInfo.businessLicenseInfo.licenseAddress = "广东省深圳市南山区xx路xx号";
request.subjectInfo.businessLicenseInfo.periodBegin = "2019-08-01";
request.subjectInfo.businessLicenseInfo.periodEnd = "2029-08-01";
request.subjectInfo.certificateInfo = new CertificateInfo();
request.subjectInfo.certificateInfo.certCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.certificateInfo.certType = CertificateType.CERTIFICATE_TYPE_2388;
request.subjectInfo.certificateInfo.certNumber = "111111111111";
request.subjectInfo.certificateInfo.merchantName = "xx公益团体";
request.subjectInfo.certificateInfo.companyAddress = "广东省深圳市南山区xx路xx号";
request.subjectInfo.certificateInfo.legalPerson = "李四";
request.subjectInfo.certificateInfo.periodBegin = "2019-08-01";
request.subjectInfo.certificateInfo.periodEnd = "2019-08-01";
request.subjectInfo.certificateLetterCopy = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.subjectInfo.financeInstitutionInfo = new FinanceInstitutionInfo();
request.subjectInfo.financeInstitutionInfo.financeType = FinanceType.BANK_AGENT;
request.subjectInfo.financeInstitutionInfo.financeLicensePics = new ArrayList<>();
{
request.subjectInfo.financeInstitutionInfo.financeLicensePics.add("0P3ng6KTIW4-Q_l2FjmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo");
};
request.subjectInfo.identityInfo = new IdentityInfo();
request.subjectInfo.identityInfo.idHolderType = IdHolderType.LEGAL;
request.subjectInfo.identityInfo.idDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
request.subjectInfo.identityInfo.authorizeLetterCopy = "47ZC6GC-vnrbEny_Ie_An5-tCpqxucuxi-vByf3Gjm7KEIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.subjectInfo.identityInfo.idCardInfo = new IdCardInfo();
request.subjectInfo.identityInfo.idCardInfo.idCardCopy = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.subjectInfo.identityInfo.idCardInfo.idCardNational = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.subjectInfo.identityInfo.idCardInfo.idCardName = client.encrypt("id_card_name");
request.subjectInfo.identityInfo.idCardInfo.idCardNumber = client.encrypt("id_card_number");
request.subjectInfo.identityInfo.idCardInfo.idCardAddress = client.encrypt("id_card_address");
request.subjectInfo.identityInfo.idCardInfo.cardPeriodBegin = "2026-06-06";
request.subjectInfo.identityInfo.idCardInfo.cardPeriodEnd = "2026-06-06";
request.subjectInfo.identityInfo.idDocInfo = new IdDocInfo();
request.subjectInfo.identityInfo.idDocInfo.idDocCopy = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.subjectInfo.identityInfo.idDocInfo.idDocCopyBack = "jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ";
request.subjectInfo.identityInfo.idDocInfo.idDocName = client.encrypt("id_doc_name");
request.subjectInfo.identityInfo.idDocInfo.idDocNumber = client.encrypt("id_doc_number");
request.subjectInfo.identityInfo.idDocInfo.idDocAddress = client.encrypt("id_doc_address");
request.subjectInfo.identityInfo.idDocInfo.docPeriodBegin = "2019-06-06";
request.subjectInfo.identityInfo.idDocInfo.docPeriodEnd = "2026-06-06";
request.subjectInfo.identityInfo.owner = true;
request.subjectInfo.uboInfoList = new ArrayList<>();
{
UBOInfoList uboInfoListItem = new UBOInfoList();
uboInfoListItem.uboIdDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
uboInfoListItem.uboIdDocCopy = "jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ";
uboInfoListItem.uboIdDocCopyBack = "jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ";
uboInfoListItem.uboIdDocName = client.encrypt("ubo_id_doc_name");
uboInfoListItem.uboIdDocNumber = client.encrypt("ubo_id_doc_number");
uboInfoListItem.uboIdDocAddress = client.encrypt("ubo_id_doc_address");
uboInfoListItem.uboPeriodBegin = "2019-06-06";
uboInfoListItem.uboPeriodEnd = "2026-06-06";
request.subjectInfo.uboInfoList.add(uboInfoListItem);
};
request.businessInfo = new BusinessInfo();
request.businessInfo.merchantShortname = "张三餐饮店";
request.businessInfo.servicePhone = "0758XXXXX";
request.businessInfo.salesInfo = new SalesInfo();
request.businessInfo.salesInfo.salesScenesType = new ArrayList<>();
{
request.businessInfo.salesInfo.salesScenesType.add(SalesScenesType.SALES_SCENES_STORE);
};
request.businessInfo.salesInfo.bizStoreInfo = new StoreInfo();
request.businessInfo.salesInfo.bizStoreInfo.bizStoreName = "大郎烧饼";
request.businessInfo.salesInfo.bizStoreInfo.bizAddressCode = "440305";
request.businessInfo.salesInfo.bizStoreInfo.bizStoreAddress = "南山区xx大厦x层xxxx室";
request.businessInfo.salesInfo.bizStoreInfo.storeEntrancePic = new ArrayList<>();
{
request.businessInfo.salesInfo.bizStoreInfo.storeEntrancePic.add("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo");
};
request.businessInfo.salesInfo.bizStoreInfo.indoorPic = new ArrayList<>();
{
request.businessInfo.salesInfo.bizStoreInfo.indoorPic.add("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo");
};
request.businessInfo.salesInfo.bizStoreInfo.bizSubAppid = "wx1234567890123456";
request.businessInfo.salesInfo.mpInfo = new MpInfo();
request.businessInfo.salesInfo.mpInfo.mpAppid = "wx1234567890123456";
request.businessInfo.salesInfo.mpInfo.mpSubAppid = "wx1234567890123456";
request.businessInfo.salesInfo.mpInfo.mpPics = new ArrayList<>();
{
request.businessInfo.salesInfo.mpInfo.mpPics.add("example_mpPics");
};
request.businessInfo.salesInfo.miniProgramInfo = new MiniProgramInfo();
request.businessInfo.salesInfo.miniProgramInfo.miniProgramAppid = "wx1234567890123456";
request.businessInfo.salesInfo.miniProgramInfo.miniProgramSubAppid = "wx1234567890123456";
request.businessInfo.salesInfo.miniProgramInfo.miniProgramPics = new ArrayList<>();
{
request.businessInfo.salesInfo.miniProgramInfo.miniProgramPics.add("example_miniProgramPics");
};
request.businessInfo.salesInfo.appInfo = new AppInfo();
request.businessInfo.salesInfo.appInfo.appAppid = "wx1234567890123456";
request.businessInfo.salesInfo.appInfo.appSubAppid = "wx1234567890123456";
request.businessInfo.salesInfo.appInfo.appPics = new ArrayList<>();
{
request.businessInfo.salesInfo.appInfo.appPics.add("example_appPics");
};
request.businessInfo.salesInfo.webInfo = new WebInfo();
request.businessInfo.salesInfo.webInfo.domain = "http://www.qq.com";
request.businessInfo.salesInfo.webInfo.webAuthorisation = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.businessInfo.salesInfo.webInfo.webAppid = "wx1234567890123456";
request.businessInfo.salesInfo.weworkInfo = new WeworkInfo();
request.businessInfo.salesInfo.weworkInfo.subCorpId = "wx1234567890123456";
request.businessInfo.salesInfo.weworkInfo.weworkPics = new ArrayList<>();
{
request.businessInfo.salesInfo.weworkInfo.weworkPics.add("example_weworkPics");
};
request.settlementInfo = new SettlementInfo();
request.settlementInfo.settlementId = "719";
request.settlementInfo.qualificationType = "餐饮";
request.settlementInfo.qualifications = new ArrayList<>();
{
request.settlementInfo.qualifications.add("example_qualifications");
};
request.settlementInfo.activitiesId = "716";
request.settlementInfo.activitiesRate = "0.6";
request.settlementInfo.activitiesAdditions = new ArrayList<>();
{
request.settlementInfo.activitiesAdditions.add("example_activitiesAdditions");
};
request.settlementInfo.debitActivitiesRate = "0.54";
request.settlementInfo.creditActivitiesRate = "0.54";
request.bankAccountInfo = new BankAccountInfo();
request.bankAccountInfo.bankAccountType = BankAccountType.BANK_ACCOUNT_TYPE_CORPORATE;
request.bankAccountInfo.accountName = client.encrypt("account_name");
request.bankAccountInfo.accountBank = "工商银行";
request.bankAccountInfo.bankAddressCode = "110000";
request.bankAccountInfo.bankBranchId = "402713354941";
request.bankAccountInfo.bankName = "施秉县农村信用合作联社城关信用社";
request.bankAccountInfo.accountNumber = client.encrypt("account_number");
request.additionInfo = new AdditionInfo();
request.additionInfo.legalPersonCommitment = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.additionInfo.legalPersonVideo = "47ZC6GC-vnrbEny__Ie_An5-tCpqxucuxi-vByf3Gjm7KE53JXvGy9tqZm2XAUf-4KGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4";
request.additionInfo.businessAdditionPics = new ArrayList<>();
{
request.additionInfo.businessAdditionPics.add("example_businessAdditionPics");
};
request.additionInfo.businessAdditionMsg = "特殊情况,说明原因";
try {
SubmitResp response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public SubmitResp run(SubmitReq request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, SubmitResp.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public Submit(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class SubmitReq {
@SerializedName("business_code")
public String businessCode;
@SerializedName("contact_info")
public ContactInfo contactInfo;
@SerializedName("subject_info")
public SubjectInfo subjectInfo;
@SerializedName("business_info")
public BusinessInfo businessInfo;
@SerializedName("settlement_info")
public SettlementInfo settlementInfo;
@SerializedName("bank_account_info")
public BankAccountInfo bankAccountInfo;
@SerializedName("addition_info")
public AdditionInfo additionInfo;
}
public static class SubmitResp {
@SerializedName("applyment_id")
public Long applymentId;
}
public static class ContactInfo {
@SerializedName("contact_type") public IdHolderType contactType;
@SerializedName("contact_name") public String contactName;
@SerializedName("contact_id_doc_type") public IdentificationType contactIdDocType;
@SerializedName("contact_id_number") public String contactIdNumber;
@SerializedName("contact_id_doc_copy") public String contactIdDocCopy;
@SerializedName("contact_id_doc_copy_back") public String contactIdDocCopyBack;
@SerializedName("contact_period_begin") public String contactPeriodBegin;
@SerializedName("contact_period_end") public String contactPeriodEnd;
@SerializedName("business_authorization_letter") public String businessAuthorizationLetter;
@SerializedName("openid") public String openid;
@SerializedName("mobile_phone") public String mobilePhone;
@SerializedName("contact_email") public String contactEmail;
}
public static class SubjectInfo {
@SerializedName("subject_type") public SubjectType subjectType;
@SerializedName("finance_institution") public Boolean financeInstitution;
@SerializedName("business_license_info") public BusinessLicense businessLicenseInfo;
@SerializedName("certificate_info") public CertificateInfo certificateInfo;
@SerializedName("certificate_letter_copy") public String certificateLetterCopy;
@SerializedName("finance_institution_info") public FinanceInstitutionInfo financeInstitutionInfo;
@SerializedName("identity_info") public IdentityInfo identityInfo;
@SerializedName("ubo_info_list") public List<UBOInfoList> uboInfoList;
}
public static class BusinessInfo {
@SerializedName("merchant_shortname") public String merchantShortname;
@SerializedName("service_phone") public String servicePhone;
@SerializedName("sales_info") public SalesInfo salesInfo;
}
public static class SettlementInfo {
@SerializedName("settlement_id") public String settlementId;
@SerializedName("qualification_type") public String qualificationType;
@SerializedName("qualifications") public List<String> qualifications;
@SerializedName("activities_id") public String activitiesId;
@SerializedName("activities_rate") public String activitiesRate;
@SerializedName("activities_additions") public List<String> activitiesAdditions;
@SerializedName("debit_activities_rate") public String debitActivitiesRate;
@SerializedName("credit_activities_rate") public String creditActivitiesRate;
}
public static class BankAccountInfo {
@SerializedName("bank_account_type") public BankAccountType bankAccountType;
@SerializedName("account_name") public String accountName;
@SerializedName("account_bank") public String accountBank;
@SerializedName("bank_address_code") public String bankAddressCode;
@SerializedName("bank_branch_id") public String bankBranchId;
@SerializedName("bank_name") public String bankName;
@SerializedName("account_number") public String accountNumber;
}
public static class AdditionInfo {
@SerializedName("legal_person_commitment") public String legalPersonCommitment;
@SerializedName("legal_person_video") public String legalPersonVideo;
@SerializedName("business_addition_pics") public List<String> businessAdditionPics;
@SerializedName("business_addition_msg") public String businessAdditionMsg;
}
public enum IdHolderType {
@SerializedName("LEGAL") LEGAL,
@SerializedName("SUPER") SUPER
}
public enum IdentificationType {
@SerializedName("IDENTIFICATION_TYPE_IDCARD") IDENTIFICATION_TYPE_IDCARD,
@SerializedName("IDENTIFICATION_TYPE_OVERSEA_PASSPORT") IDENTIFICATION_TYPE_OVERSEA_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_HONGKONG_PASSPORT") IDENTIFICATION_TYPE_HONGKONG_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_MACAO_PASSPORT") IDENTIFICATION_TYPE_MACAO_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_TAIWAN_PASSPORT") IDENTIFICATION_TYPE_TAIWAN_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_FOREIGN_RESIDENT") IDENTIFICATION_TYPE_FOREIGN_RESIDENT,
@SerializedName("IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT") IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT,
@SerializedName("IDENTIFICATION_TYPE_TAIWAN_RESIDENT") IDENTIFICATION_TYPE_TAIWAN_RESIDENT
}
public enum SubjectType {
@SerializedName("SUBJECT_TYPE_ENTERPRISE") SUBJECT_TYPE_ENTERPRISE,
@SerializedName("SUBJECT_TYPE_INSTITUTIONS") SUBJECT_TYPE_INSTITUTIONS,
@SerializedName("SUBJECT_TYPE_INDIVIDUAL") SUBJECT_TYPE_INDIVIDUAL,
@SerializedName("SUBJECT_TYPE_OTHERS") SUBJECT_TYPE_OTHERS,
@SerializedName("SUBJECT_TYPE_GOVERNMENT") SUBJECT_TYPE_GOVERNMENT
}
public static class BusinessLicense {
@SerializedName("license_copy") public String licenseCopy;
@SerializedName("license_number") public String licenseNumber;
@SerializedName("merchant_name") public String merchantName;
@SerializedName("legal_person") public String legalPerson;
@SerializedName("license_address") public String licenseAddress;
@SerializedName("period_begin") public String periodBegin;
@SerializedName("period_end") public String periodEnd;
}
public static class CertificateInfo {
@SerializedName("cert_copy") public String certCopy;
@SerializedName("cert_type") public CertificateType certType;
@SerializedName("cert_number") public String certNumber;
@SerializedName("merchant_name") public String merchantName;
@SerializedName("company_address") public String companyAddress;
@SerializedName("legal_person") public String legalPerson;
@SerializedName("period_begin") public String periodBegin;
@SerializedName("period_end") public String periodEnd;
}
public static class FinanceInstitutionInfo {
@SerializedName("finance_type") public FinanceType financeType;
@SerializedName("finance_license_pics") public List<String> financeLicensePics;
}
public static class IdentityInfo {
@SerializedName("id_holder_type") public IdHolderType idHolderType;
@SerializedName("id_doc_type") public IdentificationType idDocType;
@SerializedName("authorize_letter_copy") public String authorizeLetterCopy;
@SerializedName("id_card_info") public IdCardInfo idCardInfo;
@SerializedName("id_doc_info") public IdDocInfo idDocInfo;
@SerializedName("owner") public Boolean owner;
}
public static class UBOInfoList {
@SerializedName("ubo_id_doc_type") public IdentificationType uboIdDocType;
@SerializedName("ubo_id_doc_copy") public String uboIdDocCopy;
@SerializedName("ubo_id_doc_copy_back") public String uboIdDocCopyBack;
@SerializedName("ubo_id_doc_name") public String uboIdDocName;
@SerializedName("ubo_id_doc_number") public String uboIdDocNumber;
@SerializedName("ubo_id_doc_address") public String uboIdDocAddress;
@SerializedName("ubo_period_begin") public String uboPeriodBegin;
@SerializedName("ubo_period_end") public String uboPeriodEnd;
}
public static class SalesInfo {
@SerializedName("sales_scenes_type") public List<SalesScenesType> salesScenesType = new ArrayList<>();
@SerializedName("biz_store_info") public StoreInfo bizStoreInfo;
@SerializedName("mp_info") public MpInfo mpInfo;
@SerializedName("mini_program_info") public MiniProgramInfo miniProgramInfo;
@SerializedName("app_info") public AppInfo appInfo;
@SerializedName("web_info") public WebInfo webInfo;
@SerializedName("wework_info") public WeworkInfo weworkInfo;
}
public enum BankAccountType {
@SerializedName("BANK_ACCOUNT_TYPE_CORPORATE") BANK_ACCOUNT_TYPE_CORPORATE,
@SerializedName("BANK_ACCOUNT_TYPE_PERSONAL") BANK_ACCOUNT_TYPE_PERSONAL
}
public enum CertificateType {
@SerializedName("CERTIFICATE_TYPE_2388") CERTIFICATE_TYPE_2388,
@SerializedName("CERTIFICATE_TYPE_2389") CERTIFICATE_TYPE_2389,
@SerializedName("CERTIFICATE_TYPE_2394") CERTIFICATE_TYPE_2394,
@SerializedName("CERTIFICATE_TYPE_2395") CERTIFICATE_TYPE_2395,
@SerializedName("CERTIFICATE_TYPE_2396") CERTIFICATE_TYPE_2396,
@SerializedName("CERTIFICATE_TYPE_2399") CERTIFICATE_TYPE_2399,
@SerializedName("CERTIFICATE_TYPE_2400") CERTIFICATE_TYPE_2400,
@SerializedName("CERTIFICATE_TYPE_2391") CERTIFICATE_TYPE_2391,
@SerializedName("CERTIFICATE_TYPE_2520") CERTIFICATE_TYPE_2520,
@SerializedName("CERTIFICATE_TYPE_2521") CERTIFICATE_TYPE_2521,
@SerializedName("CERTIFICATE_TYPE_2522") CERTIFICATE_TYPE_2522
}
public enum FinanceType {
@SerializedName("BANK_AGENT") BANK_AGENT,
@SerializedName("PAYMENT_AGENT") PAYMENT_AGENT,
@SerializedName("INSURANCE") INSURANCE,
@SerializedName("TRADE_AND_SETTLE") TRADE_AND_SETTLE,
@SerializedName("OTHER") OTHER
}
public static class IdCardInfo {
@SerializedName("id_card_copy") public String idCardCopy;
@SerializedName("id_card_national") public String idCardNational;
@SerializedName("id_card_name") public String idCardName;
@SerializedName("id_card_number") public String idCardNumber;
@SerializedName("id_card_address") public String idCardAddress;
@SerializedName("card_period_begin") public String cardPeriodBegin;
@SerializedName("card_period_end") public String cardPeriodEnd;
}
public static class IdDocInfo {
@SerializedName("id_doc_copy") public String idDocCopy;
@SerializedName("id_doc_copy_back") public String idDocCopyBack;
@SerializedName("id_doc_name") public String idDocName;
@SerializedName("id_doc_number") public String idDocNumber;
@SerializedName("id_doc_address") public String idDocAddress;
@SerializedName("doc_period_begin") public String docPeriodBegin;
@SerializedName("doc_period_end") public String docPeriodEnd;
}
public enum SalesScenesType {
@SerializedName("SALES_SCENES_STORE") SALES_SCENES_STORE,
@SerializedName("SALES_SCENES_MP") SALES_SCENES_MP,
@SerializedName("SALES_SCENES_MINI_PROGRAM") SALES_SCENES_MINI_PROGRAM,
@SerializedName("SALES_SCENES_WEB") SALES_SCENES_WEB,
@SerializedName("SALES_SCENES_APP") SALES_SCENES_APP,
@SerializedName("SALES_SCENES_WEWORK") SALES_SCENES_WEWORK
}
public static class StoreInfo {
@SerializedName("biz_store_name") public String bizStoreName;
@SerializedName("biz_address_code") public String bizAddressCode;
@SerializedName("biz_store_address") public String bizStoreAddress;
@SerializedName("store_entrance_pic") public List<String> storeEntrancePic;
@SerializedName("indoor_pic") public List<String> indoorPic;
@SerializedName("biz_sub_appid") public String bizSubAppid;
}
public static class MpInfo {
@SerializedName("mp_appid") public String mpAppid;
@SerializedName("mp_sub_appid") public String mpSubAppid;
@SerializedName("mp_pics") public List<String> mpPics;
}
public static class MiniProgramInfo {
@SerializedName("mini_program_appid") public String miniProgramAppid;
@SerializedName("mini_program_sub_appid") public String miniProgramSubAppid;
@SerializedName("mini_program_pics") public List<String> miniProgramPics;
}
public static class AppInfo {
@SerializedName("app_appid") public String appAppid;
@SerializedName("app_sub_appid") public String appSubAppid;
@SerializedName("app_pics") public List<String> appPics;
}
public static class WebInfo {
@SerializedName("domain") public String domain;
@SerializedName("web_authorisation") public String webAuthorisation;
@SerializedName("web_appid") public String webAppid;
}
public static class WeworkInfo {
@SerializedName("sub_corp_id") public String subCorpId;
@SerializedName("wework_pics") public List<String> weworkPics;
}
}

View File

@@ -0,0 +1,19 @@
/**
* 图片上传
*
* 进件资料中的图片需先通过本接口上传获取 MediaID再将 MediaID 填入进件申请单对应字段。
* POST /v3/merchant/media/upload
*/
String filePath = "/your/home/hellokitty.png";
URI uri = new URI("https://api.mch.weixin.qq.com/v3/merchant/media/upload");
File file = new File(filePath);
try (FileInputStream ins1 = new FileInputStream(file)) {
String sha256 = DigestUtils.sha256Hex(ins1);
try (InputStream ins2 = new FileInputStream(file)) {
HttpPost request = new WechatPayUploadHttpPost.Builder(uri)
.withImage(file.getName(), sha256, ins2)
.build();
CloseableHttpResponse response1 = httpClient.execute(request);
}
}

View File

@@ -0,0 +1,19 @@
/**
* 视频上传
*
* 进件资料中的视频需先通过本接口上传获取 MediaID再将 MediaID 填入进件申请单对应字段。
* POST /v3/merchant/media/video_upload
*/
String filePath = "/your/home/hellokitty.avi";
URI uri = new URI("https://api.mch.weixin.qq.com/v3/merchant/media/video_upload");
File file = new File(filePath);
try (FileInputStream ins1 = new FileInputStream(file)) {
String sha256 = DigestUtils.sha256Hex(ins1);
try (InputStream ins2 = new FileInputStream(file)) {
HttpPost request = new WechatPayUploadHttpPost.Builder(uri)
.withImage(file.getName(), sha256, ins2)
.build();
CloseableHttpResponse response1 = httpClient.execute(request);
}
}

View File

@@ -0,0 +1,51 @@
# APP 调起支付
> 服务商模式与商户模式的调起支付代码完全一致,区别仅在于 `appId` 的取值:
> - 在服务商 APP 中调起支付时,`appId` 传 `sp_appid`
> - 在子商户 APP 中调起支付时,`appId` 传 `sub_appid`
>
> `appId` 必须与下单时传入的对应参数一致。
## iOS 示例
```objectivec
PayReq *request = [[[PayReq alloc] init] autorelease];
request.appId = "wxd930ea5d5a258f4f";
request.partnerId = "1900000109";
request.prepayId= "1101000000140415649af9fc314aa427",;
request.package = "Sign=WXPay";
request.nonceStr= "1101000000140429eb40476f8896f4c9";
request.timeStamp= "1398746574";
request.sign= "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==";
[WXApi sendReqrequest];
```
## Android 示例
```java
IWXAPI api;
PayReq request = new PayReq();
request.appId = "wxd930ea5d5a258f4f";
request.partnerId = "1900000109";
request.prepayId= "1101000000140415649af9fc314aa427",;
request.packageValue = "Sign=WXPay";
request.nonceStr= "1101000000140429eb40476f8896f4c9";
request.timeStamp= "1398746574";
request.sign= "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==";
api.sendReq(request);
```
## 鸿蒙示例
```typescript
IWXAPI api;
let req = new wxopensdk.PayReq
req.appId = 'wxd930ea5d5a258f4f'
req.partnerId = '1900000109'
req.prepayId = '1101000000140415649af9fc314aa427'
req.packageValue = 'Sign=WXPay'
req.nonceStr = '1101000000140429eb40476f8896f4c9'
req.timeStamp = '1398746574'
req.sign = 'oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg=='
api.sendReq(context: common.UIAbilityContext, req)
```

View File

@@ -0,0 +1,248 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* App下单
*/
public class PartnerAppPrepay {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/partner/transactions/app";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerAppPrepay client = new PartnerAppPrepay(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
PartnerAPIv3CommonPrepayRequest request = new PartnerAPIv3CommonPrepayRequest();
request.spAppid = "wx8888888888888888";
request.spMchid = "1230000109";
request.subAppid = "wxd678efh567hg6999";
request.subMchid = "1900000109";
request.description = "Image形象店-深圳腾大-QQ公仔";
request.outTradeNo = "1217752501201407033233368018";
request.timeExpire = "2018-06-08T10:34:56+08:00";
request.attach = "自定义数据说明";
request.notifyUrl = " https://www.weixin.qq.com/wxpay/pay.php";
request.goodsTag = "WXG";
request.settleInfo = new PartnerSettleInfo();
request.settleInfo.profitSharing = true;
request.supportFapiao = false;
request.amount = new CommonAmountInfo();
request.amount.total = 100L;
request.amount.currency = "CNY";
request.detail = new CouponInfo();
request.detail.costPrice = 608800L;
request.detail.invoiceId = "微信123";
request.detail.goodsDetail = new ArrayList<>();
{
GoodsDetail goodsDetailItem0 = new GoodsDetail();
goodsDetailItem0.merchantGoodsId = "1246464644";
goodsDetailItem0.wechatpayGoodsId = "1001";
goodsDetailItem0.goodsName = "iPhoneX 256G";
goodsDetailItem0.quantity = 1L;
goodsDetailItem0.unitPrice = 528800L;
request.detail.goodsDetail.add(goodsDetailItem0);
};
request.sceneInfo = new CommonSceneInfo();
request.sceneInfo.payerClientIp = "14.23.150.211";
request.sceneInfo.deviceId = "013467007045764";
request.sceneInfo.storeInfo = new StoreInfo();
request.sceneInfo.storeInfo.id = "0001";
request.sceneInfo.storeInfo.name = "腾讯大厦分店";
request.sceneInfo.storeInfo.areaCode = "440305";
request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";
try {
PartnerAPIv3AppPrepayResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public PartnerAPIv3AppPrepayResponse run(PartnerAPIv3CommonPrepayRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, PartnerAPIv3AppPrepayResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerAppPrepay(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerAPIv3CommonPrepayRequest {
@SerializedName("sp_appid")
public String spAppid;
@SerializedName("sp_mchid")
public String spMchid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("description")
public String description;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("time_expire")
public String timeExpire;
@SerializedName("attach")
public String attach;
@SerializedName("notify_url")
public String notifyUrl;
@SerializedName("goods_tag")
public String goodsTag;
@SerializedName("settle_info")
public PartnerSettleInfo settleInfo;
@SerializedName("support_fapiao")
public Boolean supportFapiao;
@SerializedName("amount")
public CommonAmountInfo amount;
@SerializedName("detail")
public CouponInfo detail;
@SerializedName("scene_info")
public CommonSceneInfo sceneInfo;
}
public static class PartnerAPIv3AppPrepayResponse {
@SerializedName("prepay_id")
public String prepayId;
}
public static class PartnerSettleInfo {
@SerializedName("profit_sharing")
public Boolean profitSharing;
}
public static class CommonAmountInfo {
@SerializedName("total")
public Long total;
@SerializedName("currency")
public String currency;
}
public static class CouponInfo {
@SerializedName("cost_price")
public Long costPrice;
@SerializedName("invoice_id")
public String invoiceId;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public static class CommonSceneInfo {
@SerializedName("payer_client_ip")
public String payerClientIp;
@SerializedName("device_id")
public String deviceId;
@SerializedName("store_info")
public StoreInfo storeInfo;
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id")
public String merchantGoodsId;
@SerializedName("wechatpay_goods_id")
public String wechatpayGoodsId;
@SerializedName("goods_name")
public String goodsName;
@SerializedName("quantity")
public Long quantity;
@SerializedName("unit_price")
public Long unitPrice;
}
public static class StoreInfo {
@SerializedName("id")
public String id;
@SerializedName("name")
public String name;
@SerializedName("area_code")
public String areaCode;
@SerializedName("address")
public String address;
}
}

View File

@@ -0,0 +1,112 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 撤销申请单
*/
public class CancelApplyment {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/apply4subject/applyment/{business_code}/cancel";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
CancelApplyment client = new CancelApplyment(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
CancelApplymentRequest request = new CancelApplymentRequest();
request.businessCode = "1900013511_10000";
request.applymentId = 20000011111L;
try {
client.run(request);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public void run(CancelApplymentRequest request) {
String uri = PATH;
uri = uri.replace("{business_code}", WXPayUtility.urlEncode(request.businessCode));
Map<String, Object> args = new HashMap<>();
args.put("applyment_id", request.applymentId);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody emptyBody = RequestBody.create(null, "");
reqBuilder.method(METHOD, emptyBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return;
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public CancelApplyment(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class CancelApplymentRequest {
@SerializedName("applyment_id")
@Expose(serialize = false)
public Long applymentId;
@SerializedName("business_code")
@Expose(serialize = false)
public String businessCode;
}
}

View File

@@ -0,0 +1,146 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询申请单审核结果
*/
public class GetAuditResult {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/apply4subject/applyment";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetAuditResult client = new GetAuditResult(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
GetAuditResultRequest request = new GetAuditResultRequest();
request.applymentId = 20000011111L;
request.businessCode = "1900013511_10000";
try {
GetAuditResultResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public GetAuditResultResponse run(GetAuditResultRequest request) {
String uri = PATH;
Map<String, Object> args = new HashMap<>();
args.put("applyment_id", request.applymentId);
args.put("business_code", request.businessCode);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, GetAuditResultResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetAuditResult(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetAuditResultRequest {
@SerializedName("applyment_id")
@Expose(serialize = false)
public Long applymentId;
@SerializedName("business_code")
@Expose(serialize = false)
public String businessCode;
}
public static class GetAuditResultResponse {
@SerializedName("applyment_state")
public ApplymentState applymentState;
@SerializedName("qrcode_data")
public String qrcodeData;
@SerializedName("reject_param")
public String rejectParam;
@SerializedName("reject_reason")
public String rejectReason;
}
public enum ApplymentState {
@SerializedName("APPLYMENT_STATE_EDITTING")
APPLYMENT_STATE_EDITTING,
@SerializedName("APPLYMENT_STATE_WAITTING_FOR_AUDIT")
APPLYMENT_STATE_WAITTING_FOR_AUDIT,
@SerializedName("APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT")
APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT,
@SerializedName("APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON")
APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON,
@SerializedName("APPLYMENT_STATE_PASSED")
APPLYMENT_STATE_PASSED,
@SerializedName("APPLYMENT_STATE_REJECTED")
APPLYMENT_STATE_REJECTED,
@SerializedName("APPLYMENT_STATE_FREEZED")
APPLYMENT_STATE_FREEZED,
@SerializedName("APPLYMENT_STATE_CANCELED")
APPLYMENT_STATE_CANCELED
}
}

View File

@@ -0,0 +1,114 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 获取商户开户意愿确认状态
*/
public class GetAuthorizeState {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/apply4subject/applyment/merchants/{sub_mchid}/state";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
GetAuthorizeState client = new GetAuthorizeState(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
GetAuthorizeStateRequest request = new GetAuthorizeStateRequest();
request.subMchid = "20001111";
try {
GetAuthorizeStateResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public GetAuthorizeStateResponse run(GetAuthorizeStateRequest request) {
String uri = PATH;
uri = uri.replace("{sub_mchid}", WXPayUtility.urlEncode(request.subMchid));
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, GetAuthorizeStateResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public GetAuthorizeState(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class GetAuthorizeStateRequest {
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
}
public static class GetAuthorizeStateResponse {
@SerializedName("authorize_state")
public AuthorizeState authorizeState;
}
public enum AuthorizeState {
@SerializedName("AUTHORIZE_STATE_UNAUTHORIZED")
AUTHORIZE_STATE_UNAUTHORIZED,
@SerializedName("AUTHORIZE_STATE_AUTHORIZED")
AUTHORIZE_STATE_AUTHORIZED
}
}

View File

@@ -0,0 +1,541 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 提交申请单
*/
public class SubmitApplyment {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/apply4subject/applyment";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
SubmitApplyment client = new SubmitApplyment(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
SubmitApplymentRequest request = new SubmitApplymentRequest();
request.channelId = "20001111";
request.businessCode = "1900013511_10000";
request.contactInfo = new ContactInfo();
request.contactInfo.name = client.encrypt("name");
request.contactInfo.mobile = client.encrypt("mobile");
request.contactInfo.idCardNumber = client.encrypt("id_card_number");
request.contactInfo.contactType = IdHolderType.LEGAL;
request.contactInfo.contactIdDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
request.contactInfo.contactIdDocCopy = "jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.contactInfo.contactIdDocCopyBack = "jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ";
request.contactInfo.contactPeriodBegin = "2019-06-06";
request.contactInfo.contactPeriodEnd = "2026-06-06";
request.subjectInfo = new SubjectInfo();
request.subjectInfo.subjectType = SubjectType.SUBJECT_TYPE_ENTERPRISE;
request.subjectInfo.isFinanceInstitution = false;
request.subjectInfo.businessLicenceInfo = new BusinessLicenceInfo();
request.subjectInfo.businessLicenceInfo.licenceNumber = "914201123033363296";
request.subjectInfo.businessLicenceInfo.licenceCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.businessLicenceInfo.merchantName = "李四网络有限公司";
request.subjectInfo.businessLicenceInfo.legalPerson = "李四";
request.subjectInfo.businessLicenceInfo.companyAddress = "广东省深圳市南山区xx路xx号";
request.subjectInfo.businessLicenceInfo.licenceValidDate = "[\\\"2017-10-28\\\",\\\"2037-10-28\\\"]";
request.subjectInfo.certificateInfo = new CertificateInfo();
request.subjectInfo.certificateInfo.certType = CertificateType.CERTIFICATE_TYPE_2388;
request.subjectInfo.certificateInfo.certNumber = "111111111111";
request.subjectInfo.certificateInfo.certCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.certificateInfo.merchantName = "xx公益团体";
request.subjectInfo.certificateInfo.legalPerson = "李四";
request.subjectInfo.certificateInfo.companyAddress = "广东省深圳市南山区xx路xx号";
request.subjectInfo.certificateInfo.certValidDate = "[\\\"2017-10-28\\\",\\\"2037-10-28\\\"]";
request.subjectInfo.companyProveCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.assistProveInfo = new AssitProveInfo();
request.subjectInfo.assistProveInfo.microBizType = MicroBizType.MICRO_TYPE_STORE;
request.subjectInfo.assistProveInfo.storeName = "大郎烧饼";
request.subjectInfo.assistProveInfo.storeAddressCode = "440305";
request.subjectInfo.assistProveInfo.storeAddress = "广东省深圳市南山区xx大厦x层xxxx室";
request.subjectInfo.assistProveInfo.storeHeaderCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.assistProveInfo.storeIndoorCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.subjectInfo.specialOperationList = new ArrayList<>();
{
SpecialOperation specialOperationListItem = new SpecialOperation();
specialOperationListItem.categoryId = 100L;
specialOperationListItem.operationCopyList = new ArrayList<>();
{
specialOperationListItem.operationCopyList.add("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo");
};
request.subjectInfo.specialOperationList.add(specialOperationListItem);
};
request.subjectInfo.financeInstitutionInfo = new FinanceInstitutionInfo();
request.subjectInfo.financeInstitutionInfo.financeType = FinanceType.BANK_AGENT;
request.subjectInfo.financeInstitutionInfo.financeLicensePics = new ArrayList<>();
{
request.subjectInfo.financeInstitutionInfo.financeLicensePics.add("0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo");
};
request.identificationInfo = new IdentificationInfo();
request.identificationInfo.idHolderType = IdHolderType.LEGAL;
request.identificationInfo.identificationType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
request.identificationInfo.identificationName = client.encrypt("identification_name");
request.identificationInfo.identificationNumber = client.encrypt("identification_number");
request.identificationInfo.identificationValidDate = "[\\\"2017-10-28\\\",\\\"2037-10-28\\\"]";
request.identificationInfo.identificationFrontCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.identificationInfo.identificationBackCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.identificationInfo.authorizeLetterCopy = "0P3ng6KTIW4-Q_l2FjKLZuhHjBWoMAjmVtCz7ScmhEIThCaV-4BBgVwtNkCHO_XXqK5dE5YdOmFJBZR9FwczhJehHhAZN6BKXQPcs-VvdSo";
request.identificationInfo.owner = false;
request.identificationInfo.identificationAddress = client.encrypt("identification_address");
request.uboInfo = new UBOInfo();
request.uboInfo.uboIdType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
request.uboInfo.uboIdCardCopy = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.uboInfo.uboIdCardNational = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.uboInfo.uboIdDocCopy = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ";
request.uboInfo.uboName = client.encrypt("ubo_name");
request.uboInfo.uboIdNumber = client.encrypt("ubo_id_number");
request.uboInfo.uboIdCardValidDate = "[\\\"2017-10-28\\\",\\\"2037-10-28\\\"]";
request.additionInfo = new AdditionInfo();
request.additionInfo.confirmMchidList = new ArrayList<>();
{
request.additionInfo.confirmMchidList.add("example_confirmMchidList");
};
request.uboInfoList = new ArrayList<>();
{
UBOInfoList uboInfoListItem = new UBOInfoList();
uboInfoListItem.uboIdDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD;
uboInfoListItem.uboIdDocCopy = "jTpGmxUXqRTvDujqhThn4ReFxikqJ5YW6zFQ";
uboInfoListItem.uboIdDocCopyBack = "jTpGmxUX3FBWVQ5NJTZvvDujqhThn4ReFxikqJ5YW6zFQ";
uboInfoListItem.uboIdDocName = client.encrypt("ubo_id_doc_name");
uboInfoListItem.uboIdDocNumber = client.encrypt("ubo_id_doc_number");
uboInfoListItem.uboIdDocAddress = client.encrypt("ubo_id_doc_address");
uboInfoListItem.uboPeriodBegin = "2019-06-06";
uboInfoListItem.uboPeriodEnd = "2026-06-06";
request.uboInfoList.add(uboInfoListItem);
};
try {
SubmitApplymentResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public SubmitApplymentResponse run(SubmitApplymentRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, SubmitApplymentResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public SubmitApplyment(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class SubmitApplymentRequest {
@SerializedName("channel_id")
public String channelId;
@SerializedName("business_code")
public String businessCode;
@SerializedName("contact_info")
public ContactInfo contactInfo;
@SerializedName("subject_info")
public SubjectInfo subjectInfo;
@SerializedName("identification_info")
public IdentificationInfo identificationInfo;
@SerializedName("ubo_info")
public UBOInfo uboInfo;
@SerializedName("addition_info")
public AdditionInfo additionInfo;
@SerializedName("ubo_info_list")
public List<UBOInfoList> uboInfoList;
}
public static class SubmitApplymentResponse {
@SerializedName("applyment_id")
public Long applymentId;
}
public static class ContactInfo {
@SerializedName("name")
public String name;
@SerializedName("mobile")
public String mobile;
@SerializedName("id_card_number")
public String idCardNumber;
@SerializedName("contact_type")
public IdHolderType contactType;
@SerializedName("contact_id_doc_type")
public IdentificationType contactIdDocType;
@SerializedName("contact_id_doc_copy")
public String contactIdDocCopy;
@SerializedName("contact_id_doc_copy_back")
public String contactIdDocCopyBack;
@SerializedName("contact_period_begin")
public String contactPeriodBegin;
@SerializedName("contact_period_end")
public String contactPeriodEnd;
}
public static class SubjectInfo {
@SerializedName("subject_type")
public SubjectType subjectType;
@SerializedName("is_finance_institution")
public Boolean isFinanceInstitution;
@SerializedName("business_licence_info")
public BusinessLicenceInfo businessLicenceInfo;
@SerializedName("certificate_info")
public CertificateInfo certificateInfo;
@SerializedName("company_prove_copy")
public String companyProveCopy;
@SerializedName("assist_prove_info")
public AssitProveInfo assistProveInfo;
@SerializedName("special_operation_list")
public List<SpecialOperation> specialOperationList;
@SerializedName("finance_institution_info")
public FinanceInstitutionInfo financeInstitutionInfo;
}
public static class IdentificationInfo {
@SerializedName("id_holder_type")
public IdHolderType idHolderType;
@SerializedName("identification_type")
public IdentificationType identificationType;
@SerializedName("identification_name")
public String identificationName;
@SerializedName("identification_number")
public String identificationNumber;
@SerializedName("identification_valid_date")
public String identificationValidDate;
@SerializedName("identification_front_copy")
public String identificationFrontCopy;
@SerializedName("identification_back_copy")
public String identificationBackCopy;
@SerializedName("authorize_letter_copy")
public String authorizeLetterCopy;
@SerializedName("owner")
public Boolean owner;
@SerializedName("identification_address")
public String identificationAddress;
}
public static class UBOInfo {
@SerializedName("ubo_id_type")
public IdentificationType uboIdType;
@SerializedName("ubo_id_card_copy")
public String uboIdCardCopy;
@SerializedName("ubo_id_card_national")
public String uboIdCardNational;
@SerializedName("ubo_id_doc_copy")
public String uboIdDocCopy;
@SerializedName("ubo_name")
public String uboName;
@SerializedName("ubo_id_number")
public String uboIdNumber;
@SerializedName("ubo_id_card_valid_date")
public String uboIdCardValidDate;
}
public static class AdditionInfo {
@SerializedName("confirm_mchid_list")
public List<String> confirmMchidList;
}
public static class UBOInfoList {
@SerializedName("ubo_id_doc_type")
public IdentificationType uboIdDocType;
@SerializedName("ubo_id_doc_copy")
public String uboIdDocCopy;
@SerializedName("ubo_id_doc_copy_back")
public String uboIdDocCopyBack;
@SerializedName("ubo_id_doc_name")
public String uboIdDocName;
@SerializedName("ubo_id_doc_number")
public String uboIdDocNumber;
@SerializedName("ubo_id_doc_address")
public String uboIdDocAddress;
@SerializedName("ubo_period_begin")
public String uboPeriodBegin;
@SerializedName("ubo_period_end")
public String uboPeriodEnd;
}
public enum IdHolderType {
@SerializedName("LEGAL")
LEGAL,
@SerializedName("SUPER")
SUPER
}
public enum IdentificationType {
@SerializedName("IDENTIFICATION_TYPE_IDCARD")
IDENTIFICATION_TYPE_IDCARD,
@SerializedName("IDENTIFICATION_TYPE_OVERSEA_PASSPORT")
IDENTIFICATION_TYPE_OVERSEA_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_HONGKONG_PASSPORT")
IDENTIFICATION_TYPE_HONGKONG_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_MACAO_PASSPORT")
IDENTIFICATION_TYPE_MACAO_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_TAIWAN_PASSPORT")
IDENTIFICATION_TYPE_TAIWAN_PASSPORT,
@SerializedName("IDENTIFICATION_TYPE_FOREIGN_RESIDENT")
IDENTIFICATION_TYPE_FOREIGN_RESIDENT,
@SerializedName("IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT")
IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT,
@SerializedName("IDENTIFICATION_TYPE_TAIWAN_RESIDENT")
IDENTIFICATION_TYPE_TAIWAN_RESIDENT
}
public enum SubjectType {
@SerializedName("SUBJECT_TYPE_ENTERPRISE")
SUBJECT_TYPE_ENTERPRISE,
@SerializedName("SUBJECT_TYPE_INSTITUTIONS_CLONED")
SUBJECT_TYPE_INSTITUTIONS_CLONED,
@SerializedName("SUBJECT_TYPE_INDIVIDUAL")
SUBJECT_TYPE_INDIVIDUAL,
@SerializedName("SUBJECT_TYPE_OTHERS")
SUBJECT_TYPE_OTHERS,
@SerializedName("SUBJECT_TYPE_MICRO")
SUBJECT_TYPE_MICRO,
@SerializedName("SUBJECT_TYPE_GOVERNMENT")
SUBJECT_TYPE_GOVERNMENT
}
public static class BusinessLicenceInfo {
@SerializedName("licence_number")
public String licenceNumber;
@SerializedName("licence_copy")
public String licenceCopy;
@SerializedName("merchant_name")
public String merchantName;
@SerializedName("legal_person")
public String legalPerson;
@SerializedName("company_address")
public String companyAddress;
@SerializedName("licence_valid_date")
public String licenceValidDate;
}
public static class CertificateInfo {
@SerializedName("cert_type")
public CertificateType certType;
@SerializedName("cert_number")
public String certNumber;
@SerializedName("cert_copy")
public String certCopy;
@SerializedName("merchant_name")
public String merchantName;
@SerializedName("legal_person")
public String legalPerson;
@SerializedName("company_address")
public String companyAddress;
@SerializedName("cert_valid_date")
public String certValidDate;
}
public static class AssitProveInfo {
@SerializedName("micro_biz_type")
public MicroBizType microBizType;
@SerializedName("store_name")
public String storeName;
@SerializedName("store_address_code")
public String storeAddressCode;
@SerializedName("store_address")
public String storeAddress;
@SerializedName("store_header_copy")
public String storeHeaderCopy;
@SerializedName("store_indoor_copy")
public String storeIndoorCopy;
}
public static class SpecialOperation {
@SerializedName("category_id")
public Long categoryId;
@SerializedName("operation_copy_list")
public List<String> operationCopyList;
}
public static class FinanceInstitutionInfo {
@SerializedName("finance_type")
public FinanceType financeType;
@SerializedName("finance_license_pics")
public List<String> financeLicensePics = new ArrayList<String>();
}
public enum CertificateType {
@SerializedName("CERTIFICATE_TYPE_2388")
CERTIFICATE_TYPE_2388,
@SerializedName("CERTIFICATE_TYPE_2389")
CERTIFICATE_TYPE_2389,
@SerializedName("CERTIFICATE_TYPE_2394")
CERTIFICATE_TYPE_2394,
@SerializedName("CERTIFICATE_TYPE_2395")
CERTIFICATE_TYPE_2395,
@SerializedName("CERTIFICATE_TYPE_2396")
CERTIFICATE_TYPE_2396,
@SerializedName("CERTIFICATE_TYPE_2397")
CERTIFICATE_TYPE_2397,
@SerializedName("CERTIFICATE_TYPE_2398")
CERTIFICATE_TYPE_2398,
@SerializedName("CERTIFICATE_TYPE_2399")
CERTIFICATE_TYPE_2399,
@SerializedName("CERTIFICATE_TYPE_2400")
CERTIFICATE_TYPE_2400,
@SerializedName("CERTIFICATE_TYPE_2390")
CERTIFICATE_TYPE_2390,
@SerializedName("CERTIFICATE_TYPE_2391")
CERTIFICATE_TYPE_2391,
@SerializedName("CERTIFICATE_TYPE_2392")
CERTIFICATE_TYPE_2392,
@SerializedName("CERTIFICATE_TYPE_2393")
CERTIFICATE_TYPE_2393,
@SerializedName("CERTIFICATE_TYPE_2520")
CERTIFICATE_TYPE_2520,
@SerializedName("CERTIFICATE_TYPE_2521")
CERTIFICATE_TYPE_2521,
@SerializedName("CERTIFICATE_TYPE_2522")
CERTIFICATE_TYPE_2522
}
public enum MicroBizType {
@SerializedName("MICRO_TYPE_STORE")
MICRO_TYPE_STORE,
@SerializedName("MICRO_TYPE_MOBILE")
MICRO_TYPE_MOBILE,
@SerializedName("MICRO_TYPE_ONLINE")
MICRO_TYPE_ONLINE
}
public enum FinanceType {
@SerializedName("BANK_AGENT")
BANK_AGENT,
@SerializedName("PAYMENT_AGENT")
PAYMENT_AGENT,
@SerializedName("INSURANCE")
INSURANCE,
@SerializedName("TRADE_AND_SETTLE")
TRADE_AND_SETTLE,
@SerializedName("OTHER")
OTHER
}
}

View File

@@ -0,0 +1,19 @@
/**
* 图片上传
*
* 开户意愿确认资料中的图片需先通过本接口上传获取 MediaID再将 MediaID 填入申请单对应字段。
* POST /v3/merchant/media/upload
*/
String filePath = "/your/home/hellokitty.png";
URI uri = new URI("https://api.mch.weixin.qq.com/v3/merchant/media/upload");
File file = new File(filePath);
try (FileInputStream ins1 = new FileInputStream(file)) {
String sha256 = DigestUtils.sha256Hex(ins1);
try (InputStream ins2 = new FileInputStream(file)) {
HttpPost request = new WechatPayUploadHttpPost.Builder(uri)
.withImage(file.getName(), sha256, ins2)
.build();
CloseableHttpResponse response1 = httpClient.execute(request);
}
}

View File

@@ -0,0 +1,23 @@
# H5 调起支付
> 服务商模式与商户模式的 H5 调起支付完全一致。
## 调起步骤
1. 服务商通过 H5 下单接口获取 `h5_url`
2. 在配置了 H5 支付域名的网页中跳转 `h5_url`,调起微信支付收银台中间页
3. 微信支付收银台进行 H5 权限校验和安全性检查,校验通过后用户正常支付
## 支付后返回指定页面
用户支付完成后默认返回发起支付的页面。如需返回指定页面,在 `h5_url` 后拼接 `redirect_url` 参数:
```
h5_url=https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn
```
> `redirect_url` 的域名必须为商户配置的 H5 支付域名,且需对 `redirect_url` 进行 urlencode 处理。
## 返回商户 H5 页面后查单
用户点击"取消支付"或支付成功后点击"完成"时,会返回服务商的支付页面(或指定的 `redirect_url` 页面)。建议在回跳页面中增设"确认支付情况"按钮,用户点击后触发查单操作,确保及时了解订单状态。

View File

@@ -0,0 +1,201 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* H5下单
*/
public class PartnerH5Prepay {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/partner/transactions/h5";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerH5Prepay client = new PartnerH5Prepay(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
PartnerAPIv3PartnerH5PrepayRequest request = new PartnerAPIv3PartnerH5PrepayRequest();
request.spAppid = "wx8888888888888888";
request.spMchid = "1230000109";
request.subAppid = "wxd678efh567hg6999";
request.subMchid = "1900000109";
request.description = "Image形象店-深圳腾大-QQ公仔";
request.outTradeNo = "1217752501201407033233368018";
request.timeExpire = "2018-06-08T10:34:56+08:00";
request.attach = "自定义数据说明";
request.notifyUrl = " https://www.weixin.qq.com/wxpay/pay.php";
request.goodsTag = "WXG";
request.settleInfo = new PartnerSettleInfo();
request.settleInfo.profitSharing = true;
request.supportFapiao = false;
request.amount = new CommonAmountInfo();
request.amount.total = 100L;
request.amount.currency = "CNY";
request.detail = new CouponInfo();
request.detail.costPrice = 608800L;
request.detail.invoiceId = "微信123";
request.detail.goodsDetail = new ArrayList<>();
{
GoodsDetail goodsDetailItem0 = new GoodsDetail();
goodsDetailItem0.merchantGoodsId = "1246464644";
goodsDetailItem0.wechatpayGoodsId = "1001";
goodsDetailItem0.goodsName = "iPhoneX 256G";
goodsDetailItem0.quantity = 1L;
goodsDetailItem0.unitPrice = 528800L;
request.detail.goodsDetail.add(goodsDetailItem0);
};
request.sceneInfo = new H5ReqSceneInfo();
request.sceneInfo.payerClientIp = "14.23.150.211";
request.sceneInfo.deviceId = "013467007045764";
request.sceneInfo.storeInfo = new StoreInfo();
request.sceneInfo.storeInfo.id = "0001";
request.sceneInfo.storeInfo.name = "腾讯大厦分店";
request.sceneInfo.storeInfo.areaCode = "440305";
request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";
request.sceneInfo.h5Info = new H5Info();
request.sceneInfo.h5Info.type = "iOS";
request.sceneInfo.h5Info.appName = "王者荣耀";
request.sceneInfo.h5Info.appUrl = "https://pay.qq.com";
request.sceneInfo.h5Info.bundleId = "com.tencent.wzryiOS";
request.sceneInfo.h5Info.packageName = "com.tencent.tmgp.sgame";
try {
PartnerAPIv3PartnerH5PrepayResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public PartnerAPIv3PartnerH5PrepayResponse run(PartnerAPIv3PartnerH5PrepayRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, PartnerAPIv3PartnerH5PrepayResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerH5Prepay(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerAPIv3PartnerH5PrepayRequest {
@SerializedName("sp_appid") public String spAppid;
@SerializedName("sp_mchid") public String spMchid;
@SerializedName("sub_appid") public String subAppid;
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("description") public String description;
@SerializedName("out_trade_no") public String outTradeNo;
@SerializedName("time_expire") public String timeExpire;
@SerializedName("attach") public String attach;
@SerializedName("notify_url") public String notifyUrl;
@SerializedName("goods_tag") public String goodsTag;
@SerializedName("settle_info") public PartnerSettleInfo settleInfo;
@SerializedName("support_fapiao") public Boolean supportFapiao;
@SerializedName("amount") public CommonAmountInfo amount;
@SerializedName("detail") public CouponInfo detail;
@SerializedName("scene_info") public H5ReqSceneInfo sceneInfo;
}
public static class PartnerAPIv3PartnerH5PrepayResponse {
@SerializedName("h5_url") public String h5Url;
}
public static class PartnerSettleInfo {
@SerializedName("profit_sharing") public Boolean profitSharing;
}
public static class CommonAmountInfo {
@SerializedName("total") public Long total;
@SerializedName("currency") public String currency;
}
public static class CouponInfo {
@SerializedName("cost_price") public Long costPrice;
@SerializedName("invoice_id") public String invoiceId;
@SerializedName("goods_detail") public List<GoodsDetail> goodsDetail;
}
public static class H5ReqSceneInfo {
@SerializedName("payer_client_ip") public String payerClientIp;
@SerializedName("device_id") public String deviceId;
@SerializedName("store_info") public StoreInfo storeInfo;
@SerializedName("h5_info") public H5Info h5Info;
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id") public String merchantGoodsId;
@SerializedName("wechatpay_goods_id") public String wechatpayGoodsId;
@SerializedName("goods_name") public String goodsName;
@SerializedName("quantity") public Long quantity;
@SerializedName("unit_price") public Long unitPrice;
}
public static class StoreInfo {
@SerializedName("id") public String id;
@SerializedName("name") public String name;
@SerializedName("area_code") public String areaCode;
@SerializedName("address") public String address;
}
public static class H5Info {
@SerializedName("type") public String type;
@SerializedName("app_name") public String appName;
@SerializedName("app_url") public String appUrl;
@SerializedName("bundle_id") public String bundleId;
@SerializedName("package_name") public String packageName;
}
}

View File

@@ -0,0 +1,11 @@
# Native 调起支付
> 服务商模式与商户模式的 Native 调起支付完全一致。
## 调起步骤
1. 通过 Native 下单接口获取 `code_url`
2.`code_url` 转换为二维码图片,展示给用户
3. 用户打开微信"扫一扫",扫描二维码完成支付
> ⚠️ 不支持通过相册识别或长按识别二维码完成支付,仅支持扫一扫。

View File

@@ -0,0 +1,186 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Native下单
*/
public class PartnerNativePrepay {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/partner/transactions/native";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerNativePrepay client = new PartnerNativePrepay(
"19xxxxxxxx",
"1DDE55AD98Exxxxxxxxxx",
"/path/to/apiclient_key.pem",
"PUB_KEY_ID_xxxxxxxxxxxxx",
"/path/to/wxp_pub.pem"
);
PartnerAPIv3CommonPrepayRequest request = new PartnerAPIv3CommonPrepayRequest();
request.spAppid = "wx8888888888888888";
request.spMchid = "1230000109";
request.subAppid = "wxd678efh567hg6999";
request.subMchid = "1900000109";
request.description = "Image形象店-深圳腾大-QQ公仔";
request.outTradeNo = "1217752501201407033233368018";
request.timeExpire = "2018-06-08T10:34:56+08:00";
request.attach = "自定义数据说明";
request.notifyUrl = " https://www.weixin.qq.com/wxpay/pay.php";
request.goodsTag = "WXG";
request.settleInfo = new PartnerSettleInfo();
request.settleInfo.profitSharing = true;
request.supportFapiao = false;
request.amount = new CommonAmountInfo();
request.amount.total = 100L;
request.amount.currency = "CNY";
request.detail = new CouponInfo();
request.detail.costPrice = 608800L;
request.detail.invoiceId = "微信123";
request.detail.goodsDetail = new ArrayList<>();
{
GoodsDetail goodsDetailItem0 = new GoodsDetail();
goodsDetailItem0.merchantGoodsId = "1246464644";
goodsDetailItem0.wechatpayGoodsId = "1001";
goodsDetailItem0.goodsName = "iPhoneX 256G";
goodsDetailItem0.quantity = 1L;
goodsDetailItem0.unitPrice = 528800L;
request.detail.goodsDetail.add(goodsDetailItem0);
};
request.sceneInfo = new CommonSceneInfo();
request.sceneInfo.payerClientIp = "14.23.150.211";
request.sceneInfo.deviceId = "013467007045764";
request.sceneInfo.storeInfo = new StoreInfo();
request.sceneInfo.storeInfo.id = "0001";
request.sceneInfo.storeInfo.name = "腾讯大厦分店";
request.sceneInfo.storeInfo.areaCode = "440305";
request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";
try {
PartnerAPIv3PartnerNativePrepayResponse response = client.run(request);
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
e.printStackTrace();
}
}
public PartnerAPIv3PartnerNativePrepayResponse run(PartnerAPIv3CommonPrepayRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return WXPayUtility.fromJson(respBody, PartnerAPIv3PartnerNativePrepayResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerNativePrepay(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerAPIv3CommonPrepayRequest {
@SerializedName("sp_appid") public String spAppid;
@SerializedName("sp_mchid") public String spMchid;
@SerializedName("sub_appid") public String subAppid;
@SerializedName("sub_mchid") public String subMchid;
@SerializedName("description") public String description;
@SerializedName("out_trade_no") public String outTradeNo;
@SerializedName("time_expire") public String timeExpire;
@SerializedName("attach") public String attach;
@SerializedName("notify_url") public String notifyUrl;
@SerializedName("goods_tag") public String goodsTag;
@SerializedName("settle_info") public PartnerSettleInfo settleInfo;
@SerializedName("support_fapiao") public Boolean supportFapiao;
@SerializedName("amount") public CommonAmountInfo amount;
@SerializedName("detail") public CouponInfo detail;
@SerializedName("scene_info") public CommonSceneInfo sceneInfo;
}
public static class PartnerAPIv3PartnerNativePrepayResponse {
@SerializedName("code_url") public String codeUrl;
}
public static class PartnerSettleInfo {
@SerializedName("profit_sharing") public Boolean profitSharing;
}
public static class CommonAmountInfo {
@SerializedName("total") public Long total;
@SerializedName("currency") public String currency;
}
public static class CouponInfo {
@SerializedName("cost_price") public Long costPrice;
@SerializedName("invoice_id") public String invoiceId;
@SerializedName("goods_detail") public List<GoodsDetail> goodsDetail;
}
public static class CommonSceneInfo {
@SerializedName("payer_client_ip") public String payerClientIp;
@SerializedName("device_id") public String deviceId;
@SerializedName("store_info") public StoreInfo storeInfo;
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id") public String merchantGoodsId;
@SerializedName("wechatpay_goods_id") public String wechatpayGoodsId;
@SerializedName("goods_name") public String goodsName;
@SerializedName("quantity") public Long quantity;
@SerializedName("unit_price") public Long unitPrice;
}
public static class StoreInfo {
@SerializedName("id") public String id;
@SerializedName("name") public String name;
@SerializedName("area_code") public String areaCode;
@SerializedName("address") public String address;
}
}

View File

@@ -0,0 +1,45 @@
# 小程序调起支付
> 服务商模式与商户模式的小程序调起支付代码完全一致,区别仅在于签名使用的 `appid`
> - 在服务商小程序中调起支付时,签名用 `sp_appid`
> - 在子商户小程序中调起支付时,签名用 `sub_appid`
>
> 微信支付会校验下单与调起支付所使用的 `appid` 的一致性。
## 请求示例
```javascript
wx.requestPayment(
{
"timeStamp": "1414561699",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx201410272009395522657a690389285100",
"signType": "RSA",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==",
"success":function(res){},
"fail":function(res){},
"complete":function(res){}
}
)
```
## 字段说明
| 字段 | 必填 | 说明 |
|------|------|------|
| `timeStamp` | 是 | 时间戳秒级10位数字 |
| `nonceStr` | 是 | 随机字符串不长于32位 |
| `package` | 是 | 预支付交易会话标识,格式:`prepay_id=***` |
| `signType` | 是 | 固定为 `RSA` |
| `paySign` | 是 | 使用 `appid``timeStamp``nonceStr``package` 计算的签名值 |
## 回调结果
| 回调类型 | errMsg | 说明 |
|---------|--------|------|
| success | `requestPayment:ok` | 调用支付成功 |
| fail | `requestPayment:fail cancel` | 用户取消支付 |
| fail | `requestPayment:fail (detail message)` | 调用支付失败detail message 为详细原因 |
> ⚠️ 前端回调不绝对可靠,订单状态需以后端查询订单和支付成功回调通知为准。
> 若为交易类小程序,需满足《交易类小程序运营规范》并接入订单发货管理功能,否则可能被限制支付权限。

View File

@@ -0,0 +1,248 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信支付商户订单号查询订单
*/
public class PartnerQueryByOutTradeNo {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/pay/partner/transactions/out-trade-no/{out_trade_no}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerQueryByOutTradeNo client = new PartnerQueryByOutTradeNo(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
PartnerQueryByOutTradeNoRequest request = new PartnerQueryByOutTradeNoRequest();
request.outTradeNo = "1217752501201407033233368018";
request.spMchid = "1230000109";
request.subMchid = "1900000109";
try {
PartnerAPIv3PartnerQueryResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public PartnerAPIv3PartnerQueryResponse run(PartnerQueryByOutTradeNoRequest request) {
String uri = PATH;
uri = uri.replace("{out_trade_no}", WXPayUtility.urlEncode(request.outTradeNo));
Map<String, Object> args = new HashMap<>();
args.put("sp_mchid", request.spMchid);
args.put("sub_mchid", request.subMchid);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, PartnerAPIv3PartnerQueryResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerQueryByOutTradeNo(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerQueryByOutTradeNoRequest {
@SerializedName("sp_mchid")
@Expose(serialize = false)
public String spMchid;
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("out_trade_no")
@Expose(serialize = false)
public String outTradeNo;
}
public static class PartnerAPIv3PartnerQueryResponse {
@SerializedName("sp_appid")
public String spAppid;
@SerializedName("sp_mchid")
public String spMchid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("trade_type")
public String tradeType;
@SerializedName("trade_state")
public String tradeState;
@SerializedName("trade_state_desc")
public String tradeStateDesc;
@SerializedName("bank_type")
public String bankType;
@SerializedName("attach")
public String attach;
@SerializedName("success_time")
public String successTime;
@SerializedName("payer")
public PartnerCommRespPayerInfo payer;
@SerializedName("amount")
public CommRespAmountInfo amount;
@SerializedName("scene_info")
public CommRespSceneInfo sceneInfo;
@SerializedName("promotion_detail")
public List<PromotionDetail> promotionDetail;
}
public static class PartnerCommRespPayerInfo {
@SerializedName("sp_openid")
public String spOpenid;
@SerializedName("sub_openid")
public String subOpenid;
}
public static class CommRespAmountInfo {
@SerializedName("total")
public Long total;
@SerializedName("payer_total")
public Long payerTotal;
@SerializedName("currency")
public String currency;
@SerializedName("payer_currency")
public String payerCurrency;
}
public static class CommRespSceneInfo {
@SerializedName("device_id")
public String deviceId;
}
public static class PromotionDetail {
@SerializedName("coupon_id")
public String couponId;
@SerializedName("name")
public String name;
@SerializedName("scope")
public String scope;
@SerializedName("type")
public String type;
@SerializedName("amount")
public Long amount;
@SerializedName("stock_id")
public String stockId;
@SerializedName("wechatpay_contribute")
public Long wechatpayContribute;
@SerializedName("merchant_contribute")
public Long merchantContribute;
@SerializedName("other_contribute")
public Long otherContribute;
@SerializedName("currency")
public String currency;
@SerializedName("goods_detail")
public List<GoodsDetailInPromotion> goodsDetail;
}
public static class GoodsDetailInPromotion {
@SerializedName("goods_id")
public String goodsId;
@SerializedName("quantity")
public Long quantity;
@SerializedName("unit_price")
public Long unitPrice;
@SerializedName("discount_amount")
public Long discountAmount;
@SerializedName("goods_remark")
public String goodsRemark;
}
}

View File

@@ -0,0 +1,248 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信支付订单号查询订单
*/
public class PartnerQueryByWxTradeNo {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/pay/partner/transactions/id/{transaction_id}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerQueryByWxTradeNo client = new PartnerQueryByWxTradeNo(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
PartnerQueryByWxTradeNoRequest request = new PartnerQueryByWxTradeNoRequest();
request.transactionId = "1217752501201407033233368018";
request.spMchid = "1230000109";
request.subMchid = "1900000109";
try {
PartnerAPIv3PartnerQueryResponse response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public PartnerAPIv3PartnerQueryResponse run(PartnerQueryByWxTradeNoRequest request) {
String uri = PATH;
uri = uri.replace("{transaction_id}", WXPayUtility.urlEncode(request.transactionId));
Map<String, Object> args = new HashMap<>();
args.put("sp_mchid", request.spMchid);
args.put("sub_mchid", request.subMchid);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, PartnerAPIv3PartnerQueryResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerQueryByWxTradeNo(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerQueryByWxTradeNoRequest {
@SerializedName("sp_mchid")
@Expose(serialize = false)
public String spMchid;
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
@SerializedName("transaction_id")
@Expose(serialize = false)
public String transactionId;
}
public static class PartnerAPIv3PartnerQueryResponse {
@SerializedName("sp_appid")
public String spAppid;
@SerializedName("sp_mchid")
public String spMchid;
@SerializedName("sub_appid")
public String subAppid;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("trade_type")
public String tradeType;
@SerializedName("trade_state")
public String tradeState;
@SerializedName("trade_state_desc")
public String tradeStateDesc;
@SerializedName("bank_type")
public String bankType;
@SerializedName("attach")
public String attach;
@SerializedName("success_time")
public String successTime;
@SerializedName("payer")
public PartnerCommRespPayerInfo payer;
@SerializedName("amount")
public CommRespAmountInfo amount;
@SerializedName("scene_info")
public CommRespSceneInfo sceneInfo;
@SerializedName("promotion_detail")
public List<PromotionDetail> promotionDetail;
}
public static class PartnerCommRespPayerInfo {
@SerializedName("sp_openid")
public String spOpenid;
@SerializedName("sub_openid")
public String subOpenid;
}
public static class CommRespAmountInfo {
@SerializedName("total")
public Long total;
@SerializedName("payer_total")
public Long payerTotal;
@SerializedName("currency")
public String currency;
@SerializedName("payer_currency")
public String payerCurrency;
}
public static class CommRespSceneInfo {
@SerializedName("device_id")
public String deviceId;
}
public static class PromotionDetail {
@SerializedName("coupon_id")
public String couponId;
@SerializedName("name")
public String name;
@SerializedName("scope")
public String scope;
@SerializedName("type")
public String type;
@SerializedName("amount")
public Long amount;
@SerializedName("stock_id")
public String stockId;
@SerializedName("wechatpay_contribute")
public Long wechatpayContribute;
@SerializedName("merchant_contribute")
public Long merchantContribute;
@SerializedName("other_contribute")
public Long otherContribute;
@SerializedName("currency")
public String currency;
@SerializedName("goods_detail")
public List<GoodsDetailInPromotion> goodsDetail;
}
public static class GoodsDetailInPromotion {
@SerializedName("goods_id")
public String goodsId;
@SerializedName("quantity")
public Long quantity;
@SerializedName("unit_price")
public Long unitPrice;
@SerializedName("discount_amount")
public Long discountAmount;
@SerializedName("goods_remark")
public String goodsRemark;
}
}

View File

@@ -0,0 +1,110 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 关闭订单
*/
public class PartnerCloseOrder {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
PartnerCloseOrder client = new PartnerCloseOrder(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
PartnerCloseOrderRequest request = new PartnerCloseOrderRequest();
request.outTradeNo = "1217752501201407033233368018";
request.spMchid = "1230000109";
request.subMchid = "1900000109";
try {
client.run(request);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public void run(PartnerCloseOrderRequest request) {
String uri = PATH;
uri = uri.replace("{out_trade_no}", WXPayUtility.urlEncode(request.outTradeNo));
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
return;
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public PartnerCloseOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class PartnerCloseOrderRequest {
@SerializedName("sp_mchid")
public String spMchid;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("out_trade_no")
@Expose(serialize = false)
public String outTradeNo;
}
}

View File

@@ -0,0 +1,331 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 发起异常退款
*/
public class CreateAbnormalRefund {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/refund/domestic/refunds/{refund_id}/apply-abnormal-refund";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
CreateAbnormalRefund client = new CreateAbnormalRefund(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
CreateAbnormalRefundRequest request = new CreateAbnormalRefundRequest();
request.refundId = "50000000382019052709732678859";
request.subMchid = "1900000109";
request.outRefundNo = "1217752501201407033233368018";
request.type = AbnormalReceiveType.MERCHANT_BANK_CARD;
request.bankType = "ICBC_DEBIT";
request.bankAccount = client.encrypt("bank_account");
request.realName = client.encrypt("real_name");
try {
Refund response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public Refund run(CreateAbnormalRefundRequest request) {
String uri = PATH;
uri = uri.replace("{refund_id}", WXPayUtility.urlEncode(request.refundId));
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, Refund.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public CreateAbnormalRefund(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class CreateAbnormalRefundRequest {
@SerializedName("refund_id")
@Expose(serialize = false)
public String refundId;
@SerializedName("sub_mchid")
public String subMchid;
@SerializedName("out_refund_no")
public String outRefundNo;
@SerializedName("type")
public AbnormalReceiveType type;
@SerializedName("bank_type")
public String bankType;
@SerializedName("bank_account")
public String bankAccount;
@SerializedName("real_name")
public String realName;
}
public static class Refund {
@SerializedName("refund_id")
public String refundId;
@SerializedName("out_refund_no")
public String outRefundNo;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("channel")
public Channel channel;
@SerializedName("user_received_account")
public String userReceivedAccount;
@SerializedName("success_time")
public String successTime;
@SerializedName("create_time")
public String createTime;
@SerializedName("status")
public Status status;
@SerializedName("funds_account")
public FundsAccount fundsAccount;
@SerializedName("amount")
public Amount amount;
@SerializedName("promotion_detail")
public List<Promotion> promotionDetail;
@SerializedName("refund_account")
public RefundAccount refundAccount;
}
public enum AbnormalReceiveType {
@SerializedName("USER_BANK_CARD")
USER_BANK_CARD,
@SerializedName("MERCHANT_BANK_CARD")
MERCHANT_BANK_CARD
}
public enum Channel {
@SerializedName("ORIGINAL")
ORIGINAL,
@SerializedName("BALANCE")
BALANCE,
@SerializedName("OTHER_BALANCE")
OTHER_BALANCE,
@SerializedName("OTHER_BANKCARD")
OTHER_BANKCARD
}
public enum Status {
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("CLOSED")
CLOSED,
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("ABNORMAL")
ABNORMAL
}
public enum FundsAccount {
@SerializedName("UNSETTLED")
UNSETTLED,
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE,
@SerializedName("OPERATION")
OPERATION,
@SerializedName("BASIC")
BASIC,
@SerializedName("ECNY_BASIC")
ECNY_BASIC
}
public static class Amount {
@SerializedName("total")
public Long total;
@SerializedName("refund")
public Long refund;
@SerializedName("from")
public List<FundsFromItem> from;
@SerializedName("payer_total")
public Long payerTotal;
@SerializedName("payer_refund")
public Long payerRefund;
@SerializedName("settlement_refund")
public Long settlementRefund;
@SerializedName("settlement_total")
public Long settlementTotal;
@SerializedName("discount_refund")
public Long discountRefund;
@SerializedName("currency")
public String currency;
@SerializedName("refund_fee")
public Long refundFee;
@SerializedName("advance")
public Long advance;
}
public static class Promotion {
@SerializedName("promotion_id")
public String promotionId;
@SerializedName("scope")
public PromotionScope scope;
@SerializedName("type")
public PromotionType type;
@SerializedName("amount")
public Long amount;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public enum RefundAccount {
@SerializedName("REFUND_SOURCE_PARTNER_ADVANCE")
REFUND_SOURCE_PARTNER_ADVANCE,
@SerializedName("REFUND_SOURCE_SUB_MERCHANT")
REFUND_SOURCE_SUB_MERCHANT,
@SerializedName("REFUND_SOURCE_SUB_MERCHANT_ADVANCE")
REFUND_SOURCE_SUB_MERCHANT_ADVANCE
}
public static class FundsFromItem {
@SerializedName("account")
public Account account;
@SerializedName("amount")
public Long amount;
}
public enum PromotionScope {
@SerializedName("GLOBAL")
GLOBAL,
@SerializedName("SINGLE")
SINGLE
}
public enum PromotionType {
@SerializedName("COUPON")
COUPON,
@SerializedName("DISCOUNT")
DISCOUNT
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id")
public String merchantGoodsId;
@SerializedName("wechatpay_goods_id")
public String wechatpayGoodsId;
@SerializedName("goods_name")
public String goodsName;
@SerializedName("unit_price")
public Long unitPrice;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("refund_quantity")
public Long refundQuantity;
}
public enum Account {
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE
}
}

View File

@@ -0,0 +1,351 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/merchant/4014931831
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 退款申请
*/
public class Create {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/refund/domestic/refunds";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/merchant/4013070756
Create client = new Create(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
CreateRequest request = new CreateRequest();
request.transactionId = "1217752501201407033233368018";
request.outTradeNo = "1217752501201407033233368018";
request.outRefundNo = "1217752501201407033233368018";
request.reason = "商品已售完";
request.notifyUrl = "https://weixin.qq.com";
request.fundsAccount = ReqFundsAccount.AVAILABLE;
request.amount = new AmountReq();
request.amount.refund = 888L;
request.amount.from = new ArrayList<>();
{
FundsFromItem fromItem = new FundsFromItem();
fromItem.account = Account.AVAILABLE;
fromItem.amount = 444L;
request.amount.from.add(fromItem);
};
request.amount.total = 888L;
request.amount.currency = "CNY";
request.goodsDetail = new ArrayList<>();
{
GoodsDetail goodsDetailItem = new GoodsDetail();
goodsDetailItem.merchantGoodsId = "1217752501201407033233368018";
goodsDetailItem.wechatpayGoodsId = "1001";
goodsDetailItem.goodsName = "iPhone6s 16G";
goodsDetailItem.unitPrice = 528800L;
goodsDetailItem.refundAmount = 528800L;
goodsDetailItem.refundQuantity = 1L;
request.goodsDetail.add(goodsDetailItem);
};
try {
Refund response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public Refund run(CreateRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, Refund.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public Create(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class CreateRequest {
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("out_refund_no")
public String outRefundNo;
@SerializedName("reason")
public String reason;
@SerializedName("notify_url")
public String notifyUrl;
@SerializedName("funds_account")
public ReqFundsAccount fundsAccount;
@SerializedName("amount")
public AmountReq amount;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public static class Refund {
@SerializedName("refund_id")
public String refundId;
@SerializedName("out_refund_no")
public String outRefundNo;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("channel")
public Channel channel;
@SerializedName("user_received_account")
public String userReceivedAccount;
@SerializedName("success_time")
public String successTime;
@SerializedName("create_time")
public String createTime;
@SerializedName("status")
public Status status;
@SerializedName("funds_account")
public FundsAccount fundsAccount;
@SerializedName("amount")
public Amount amount;
@SerializedName("promotion_detail")
public List<Promotion> promotionDetail;
}
public enum ReqFundsAccount {
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNSETTLED")
UNSETTLED
}
public static class AmountReq {
@SerializedName("refund")
public Long refund;
@SerializedName("from")
public List<FundsFromItem> from;
@SerializedName("total")
public Long total;
@SerializedName("currency")
public String currency;
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id")
public String merchantGoodsId;
@SerializedName("wechatpay_goods_id")
public String wechatpayGoodsId;
@SerializedName("goods_name")
public String goodsName;
@SerializedName("unit_price")
public Long unitPrice;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("refund_quantity")
public Long refundQuantity;
}
public enum Channel {
@SerializedName("ORIGINAL")
ORIGINAL,
@SerializedName("BALANCE")
BALANCE,
@SerializedName("OTHER_BALANCE")
OTHER_BALANCE,
@SerializedName("OTHER_BANKCARD")
OTHER_BANKCARD
}
public enum Status {
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("CLOSED")
CLOSED,
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("ABNORMAL")
ABNORMAL
}
public enum FundsAccount {
@SerializedName("UNSETTLED")
UNSETTLED,
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE,
@SerializedName("OPERATION")
OPERATION,
@SerializedName("BASIC")
BASIC,
@SerializedName("ECNY_BASIC")
ECNY_BASIC
}
public static class Amount {
@SerializedName("total")
public Long total;
@SerializedName("refund")
public Long refund;
@SerializedName("from")
public List<FundsFromItem> from;
@SerializedName("payer_total")
public Long payerTotal;
@SerializedName("payer_refund")
public Long payerRefund;
@SerializedName("settlement_refund")
public Long settlementRefund;
@SerializedName("settlement_total")
public Long settlementTotal;
@SerializedName("discount_refund")
public Long discountRefund;
@SerializedName("currency")
public String currency;
@SerializedName("refund_fee")
public Long refundFee;
}
public static class Promotion {
@SerializedName("promotion_id")
public String promotionId;
@SerializedName("scope")
public PromotionScope scope;
@SerializedName("type")
public PromotionType type;
@SerializedName("amount")
public Long amount;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public static class FundsFromItem {
@SerializedName("account")
public Account account;
@SerializedName("amount")
public Long amount;
}
public enum PromotionScope {
@SerializedName("GLOBAL")
GLOBAL,
@SerializedName("SINGLE")
SINGLE
}
public enum PromotionType {
@SerializedName("CASH")
CASH,
@SerializedName("NOCASH")
NOCASH
}
public enum Account {
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE
}
}

View File

@@ -0,0 +1,304 @@
package com.java.demo;
import com.java.utils.WXPayUtility; // 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/partner/4014985777
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 查询单笔退款(通过商户退款单号)
*/
public class QueryByOutRefundNo {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "GET";
private static String PATH = "/v3/refund/domestic/refunds/{out_refund_no}";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/partner/4013080340
QueryByOutRefundNo client = new QueryByOutRefundNo(
"19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340
"1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924
"/path/to/apiclient_key.pem", // 商户API证书私钥文件路径本地文件路径
"PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589
"/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径
);
QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
request.outRefundNo = "1217752501201407033233368018";
request.subMchid = "1900000109";
try {
Refund response = client.run(request);
// TODO: 请求成功,继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败,根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public Refund run(QueryByOutRefundNoRequest request) {
String uri = PATH;
uri = uri.replace("{out_refund_no}", WXPayUtility.urlEncode(request.outRefundNo));
Map<String, Object> args = new HashMap<>();
args.put("sub_mchid", request.subMchid);
String queryString = WXPayUtility.urlEncode(args);
if (!queryString.isEmpty()) {
uri = uri + "?" + queryString;
}
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null));
reqBuilder.method(METHOD, null);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, Refund.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public QueryByOutRefundNo(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public static class QueryByOutRefundNoRequest {
@SerializedName("out_refund_no")
@Expose(serialize = false)
public String outRefundNo;
@SerializedName("sub_mchid")
@Expose(serialize = false)
public String subMchid;
}
public static class Refund {
@SerializedName("refund_id")
public String refundId;
@SerializedName("out_refund_no")
public String outRefundNo;
@SerializedName("transaction_id")
public String transactionId;
@SerializedName("out_trade_no")
public String outTradeNo;
@SerializedName("channel")
public Channel channel;
@SerializedName("user_received_account")
public String userReceivedAccount;
@SerializedName("success_time")
public String successTime;
@SerializedName("create_time")
public String createTime;
@SerializedName("status")
public Status status;
@SerializedName("funds_account")
public FundsAccount fundsAccount;
@SerializedName("amount")
public Amount amount;
@SerializedName("promotion_detail")
public List<Promotion> promotionDetail;
@SerializedName("refund_account")
public RefundAccount refundAccount;
}
public enum Channel {
@SerializedName("ORIGINAL")
ORIGINAL,
@SerializedName("BALANCE")
BALANCE,
@SerializedName("OTHER_BALANCE")
OTHER_BALANCE,
@SerializedName("OTHER_BANKCARD")
OTHER_BANKCARD
}
public enum Status {
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("CLOSED")
CLOSED,
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("ABNORMAL")
ABNORMAL
}
public enum FundsAccount {
@SerializedName("UNSETTLED")
UNSETTLED,
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE,
@SerializedName("OPERATION")
OPERATION,
@SerializedName("BASIC")
BASIC,
@SerializedName("ECNY_BASIC")
ECNY_BASIC
}
public static class Amount {
@SerializedName("total")
public Long total;
@SerializedName("refund")
public Long refund;
@SerializedName("from")
public List<FundsFromItem> from;
@SerializedName("payer_total")
public Long payerTotal;
@SerializedName("payer_refund")
public Long payerRefund;
@SerializedName("settlement_refund")
public Long settlementRefund;
@SerializedName("settlement_total")
public Long settlementTotal;
@SerializedName("discount_refund")
public Long discountRefund;
@SerializedName("currency")
public String currency;
@SerializedName("refund_fee")
public Long refundFee;
@SerializedName("advance")
public Long advance;
}
public static class Promotion {
@SerializedName("promotion_id")
public String promotionId;
@SerializedName("scope")
public PromotionScope scope;
@SerializedName("type")
public PromotionType type;
@SerializedName("amount")
public Long amount;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("goods_detail")
public List<GoodsDetail> goodsDetail;
}
public enum RefundAccount {
@SerializedName("REFUND_SOURCE_PARTNER_ADVANCE")
REFUND_SOURCE_PARTNER_ADVANCE,
@SerializedName("REFUND_SOURCE_SUB_MERCHANT")
REFUND_SOURCE_SUB_MERCHANT,
@SerializedName("REFUND_SOURCE_SUB_MERCHANT_ADVANCE")
REFUND_SOURCE_SUB_MERCHANT_ADVANCE
}
public static class FundsFromItem {
@SerializedName("account")
public Account account;
@SerializedName("amount")
public Long amount;
}
public enum PromotionScope {
@SerializedName("GLOBAL")
GLOBAL,
@SerializedName("SINGLE")
SINGLE
}
public enum PromotionType {
@SerializedName("COUPON")
COUPON,
@SerializedName("DISCOUNT")
DISCOUNT
}
public static class GoodsDetail {
@SerializedName("merchant_goods_id")
public String merchantGoodsId;
@SerializedName("wechatpay_goods_id")
public String wechatpayGoodsId;
@SerializedName("goods_name")
public String goodsName;
@SerializedName("unit_price")
public Long unitPrice;
@SerializedName("refund_amount")
public Long refundAmount;
@SerializedName("refund_quantity")
public Long refundQuantity;
}
public enum Account {
@SerializedName("AVAILABLE")
AVAILABLE,
@SerializedName("UNAVAILABLE")
UNAVAILABLE
}
}

View File

@@ -0,0 +1,77 @@
# 支付成功回调通知(服务商模式)
用户使用普通支付APP/H5/JSAPI/Native/小程序)成功支付订单后,微信支付会通过 POST 方式向服务商下单时传入的 `notify_url` 发送回调通知。
## 回调通知报文
```json
{
"id": "EV-2018022511223320873",
"create_time": "2015-05-20T13:29:35+08:00",
"resource_type": "encrypt-resource",
"event_type": "TRANSACTION.SUCCESS",
"summary": "支付成功",
"resource": {
"original_type": "transaction",
"algorithm": "AEAD_AES_256_GCM",
"ciphertext": "",
"associated_data": "",
"nonce": ""
}
}
```
## 处理步骤
1. **验签**:使用请求头中的 `Wechatpay-Timestamp``Wechatpay-Nonce` 和请求主体构建验签串,用 `Wechatpay-Serial` 对应的微信支付公钥/平台证书验签
2. **应答**:验签通过返回 HTTP 200/204无报文体验签失败返回 4XX/5XX + `{"code":"FAIL","message":"失败原因"}`
3. **解密**:使用 APIv3 密钥 + `resource.nonce` + `resource.associated_data``resource.ciphertext` 进行 AEAD_AES_256_GCM 解密
> ⚠️ 必须先应答再处理业务逻辑推荐异步处理5 秒内未应答视为超时。
> 重试机制15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h最多 15 次。
> 收到重复通知时需做好幂等处理并持续应答 200。
> 若服务商对回调 IP 有防火墙限制,需对微信回调 IP 段开白名单。
## 解密后的业务字段(与商户模式的区别)
解密后返回的 JSON 中,服务商模式特有的字段:
| 字段 | 说明 |
|------|------|
| `sp_mchid` | 服务商商户号 |
| `sub_mchid` | 子商户号 |
| `sp_appid` | 服务商 APPID |
| `sub_appid` | 子商户 APPID下单未传则不返回 |
| `payer.sp_openid` | 用户在 sp_appid 下的唯一标识 |
| `payer.sub_openid` | 用户在 sub_appid 下的唯一标识(下单未传 sub_appid 则不返回) |
其余字段(`out_trade_no``transaction_id``trade_type``trade_state``amount``promotion_detail` 等)与商户模式结构一致。
## 解密后示例
```json
{
"sp_appid": "wx8888888888888888",
"sp_mchid": "1230000109",
"sub_appid": "wxd678efh567hg6999",
"sub_mchid": "1900000109",
"out_trade_no": "1217752501201407033233368018",
"transaction_id": "1217752501201407033233368018",
"trade_type": "JSAPI",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"bank_type": "CMC",
"attach": "自定义数据",
"success_time": "2018-06-08T10:34:56+08:00",
"payer": {
"sp_openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
"sub_openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
},
"amount": {
"total": 100,
"payer_total": 100,
"currency": "CNY",
"payer_currency": "CNY"
}
}
```

View File

@@ -0,0 +1,106 @@
# 服务商基础支付示例代码接口索引
> 根据用户确认的开发语言加载对应语言目录下的文件。Java 和 Go 目录结构一致。
> 服务商模式 API 路径前缀为 `/v3/pay/partner/transactions`,与商户模式(`/v3/pay/transactions`)不同。
## 下单(需确认支付方式)
| 支付方式 | 接口 | Java | Go |
|---------|------|------|-----|
| JSAPI/小程序 | POST /v3/pay/partner/transactions/jsapi | `Java/1-JSAPI支付/PartnerJsapiPrepay.java` | `Go/1-JSAPI支付/PartnerJsapiPrepay.go` |
| APP | POST /v3/pay/partner/transactions/app | `Java/2-APP支付/PartnerAppPrepay.java` | `Go/2-APP支付/PartnerAppPrepay.go` |
| H5 | POST /v3/pay/partner/transactions/h5 | `Java/3-H5支付/PartnerH5Prepay.java` | `Go/3-H5支付/PartnerH5Prepay.go` |
| Native | POST /v3/pay/partner/transactions/native | `Java/4-Native支付/PartnerNativePrepay.java` | `Go/4-Native支付/PartnerNativePrepay.go` |
## 通用接口(无需确认支付方式,各支付方式完全相同)
| 业务 | 接口 | Java | Go |
|------|------|------|-----|
| 微信订单号查单 | GET /v3/pay/partner/transactions/id/{transaction_id} | `Java/6-订单查询/PartnerQueryByWxTradeNo.java` | `Go/6-订单查询/PartnerQueryByWxTradeNo.go` |
| 商户订单号查单 | GET /v3/pay/partner/transactions/out-trade-no/{out_trade_no} | `Java/6-订单查询/PartnerQueryByOutTradeNo.java` | `Go/6-订单查询/PartnerQueryByOutTradeNo.go` |
| 关闭订单 | POST /v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close | `Java/7-关闭订单/PartnerCloseOrder.java` | `Go/7-关闭订单/PartnerCloseOrder.go` |
| 退款申请 | POST /v3/refund/domestic/refunds | `Java/8-订单退款/CreateRefund.java` | `Go/8-订单退款/CreateRefund.go` |
| 查询退款 | GET /v3/refund/domestic/refunds/{out_refund_no} | `Java/8-订单退款/QueryByOutRefundNo.java` | `Go/8-订单退款/QueryByOutRefundNo.go` |
| 异常退款 | POST /v3/refund/domestic/refunds/{refund_id}/apply-abnormal-refund | `Java/8-订单退款/CreateAbnormalRefund.java` | `Go/8-订单退款/CreateAbnormalRefund.go` |
| 支付回调通知 | 回调报文格式与处理要求 | `Java/9-支付回调通知/支付成功回调通知说明.md` | — |
| 退款回调通知 | 回调报文格式与处理要求 | `Java/10-退款结果回调通知/退款结果回调通知说明.md` | — |
| 申请交易账单 | GET /v3/bill/tradebill | `Java/11-申请交易账单/GetTradeBill.java` | `Go/11-申请交易账单/GetTradeBill.go` |
| 申请资金账单 | GET /v3/bill/fundflowbill | `Java/12-申请资金账单/GetFundFlowBill.java` | `Go/12-申请资金账单/GetFundFlowBill.go` |
| 下载账单 | GET download_url | `Java/13-下载账单/DownloadBill.java` | — |
> 退款接口和账单接口商户模式和服务商模式完全相同,无 partner 前缀。交易账单可通过 `sub_mchid` 指定单个子商户,不传则查所有子商户。资金账单反映服务商自身账户的资金变动,建议次日 10 点后获取。
## 调起支付(需确认支付方式,前端集成参考)
| 支付方式 | 调起方式 | 参考文件 |
|---------|---------|---------|
| JSAPI | WeixinJSBridge | `Java/1-JSAPI支付/JsapiInvoke.md` |
| APP | OpenSDK sendReq | `Java/2-APP支付/AppInvoke.md` |
| H5 | 跳转h5_url | `Java/3-H5支付/H5Invoke.md` |
| Native | code_url转二维码 | `Java/4-Native支付/NativeInvoke.md` |
| 小程序 | wx.requestPayment | `Java/5-小程序支付/MiniProgramInvoke.md` |
## 16. 点金计划管理
| 接口 | Java | Go |
|------|------|------|
| 点金计划管理(开通/关闭) | `Java/16-点金计划/ChangeGoldPlanStatus.java` | `Go/16-点金计划/ChangeGoldPlanStatus.go` |
| 商家小票管理(开通/关闭) | `Java/16-点金计划/ChangeCustomPageStatus.java` | `Go/16-点金计划/ChangeCustomPageStatus.go` |
| 同业过滤标签管理 | `Java/16-点金计划/SetAdvertisingIndustryFilter.java` | `Go/16-点金计划/SetAdvertisingIndustryFilter.go` |
| 开通广告展示 | `Java/16-点金计划/OpenAdvertisingShow.java` | `Go/16-点金计划/OpenAdvertisingShow.go` |
| 关闭广告展示 | `Java/16-点金计划/CloseAdvertisingShow.java` | `Go/16-点金计划/CloseAdvertisingShow.go` |
> 点金计划是服务商 JSAPI 支付必接能力,详见 `接入指南/点金计划.md`。
## 17. 分账
| 接口 | Java | Go |
|------|------|------|
| 请求分账 | `Java/17-分账/CreateOrder.java` | `Go/17-分账/CreateOrder.go` |
| 查询分账结果 | `Java/17-分账/QueryOrder.java` | `Go/17-分账/QueryOrder.go` |
| 请求分账回退 | `Java/17-分账/CreateReturnOrder.java` | `Go/17-分账/CreateReturnOrder.go` |
| 查询分账回退结果 | `Java/17-分账/QueryReturnOrder.java` | `Go/17-分账/QueryReturnOrder.go` |
| 解冻剩余资金 | `Java/17-分账/UnfreezeOrder.java` | `Go/17-分账/UnfreezeOrder.go` |
| 查询剩余待分金额 | `Java/17-分账/QueryOrderAmount.java` | `Go/17-分账/QueryOrderAmount.go` |
| 查询最大分账比例 | `Java/17-分账/QueryMerchantRatio.java` | `Go/17-分账/QueryMerchantRatio.go` |
| 添加分账接收方 | `Java/17-分账/AddReceiver.java` | `Go/17-分账/AddReceiver.go` |
| 删除分账接收方 | `Java/17-分账/DeleteReceiver.java` | `Go/17-分账/DeleteReceiver.go` |
| 申请分账账单 | `Java/17-分账/SplitBill.java` | `Go/17-分账/SplitBill.go` |
> 分账规则、API 列表见 `3-商户与服务商通用/接入指南/分账接入指南.md`。与商户版的差异:请求体增加 `sub_mchid`、`sub_appid`,接收方类型增加 `PERSONAL_SUB_OPENID`,服务商独有「查询最大分账比例」接口。
## 19. 特约商户进件
| 接口 | Java | Go |
|------|------|------|
| 提交申请单 | `Java/19-特约商户进件/Submit.java` | `Go/19-特约商户进件/Submit.go` |
| 查询申请单状态(业务申请编号) | `Java/19-特约商户进件/QueryState.java` | `Go/19-特约商户进件/QueryState.go` |
| 查询申请单状态申请单ID | `Java/19-特约商户进件/QueryStateById.java` | `Go/19-特约商户进件/QueryStateById.go` |
| 修改结算账户 | `Java/19-特约商户进件/ModifySettlement.java` | `Go/19-特约商户进件/ModifySettlement.go` |
| 查询结算账户 | `Java/19-特约商户进件/GetSettlement.java` | `Go/19-特约商户进件/GetSettlement.go` |
| 查询结算账户修改申请状态 | `Java/19-特约商户进件/GetApplication.java` | `Go/19-特约商户进件/GetApplication.go` |
| 图片上传 | `Java/19-特约商户进件/UploadMedia.java` | — |
| 视频上传 | `Java/19-特约商户进件/UploadVideo.java` | — |
> 特约商户进件为服务商专属能力敏感字段须使用微信支付公钥加密HTTP 头须上送 `Wechatpay-Serial`。进件流程和参数说明见 `接入指南/特约商户进件.md`。
## 20. 商户开户意愿确认
| 接口 | Java | Go |
|------|------|------|
| 提交申请单 | `Java/20-商户开户意愿确认/SubmitApplyment.java` | `Go/20-商户开户意愿确认/SubmitApplyment.go` |
| 查询申请单审核结果 | `Java/20-商户开户意愿确认/GetAuditResult.java` | `Go/20-商户开户意愿确认/GetAuditResult.go` |
| 撤销申请单 | `Java/20-商户开户意愿确认/CancelApplyment.java` | `Go/20-商户开户意愿确认/CancelApplyment.go` |
| 获取商户开户意愿确认状态 | `Java/20-商户开户意愿确认/GetAuthorizeState.java` | `Go/20-商户开户意愿确认/GetAuthorizeState.go` |
| 图片上传 | `Java/20-商户开户意愿确认/UploadMedia.java` | — |
> 商户开户意愿确认为服务商/渠道商专属能力API 前缀为 `/v3/apply4subject/`敏感字段须使用微信支付公钥加密HTTP 头须上送 `Wechatpay-Serial`。流程和参数说明见 `接入指南/商户开户意愿确认.md`。
## SDK工具类所有接口的公共依赖
> 服务商模式与商户模式共用同一套 SDK 工具类提供签名、验签、加解密、HTTP请求等基础能力。
| 语言 | 文件 |
|------|------|
| Java | 参考商户模式 `1-商户/示例代码/Java/14-SDK工具类/WXPayUtility.java` + `WXPayClient.java` |
| Go | 参考商户模式 `1-商户/示例代码/Go/14-SDK工具类/wxpay_utility.go` + `wxpay_client.go` |