Add WeChat Pay local skills
This commit is contained in:
@@ -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` 字段填写有误,需选择正确的门店所在省市区行政区划代码 |
|
||||
@@ -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_id(2h) | prepay_id(2h) | h5_url(**5min**) | code_url(2h) | prepay_id(2h) |
|
||||
| **调起方式** | 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)
|
||||
```
|
||||
@@ -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 支付场景**不支持** |
|
||||
| 从业机构号可以开通点金计划吗? | **不支持**,需要从业机构下的渠道商去开通配置 |
|
||||
@@ -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 修改 |
|
||||
| 单个人/主体进件次数有限制吗? | 有限制,系统动态评估,具体以实际返回为准 |
|
||||
| 商户已存在怎么办? | 根据提示先注销已有商户号,再重新进件 |
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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();
|
||||
}
|
||||
```
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 sendReq:request];
|
||||
```
|
||||
|
||||
## 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)
|
||||
```
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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` 页面)。建议在回跳页面中增设"确认支付情况"按钮,用户点击后触发查单操作,确保及时了解订单状态。
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Native 调起支付
|
||||
|
||||
> 服务商模式与商户模式的 Native 调起支付完全一致。
|
||||
|
||||
## 调起步骤
|
||||
|
||||
1. 通过 Native 下单接口获取 `code_url`
|
||||
2. 将 `code_url` 转换为二维码图片,展示给用户
|
||||
3. 用户打开微信"扫一扫",扫描二维码完成支付
|
||||
|
||||
> ⚠️ 不支持通过相册识别或长按识别二维码完成支付,仅支持扫一扫。
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 为详细原因 |
|
||||
|
||||
> ⚠️ 前端回调不绝对可靠,订单状态需以后端查询订单和支付成功回调通知为准。
|
||||
> 若为交易类小程序,需满足《交易类小程序运营规范》并接入订单发货管理功能,否则可能被限制支付权限。
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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` |
|
||||
Reference in New Issue
Block a user