129 Commits

Author SHA1 Message Date
felord.cn
d95d9de0f1 Merge pull request #124 from dromara/1.0.20
1.0.20
2024-04-29 13:41:35 +08:00
xiafang
5b8850b980 enhance: 1.0.20 2024-04-29 13:41:07 +08:00
xiafang
85621edace Merge branch 'release' into 1.0.20
# Conflicts:
#	payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/ecommerce/EcommerceContactInfo.java
2024-04-29 13:38:43 +08:00
xiafang
56995088d1 enhance: 发放代金券中制券商户号用户可自定义
Closes #122
2024-04-29 13:30:39 +08:00
xiafang
6e2b6decf4 enhance: 发起商家转账增加回调通知
Closes #123
2024-04-29 12:50:12 +08:00
xiafang
d068734422 enhance: 优化逻辑 2024-01-15 15:53:52 +08:00
xiafang
57e794280f fix: 微信支付分停车GET请求车牌号省份汉字encode问题
Closes  #113
2023-11-28 14:08:34 +08:00
xiafang
56bf43f04f #109 2023-11-28 13:50:53 +08:00
felord.cn
87257fc8b1 Merge pull request #109 from lgxisbb/20230703_media_api
20230703 ecommerce api
2023-11-28 13:37:23 +08:00
felord.cn
616ea0cede Merge pull request #110 from dromara/dependabot/maven/org.bouncycastle-bcprov-jdk15to18-1.74
build(deps): bump bcprov-jdk15to18 from 1.69 to 1.74
2023-11-28 13:36:57 +08:00
xiafang
f4615b02b3 修复时间序列化问题 2023-11-28 13:30:26 +08:00
dependabot[bot]
4e27958ace build(deps): bump bcprov-jdk15to18 from 1.69 to 1.74
Bumps [bcprov-jdk15to18](https://github.com/bcgit/bc-java) from 1.69 to 1.74.
- [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.html)
- [Commits](https://github.com/bcgit/bc-java/commits)

---
updated-dependencies:
- dependency-name: org.bouncycastle:bcprov-jdk15to18
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-06 15:41:12 +00:00
fourier
aaad20b78a feat: 电商收付通二级商户进件接口联系人手机号码加密 2023-07-04 10:33:41 +08:00
fourier
10b09ac4bb feat: 电商收付通二级商户进件接口联系人信息增加字段 2023-07-04 10:26:54 +08:00
xiafang
62ecc5b700 Merge remote-tracking branch 'origin/1.0.20' into 1.0.20 2023-07-01 09:27:04 +08:00
xiafang
8168097427 enhance: 电商收付通二级商户进件申请参数
Closes #108
2023-07-01 09:26:28 +08:00
xiafang
9645d20b33 enhance: 电商收付通二级商户进件申请参数 2023-07-01 09:25:12 +08:00
xiafang
c42f6d9d5e - 电商二级商户进件补充最终受益人列表 2023-06-27 14:02:07 +08:00
xiafang
0635d59666 1.0.19 2023-06-24 11:29:11 +08:00
xiafang
5941907d7c feat: 支付有礼-直连商户 2023-06-21 15:15:22 +08:00
xiafang
348fe9b5f1 enhance: 代金券商家券样式兼容 2023-06-20 09:34:20 +08:00
xiafang
fa0cc541de fix:服务商模式下预支付的签名问题
Closes #I7829T
2023-06-20 08:35:22 +08:00
xiafang
85fde9bb68 优化默认的证书加载,增加缓存 2023-05-22 14:07:24 +08:00
xiafang
da0fe928eb Merge README.md 2023-05-05 12:55:33 +08:00
felord.cn
1c27375d93 Merge pull request #99 from dromara/1.0.18
1.0.18
2023-05-05 12:44:37 +08:00
xiafang
4271491bc3 Merge README.md 2023-05-05 12:41:23 +08:00
xiafang
730c15b6b8 Update pom.xml 2023-05-05 12:33:21 +08:00
xiafang
dc6e48d538 enhance: 修改了支付配置加载机制,现在可以不停机维护微信支付参数了 2023-05-05 12:20:06 +08:00
xiafang
36259fc8ac 更新群信息 2023-04-25 11:00:18 +08:00
xiafang
e6e704cc28 docs: 修正文档描述错误 2023-03-24 13:43:34 +08:00
xiafang
8578300d1c docs: 修正文档描述错误 2023-03-24 13:40:32 +08:00
Fang
d7cdebc731 docs: 项目文档迁入dromara
Closes #96
2023-03-12 20:54:25 +08:00
felord.cn
97d87ce6f0 Delete 提问.md 2023-03-11 08:53:13 +08:00
felord.cn
99136f9bd6 Update issue templates 2023-03-11 08:52:15 +08:00
felord.cn
571bd2e563 Update issue templates 2023-03-11 08:49:32 +08:00
Fang
aef8ef9ac3 factor:移除过时的V2退款API 2023-03-10 22:32:52 +08:00
Fang
f630301bc3 docs:更新文档地址到dromara组织 2023-03-10 22:31:06 +08:00
xiafang
f7ba4dd306 1.0.18 2023-03-08 13:39:11 +08:00
Fang
997f004708 enhance: 增强资源加载器 2023-03-06 22:31:55 +08:00
xiafang
5e63779f36 1.0.18 2023-03-01 09:29:36 +08:00
xiafang
30613a2fdd enhance: 优化证书加载方式以支持Docker内读取
Closes #94
2023-03-01 09:24:51 +08:00
felord.cn
e9388f62c1 Update changelog.md 2023-02-26 14:33:38 +08:00
xiafang
685839089f README.md 2023-02-25 17:16:29 +08:00
xiafang
7b9bdd21f7 README.md 2023-02-25 16:56:37 +08:00
xiafang
8c4ecad809 README.md 2023-02-25 16:52:29 +08:00
xiafang
e24aa83ba0 README.md 2023-02-25 16:47:36 +08:00
felord.cn
d6d5e33dae Merge pull request #93 from NotFound403/1.0.17
1.0.17
2023-02-25 16:41:16 +08:00
xiafang
f4df8d271e docs: 现在可以通过API清单检索相关的API了 2023-02-25 16:35:07 +08:00
xiafang
fec2468b6f factor: 营销图片上传API现在由WechatMediaApi#marketingImageUpload实现,以代替WechatMarketingFavorApi#marketingImageUpload,旧实现以被标记过时 2023-02-25 15:07:59 +08:00
xiafang
0fadd3dbc0 docs: 修复文档描述错误 2023-02-25 14:26:38 +08:00
xiafang
38f6fb4e06 feat: 支付分增加退款独立的API 2023-02-25 13:39:27 +08:00
xiafang
2fd1d0c1f9 feat: 直连商户合单支付增加查询单笔退款 2023-02-25 13:20:41 +08:00
xiafang
dccc105807 factor:时间格式优化,移除时区限制为东八区,由LocalDateTime改为OffsetDateTime 2023-02-23 08:53:45 +08:00
xiafang
2fa018a0c9 增加示例 2023-02-14 17:44:15 +08:00
xiafang
e370610e2e README 2023-02-10 16:55:35 +08:00
xiafang
0f2b8762cb README 2023-02-10 16:09:41 +08:00
xiafang
843afa4b1c README 2023-02-10 16:09:09 +08:00
xiafang
b177174589 README 2023-02-10 16:08:33 +08:00
felord.cn
f80245e302 Update README.md 2023-02-10 16:07:06 +08:00
xiafang
0213ddcb23 README 2023-02-10 16:02:48 +08:00
xiafang
e914be40ad gitee 2023-02-10 13:35:17 +08:00
xiafang
c53ee8bf24 README 2023-02-10 13:22:08 +08:00
xiafang
0d80d4191c README 2023-02-10 13:20:16 +08:00
xiafang
c6331a08f7 changelog.md 2023-02-10 12:33:43 +08:00
xiafang
402fda7cf9 1.0.16 2023-02-10 11:32:49 +08:00
xiafang
9cc3e96dff Merge remote-tracking branch 'origin/release' into release 2023-02-10 11:32:04 +08:00
xiafang
9ccbe1e977 upgrade: bcprov-jdk15to18 upgrade to 1.69 2023-02-10 11:31:45 +08:00
felord.cn
6b78b30b75 Merge pull request #90 from NotFound403/1.0.16
1.0.16
2023-02-10 09:40:15 +08:00
xiafang
bd782503ea factor:租户信息服务类优化 2023-02-09 09:35:06 +08:00
xiafang
110b8b5cfc 配置导入 2023-02-09 09:26:00 +08:00
Fang
55440b1275 feat: 直连商户-委托营销相关API实现 2023-02-08 23:15:48 +08:00
xiafang
59be1e96ad README 2023-02-07 17:35:01 +08:00
xiafang
6534d4c0f6 enhance: 增加抽象接口WechatTenantService负责从配置文件或者其它数据源检索租户配置信息,提供默认实现InMemoryWechatTenantService(可被覆盖)
Closes #88
2023-02-03 13:32:00 +08:00
xiafang
0faa855f90 README 2023-02-03 09:59:15 +08:00
xiafang
4fc6aad767 upgrade: gpg upgrade to 3.0.1 2023-01-29 15:33:58 +08:00
xiafang
c55df6f576 refactor: 基础支付增加电子发票入口开放标识 2023-01-28 16:17:01 +08:00
xiafang
3398f7e2b7 refactor: 服务商商户进件请求不再需要银行证明材料,已标记为废弃,涉及特约商户进件和电商收付通 2023-01-28 15:16:45 +08:00
xiafang
c5d19c68c0 enhance:商家转账到零钱-发起商家转账 增加转账场景ID 2023-01-13 16:53:28 +08:00
felord.cn
4dea6b0afe Merge pull request #86 from NotFound403/1.0.15
1.0.15
2023-01-03 16:08:34 +08:00
xiafang
379d007bb4 Merge branch 'release' into 1.0.15
# Conflicts:
#	README.md
#	payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatBatchTransferApi.java
2023-01-03 16:07:25 +08:00
xiafang
de3cf3d2ae 解决冲突 2023-01-03 16:06:06 +08:00
xiafang
9d2f8a7d72 upgrade: spring boot 版本升级到2.7.7 2023-01-03 15:38:12 +08:00
xiafang
e1ec5f1b7c upgrade: spring boot 版本升级到2.7.7 2023-01-03 15:32:50 +08:00
xiafang
d8288cdd3a feat: 微信服务商分账-连锁品牌分账
Closes #82
2023-01-03 15:09:13 +08:00
xiafang
113e531eae Merge remote-tracking branch 'origin/1.0.15' into 1.0.15 2023-01-03 09:32:20 +08:00
xiafang
d91b52ba2b fix: 微信代金券样式的背景颜色枚举更新
Closes #84
2023-01-03 09:28:08 +08:00
xiafang
1742437c2c fix: 批量转账到零钱金额小于2000 userName是可以非必填的
Closes #85
2023-01-03 09:25:10 +08:00
felord.cn
2f391cc14c Update README.md 2022-12-09 11:01:55 +08:00
Fang
31bef5bfac Merge remote-tracking branch 'origin/1.0.15' into 1.0.15 2022-11-02 18:44:03 +08:00
Fang
5d1fd73f2b enhance: 增加小微商户进件主体类型 2022-11-02 18:41:51 +08:00
felord.cn
18b6615c44 Update README.md 2022-10-11 13:20:14 +08:00
xiafang
0ebe58ae09 Merge remote-tracking branch 'origin/1.0.15' into 1.0.15 2022-10-11 11:16:04 +08:00
xiafang
2f69023ffd upgrade: gpg upgrade to 3.0.1 2022-10-11 11:12:26 +08:00
felord.cn
a11aae69c3 Merge pull request #81 from zjiecode/bugfix/user-name-npe
修复【发起批量转账API】,转账姓名为空是发生NPE
2022-10-05 17:44:32 +08:00
Fang
2c28113ee7 Merge remote-tracking branch 'origin/1.0.15' into 1.0.15 2022-10-05 13:21:43 +08:00
Fang
05a3e83e3e enhance: 订单失效时间现在需要以java时间格式LocalDateTime传入
#66
2022-10-05 13:21:23 +08:00
Fang
2f7e6c6b22 enhance: 订单失效时间现在需要以java时间格式LocalDateTime传入 2022-10-05 13:17:06 +08:00
Fang
9b4193a4f9 upgrade: spring boot 版本升级到2.7.4 2022-10-05 12:25:38 +08:00
Fang
6e4bfd2192 enhance: rfc 3339 格式优化 2022-10-05 12:13:52 +08:00
zjiecode
e412760a8e 修复【发起批量转账API】,转账姓名为空是发生NPE
当付款金额低于0.3元的时候,微信不支持实名验证,因此不能传userName。
不传userName,此处为发生NPE。
2022-10-04 14:37:38 +08:00
xiafang
02867baa2c fix: 商家卷-修改批次预算API配置修改为Patch
Closes #79
2022-09-28 08:39:50 +08:00
felord.cn
4c21329ceb Merge pull request #78 from hellozhongying/1.0.15
增加服务商退款api和查询服务商退款订单api
2022-09-28 08:36:58 +08:00
xiafang
e1616c5606 fix: 商家卷-修改批次预算API请求方法应该为Patch
Closes #79
2022-09-28 08:35:20 +08:00
hellozhongying
34d0bed373 去掉多余的退款枚举 2022-09-22 18:31:35 +08:00
hellozhongying
575bf6e8a2 增加服务商退款api 2022-09-22 17:54:04 +08:00
xiafang
f73be6452e fix: 多租户证书无法复用的问题,刷新时正确移除证书
Closes #77
2022-09-22 15:34:51 +08:00
xiafang
a9ab004a96 fix: 多租户证书无法复用的问题
Closes #77
2022-09-22 15:28:32 +08:00
xiafang
24f270acd6 changelog 2022-09-15 18:25:55 +08:00
felord.cn
0145a343f9 Merge pull request #76 from NotFound403/1.0.14.RELEASE
1.0.14.RELEASE
2022-09-15 14:12:53 +08:00
xiafang
0dd7ca97f7 changelog 2022-09-15 14:09:46 +08:00
dax
5ef0ff0c85 feat: 增加证书绝对路径实现
- 配置项增加`certAbsolutePath`字段用来定义证书的绝对路径,优先级高于`certPath`。当这两个路径都不配置时采用classpath路径`wechat/apiclient_cert.p12`。

Closes #73
2022-07-21 10:05:37 +08:00
dax
af3ee97c33 feat: 移除V2的分账实现 2022-07-21 09:49:29 +08:00
dax
796cb4c921 feat: 其它能力-银行组件(服务商)
- 获取对私银行卡号开户银行API
- 查询支持个人业务的银行列表API
- 查询支持对公业务的银行列表API
- 查询省份列表API
- 查询城市列表API
- 查询支行列表API
2022-07-12 10:07:07 +08:00
dax
28b4c9c7a6 fix: 二级商户进件字段补充 2022-07-12 09:06:39 +08:00
dax
91597b90ac fix: 修复地址加密的NPE问题 2022-07-07 18:57:43 +08:00
dax
1acdf629d8 fix: 修复商户进件身份信息没有加密的问题,证件结束日期修改为字符串格式以兼容 长期 选项 2022-07-07 14:05:37 +08:00
Fang
d8ec62c293 fix: 批量转账到零钱查询BUG
Closes #I5E2X7
2022-06-27 23:34:32 +08:00
Fang
37fc29a02c feat: 实现智慧商圈 2022-06-20 15:59:51 +08:00
Fang
8e9f704b89 feat: 移除无效的BOM 2022-06-20 13:09:58 +08:00
Fang
d8ada58822 feat: 实现电商收付通功能,补充优化一些接口,增加了部分缺失回调
- 实现电商收付通
- 兼容较低版本的jackson
- 服务商分账新增下载账单
- 增加服务商退款回调
- 一些其它问题
2022-06-20 10:28:28 +08:00
Fang
89f12df44a feat: 实现经营能力接口
- 支付即服务,适用于服务商和直连商户
- 点金计划,适用于服务商
2022-06-19 01:23:26 +08:00
Fang
0027e6f934 upgrade: 版本号变更 2022-06-18 16:00:33 +08:00
Fang
565f27988d upgrade: 版本号变更 2022-06-18 15:40:52 +08:00
Fang
5e050ddbcb feat: 实现媒体上传
- 图片上传API
- 视频上传API
2022-06-18 15:37:01 +08:00
Fang
5a46bbc0a4 feat: 实现服务商商户进件-特约商户进件
- 提交申请单API
- 查询申请单状态API
  - 通过业务申请编号查询申请状态
  - 通过申请单号查询申请状态
- 修改结算账号API
- 查询结算账户API
2022-06-18 15:11:20 +08:00
felord.cn
14553f9ba7 Merge pull request #70 from zhyblack/zhy_black
TransactionConsumeData Payer add spOpenid subOpenid
2022-06-18 10:16:54 +08:00
zhy_black
ebfc54d1db “TransactionConsumeData Payer add spOpenid subOpenid 2022-06-17 19:25:51 +08:00
felord.cn
e59c8f4b16 Merge pull request #68 from NotFound403/1.0.13.SNAPSHOT
1.0.13.RELEASE
2022-06-13 09:56:21 +08:00
codesee-architecture-diagrams[bot]
a1071d2f86 Add CodeSee architecture diagram workflow to repository 2022-01-17 15:10:42 +00:00
300 changed files with 9033 additions and 1577 deletions

27
.github/ISSUE_TEMPLATE/issues.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: issues
about: 向维护者提问以帮助改进
title: ''
labels: ''
assignees: ''
---
**提问前的思考**
1. 我是否已经认真阅读了文档和相关操作说明
2. 其它ISSUES是否已经有了解决方案
**描述问题**
提问时应该按照以下要点清晰地描述问题,才能得到可靠的答复
**环境版本信息**
问题发生的环境,不限于软件版本、运行时环境、操作系统等
**操作行为**
产生问题的操作行为
**期望的结果**
清晰地描述期望达成的结果
**代码与截图**
通常不建议使用代码截图这样不太方便维护者进行Preview。代码应该使用Markdown代码块进行格式化。因交互导致的问题才建议使用截图辅助排查。

View File

@@ -0,0 +1,81 @@
on:
push:
branches:
- release
pull_request_target:
types: [opened, synchronize, reopened]
name: CodeSee Map
jobs:
test_map_action:
runs-on: ubuntu-latest
continue-on-error: true
name: Run CodeSee Map Analysis
steps:
- name: checkout
id: checkout
uses: actions/checkout@v2
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
# codesee-detect-languages has an output with id languages.
- name: Detect Languages
id: detect-languages
uses: Codesee-io/codesee-detect-languages-action@latest
- name: Configure JDK 16
uses: actions/setup-java@v2
if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
with:
java-version: '16'
distribution: 'zulu'
# CodeSee Maps Go support uses a static binary so there's no setup step required.
- name: Configure Node.js 14
uses: actions/setup-node@v2
if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
with:
node-version: '14'
- name: Configure Python 3.x
uses: actions/setup-python@v2
if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
with:
python-version: '3.10'
architecture: 'x64'
- name: Configure Ruby '3.x'
uses: ruby/setup-ruby@v1
if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
with:
ruby-version: '3.0'
# CodeSee Maps Rust support uses a static binary so there's no setup step required.
- name: Generate Map
id: generate-map
uses: Codesee-io/codesee-map-action@latest
with:
step: map
github_ref: ${{ github.ref }}
languages: ${{ steps.detect-languages.outputs.languages }}
- name: Upload Map
id: upload-map
uses: Codesee-io/codesee-map-action@latest
with:
step: mapUpload
api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
github_ref: ${{ github.ref }}
- name: Insights
id: insights
uses: Codesee-io/codesee-map-action@latest
with:
step: insights
api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
github_ref: ${{ github.ref }}

373
README.md
View File

@@ -1,66 +1,355 @@
# 最好用的微信支付V3 Spring Boot 组件
<div align="center" style="margin-bottom: 10px"><h1>最全最好用的微信支付V3 Spring Boot 组件</h1></div>
为了满足业务中出现app支付、公众号支付、小程序支付等多appid并存的场景对原有的进行了增强开发出了多租户版本。
<p align="center">
<a target="_blank" href="https://github.com/dromara/payment-spring-boot/blob/release/LICENSE">
<img alt="" src="https://img.shields.io/github/license/dromara/payment-spring-boot"/>
</a>
<a target="_blank" href="https://felord.cn">
<img alt="" src="https://img.shields.io/badge/java-8-red"/>
</a>
<a target="_blank" href="https://spring.io">
<img alt="" src="https://img.shields.io/badge/spring%20boot-2.4%2B-brightgreen"/>
</a>
<a target="_blank" href="https://mvnrepository.com/artifact/cn.felord/payment-spring-boot">
<img alt="" src="https://img.shields.io/maven-central/v/cn.felord/payment-spring-boot.svg?style=flat-square"/>
</a>
<a target="_blank" href="https://github.com/dromara/payment-spring-boot">
<img alt="" src="https://img.shields.io/github/stars/dromara/payment-spring-boot?style=social"/>
</a>
<a target="_blank" href="https://gitee.com/dromara/payment-spring-boot/stargazers">
<img alt="" src="https://gitee.com/felord/payment-spring-boot/badge/star.svg?theme=white"/>
</a>
<a target="_blank" href="https://work.weixin.qq.com/kfid/kfc9d9d759f27f087e1">
<img alt="点击立即微信咨询" src="https://img.shields.io/badge/%E7%82%B9%E5%87%BB-%E5%BE%AE%E4%BF%A1%E5%92%A8%E8%AF%A2-brightgreen"/>
</a>
<a target="_blank" href="#">
<img alt="点击加入QQ交流①群" src="https://img.shields.io/badge/QQ%E4%BA%A4%E6%B5%81%E7%BE%A4-945342113-ff69b4"/>
</a>
<a target="_blank" href="https://jq.qq.com/?_wv=1027&k=cCiv8Vlv">
<img alt="点击加入QQ交流②群" src="https://img.shields.io/badge/QQ%E4%BA%A4%E6%B5%81%E7%BE%A4-549174561-ff69b4"/>
</a>
</p>
请给[Payment Spring Boot](https://github.com/NotFound403/payment-spring-boot) **Star**以鼓励,谢谢。
<p align="center">如果你感觉这个项目不错请点击右上角的Star以鼓励作者谢谢。</p>
## 简介
Java微信支付V3支付Spring Boot
Starter支持微信优惠券代金券、商家券、智慧商圈、商家转账到零钱、公众号支付、微信小程序支付、分账、支付分、商家券、合单支付、先享卡、电商收付通等全部微信支付功能API同时满足多个服务商、多个商户开发需求。一键集成屏蔽了复杂度API友好上手快欢迎star。
## Maven 最新中央仓库坐标
```xml
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.13.RELEASE</version>
<version>1.0.20.RELEASE</version>
</dependency>
```
## 功能
- 实现微信支付多商户
- 集成支付宝SDK、快速接入Spring Boot
- 实现微信支付V3 基础支付
- 实现微信支付V3 合单支付
- 实现微信支付V3 代金券
- 实现微信支付V3 微信支付分
- 实现微信支付V3 先享卡
- 实现微信支付V3 商家券
- 实现微信支付V3 批量转账到零钱
## JDK问题
更多参考[changelog](https://notfound403.github.io/payment-spring-boot/#/changelog)
**推荐使用Open JDK**,原因参见[FBI Warning](https://github.com/dromara/payment-spring-boot/issues/5)
## 核心API结构
![](https://asset.felord.cn/blog/20220613092244.png)
## 文档地址
- `WechatPartnerProfitsharingApi` 微信支付服务商V3分账
- `WechatPayCallback` 微信支付V3回调通知工具封装
- `WechatAllocationApi` 微信支付V2分账未来会移除
- `WechatMarketingFavorApi` 微信支付代金券V3
- `WechatCombinePayApi` 微信支付合单支付V3
- `WechatPayScoreApi` 微信支付分V3
- `WechatPayRedpackApi` 微信支付V2现金红包
- `WechatDiscountCardApi` 微信支付V3先享卡
- `WechatProfitsharingApi` 微信支付直连商户V3分账
- `WechatPartnerPayApi` 微信支付服务商模式V3普通支付
- `WechatMarketingBusiFavorApi` 微信支付V3商家券
- `WechatPayTransfersApi` 微信支付V2企业付款到零钱目前不包括到银行卡
- `WechatDirectPayApi` 微信支付直连模式V3普通支付
- `WechatPayScoreParkingApi` 微信支付分V3停车服务
- `WechatBatchTransferApi` 微信支付V3批量转账到零钱
- [payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
> 随着版本迭代功能会增加。
## API清单
目前已经实现绝大部分微信支付直连商户和服务商的接口具体的API明细可查看[API清单](https://dromara.github.io/payment-spring-boot/#/wechat_v3_api)
> 随着版本迭代功能会增加也可通过API注册表类`WechatPayV3Type`进行API接口检索。
## CHANGELOG
更新日志[CHANGELOG](https://dromara.github.io/payment-spring-boot/#/changelog)
## 使用入门
### 集成配置
关于集成配置请详细阅读[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
中[快速接入](https://dromara.github.io/payment-spring-boot/#/quick_start)章节
### 调用示例
#### 开启支付
需要手动通过`@EnableMobilePay`注解开启支付
```java
import cn.felord.payment.autoconfigure.EnableMobilePay;
import org.springframework.context.annotation.Configuration;
@EnableMobilePay
@Configuration
public class PayConfig {
}
```
#### 支付接口调用
这里简单以小程序支付为例写了一个Spring MVC 控制器,在实践中建议对`WechatApiProvider`进行二次封装作服务层调用
```java
import cn.felord.payment.wechat.enumeration.TradeBillType;
import cn.felord.payment.wechat.v3.WechatApiProvider;
import cn.felord.payment.wechat.v3.WechatDirectPayApi;
import cn.felord.payment.wechat.v3.model.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.Month;
/**
* 支付接口开发样例,以小程序支付为例.
*/
@Profile({"wechat", "dev"})
@RestController
@RequestMapping("/marketing")
public class PayController {
@Autowired
private WechatApiProvider wechatApiProvider;
String TENANT_ID = "mobile";
/**
* 总流程建议为 生成商品订单 -> 生成对应的支付订单 -> 支付操作 -> 支付结果回调更新 -> 结束
* <p>
* 此处建议在商品订单生成之后调用
*
* @param orderId 商品订单id
* @return the object node
*/
@PostMapping("/js")
public ObjectNode js(@RequestParam String orderId) {
//TODO
// 查询该orderId下是否生成了支付订单
// 如果没有
// 新增支付订单存入数据库 并标明支付状态为【待支付】
// 根据新生成的支付订单信息向微信支付发起支付 并根据返回结果进行处理
// 如果有状态为待支付
// 根据待支付订单信息向微信支付发起支付 并根据返回结果进行处理
// 如果有状态为待支付之外的状态
// 根据产品的业务设计自行实现
// 支付状态更新逻辑在【回调接口 /wxpay/callbacks/transaction】中处理 需要幂等处理
// 开发时需要指定使用的商户租户配置 这里为 mobile 请参考 application-wechat.yml
PayParams payParams = new PayParams();
payParams.setDescription("felord.cn");
//
// 商户侧唯一订单号 建议为商户侧支付订单号 订单表主键 或者唯一标识字段
payParams.setOutTradeNo("X135423420201521613448");
// 需要定义回调通知
payParams.setNotifyUrl("/wxpay/callbacks/transaction");
Amount amount = new Amount();
amount.setTotal(100);
payParams.setAmount(amount);
// 此类支付 Payer 必传 且openid需要同appid有绑定关系 具体去看文档
Payer payer = new Payer();
payer.setOpenid("ooadI5kQYrrCqpgbisvC8bEw_oUc");
payParams.setPayer(payer);
return wechatApiProvider.directPayApi(TENANT_ID)
.jsPay(payParams)
.getBody();
}
/**
* 下载对账单 如果要解析内容的话自行实现
*
* @return the response entity
*/
@GetMapping("/tradebill")
public ResponseEntity<Resource> download() {
WechatDirectPayApi wechatDirectPayApi = wechatApiProvider.directPayApi(TENANT_ID);
TradeBillParams tradeBillParams = new TradeBillParams();
tradeBillParams.setBillDate(LocalDate.of(2021, Month.MAY, 20));
tradeBillParams.setBillType(TradeBillType.ALL);
return wechatDirectPayApi.downloadTradeBill(tradeBillParams);
}
/**
* 下载申请资金账单 如果要解析内容的话自行实现
*
* @return the response entity
*/
@GetMapping("/fundflowbill")
public ResponseEntity<Resource> fundFlowBill() {
WechatDirectPayApi wechatDirectPayApi = wechatApiProvider.directPayApi(TENANT_ID);
FundFlowBillParams fundFlowBillParams = new FundFlowBillParams();
fundFlowBillParams.setBillDate(LocalDate.of(2021, Month.MAY, 20));
return wechatDirectPayApi.downloadFundFlowBill(fundFlowBillParams);
}
}
```
#### 回调示例
回调可通过以下示例实现多租户的回调可将租户ID`tenantId`作为路径参数来实现
```java
import cn.felord.payment.wechat.v3.WechatApiProvider;
import cn.felord.payment.wechat.v3.WechatMarketingFavorApi;
import cn.felord.payment.wechat.v3.WechatPayCallback;
import cn.felord.payment.wechat.v3.model.ResponseSignVerifyParams;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 注意为了演示该配置在使用微信配置application-wechat.yaml才生效
* <p>
* 务必保证回调接口的幂等性
* <p>
* 微信回调控制器,当支付成功、代金券核销成功后,微信支付服务器会通过回调进行通知商户侧。
* 商户侧可以根据微信的回调通知进行支付的后续处理,例如支付状态的变更等等。
* 需要注意的是回调接口需要白名单放行。
* <p>
* 开发者只需要编写对结果的{@link java.util.function.Consumer}即可。
* <p>
* 请注意:返回的格格式必须是{@link WechatPayCallback} 给出的格式,不能被包装和更改,切记!
* @author felord.cn
* @since 1.0.0.RELEASE
*/
@Profile({"wechat", "dev"})
@RestController
@RequestMapping("/wxpay/callbacks")
public class CallbackController {
private static final String TENANT_ID = "mobile";
@Autowired
private WechatApiProvider wechatApiProvider;
/**
* 代金券核销通知.
* <p>
* 需要手动调用{@link WechatMarketingFavorApi#setMarketingFavorCallback(String)} 设置,一次性操作!
*
* @param wechatpaySerial the wechatpay serial
* @param wechatpaySignature the wechatpay signature
* @param wechatpayTimestamp the wechatpay timestamp
* @param wechatpayNonce the wechatpay nonce
* @param request the request
* @return the map
*/
@SneakyThrows
@PostMapping("/coupon")
public Map<String, ?> couponCallback(
@RequestHeader("Wechatpay-Serial") String wechatpaySerial,
@RequestHeader("Wechatpay-Signature") String wechatpaySignature,
@RequestHeader("Wechatpay-Timestamp") String wechatpayTimestamp,
@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,
HttpServletRequest request) {
String body = request.getReader().lines().collect(Collectors.joining());
// 对请求头进行验签 以确保是微信服务器的调用
ResponseSignVerifyParams params = new ResponseSignVerifyParams();
params.setWechatpaySerial(wechatpaySerial);
params.setWechatpaySignature(wechatpaySignature);
params.setWechatpayTimestamp(wechatpayTimestamp);
params.setWechatpayNonce(wechatpayNonce);
params.setBody(body);
return wechatApiProvider.callback(TENANT_ID).couponCallback(params, data -> {
//TODO 对回调解析的结果进行消费 需要保证消费的幂等性 微信有可能多次调用此接口
});
}
/**
* 微信支付成功回调.
* <p>
* 无需开发者判断,只有扣款成功微信才会回调此接口
*
* @param wechatpaySerial the wechatpay serial
* @param wechatpaySignature the wechatpay signature
* @param wechatpayTimestamp the wechatpay timestamp
* @param wechatpayNonce the wechatpay nonce
* @param request the request
* @return the map
*/
@SneakyThrows
@PostMapping("/transaction")
public Map<String, ?> transactionCallback(
@RequestHeader("Wechatpay-Serial") String wechatpaySerial,
@RequestHeader("Wechatpay-Signature") String wechatpaySignature,
@RequestHeader("Wechatpay-Timestamp") String wechatpayTimestamp,
@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,
HttpServletRequest request) {
String body = request.getReader().lines().collect(Collectors.joining());
// 对请求头进行验签 以确保是微信服务器的调用
ResponseSignVerifyParams params = new ResponseSignVerifyParams();
params.setWechatpaySerial(wechatpaySerial);
params.setWechatpaySignature(wechatpaySignature);
params.setWechatpayTimestamp(wechatpayTimestamp);
params.setWechatpayNonce(wechatpayNonce);
params.setBody(body);
return wechatApiProvider.callback(TENANT_ID).transactionCallback(params, data -> {
//TODO 对回调解析的结果进行消费 需要保证消费的幂等性 微信有可能多次调用此接口
});
}
/**
* 微信合单支付成功回调.
* <p>
* 无需开发者判断,只有扣款成功微信才会回调此接口
*
* @param wechatpaySerial the wechatpay serial
* @param wechatpaySignature the wechatpay signature
* @param wechatpayTimestamp the wechatpay timestamp
* @param wechatpayNonce the wechatpay nonce
* @param request the request
* @return the map
*/
@SneakyThrows
@PostMapping("/combine_transaction")
public Map<String, ?> combineTransactionCallback(
@RequestHeader("Wechatpay-Serial") String wechatpaySerial,
@RequestHeader("Wechatpay-Signature") String wechatpaySignature,
@RequestHeader("Wechatpay-Timestamp") String wechatpayTimestamp,
@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,
HttpServletRequest request) {
String body = request.getReader().lines().collect(Collectors.joining());
// 对请求头进行验签 以确保是微信服务器的调用
ResponseSignVerifyParams params = new ResponseSignVerifyParams();
params.setWechatpaySerial(wechatpaySerial);
params.setWechatpaySignature(wechatpaySignature);
params.setWechatpayTimestamp(wechatpayTimestamp);
params.setWechatpayNonce(wechatpayNonce);
params.setBody(body);
return wechatApiProvider.callback(TENANT_ID).combineTransactionCallback(params, data -> {
//TODO 对回调解析的结果进行消费 需要保证消费的幂等性 微信有可能多次调用此接口
});
}
}
```
## 开源协议
**Apache 2.0**
## 仓库地址
- [GitHub](https://github.com/NotFound403/payment-spring-boot)
- [Gitee](https://gitee.com/felord/payment-spring-boot)
## 文档地址
- [payment-spring-boot GitHub文档](https://notfound403.github.io/payment-spring-boot)
- [payment-spring-boot Gitee文档](https://felord.gitee.io/payment-spring-boot)
- [GitHub](https://github.com/dromara/payment-spring-boot)
- [Gitee](https://gitee.com/dromara/payment-spring-boot)
## QQ交流群
为了交流解惑新建QQ群可通过扫码进入。
![QQ交流群](./docs/img/qqun.png)

View File

@@ -1,3 +1,20 @@
<!--
~ Copyright 2019-2022 felord.cn
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~ Website:
~ https://felord.cn
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="zh">
@@ -137,7 +154,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<td class="colLast"><code><span class="memberNameLink"><a href="../../../../../../cn/felord/payment/wechat/v3/model/StocksQueryParams.html#createEndTime">createEndTime</a></span></code>
<div class="block">选填
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</td>
</tr>
<tr class="rowColor">
@@ -145,7 +162,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<td class="colLast"><code><span class="memberNameLink"><a href="../../../../../../cn/felord/payment/wechat/v3/model/StocksQueryParams.html#createStartTime">createStartTime</a></span></code>
<div class="block">选填
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</td>
</tr>
<tr class="altColor">
@@ -252,7 +269,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html?is-external=true" title="java.time中的类或接口">OffsetDateTime</a> createStartTime</pre>
<div class="block">选填
<p>
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</li>
</ul>
<a name="createEndTime">
@@ -264,7 +281,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<pre>private&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html?is-external=true" title="java.time中的类或接口">OffsetDateTime</a> createEndTime</pre>
<div class="block">选填
<p>
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</li>
</ul>
<a name="status">

View File

@@ -1,3 +1,20 @@
<!--
~ Copyright 2019-2022 felord.cn
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~ Website:
~ https://felord.cn
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="zh">
@@ -1780,7 +1797,7 @@
<dd>
<div class="block">选填
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
终止时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</dd>
<dt><span class="memberNameLink"><a href="cn/felord/payment/wechat/v3/WechatPayScoreApi.html#createServiceOrder-cn.felord.payment.wechat.v3.model.payscore.UserServiceOrderParams-">createServiceOrder(UserServiceOrderParams)</a></span> - 类 中的方法cn.felord.payment.wechat.v3.<a href="cn/felord/payment/wechat/v3/WechatPayScoreApi.html" title="cn.felord.payment.wechat.v3中的类">WechatPayScoreApi</a></dt>
<dd>
@@ -1796,7 +1813,7 @@
<dd>
<div class="block">选填
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</code></div>
起始时间 最终满足格式 <code>yyyy-MM-dd'T'HH:mm:ssXXX</code></div>
</dd>
<dt><span class="memberNameLink"><a href="cn/felord/payment/wechat/v3/WechatMarketingBusiFavorApi.html#createStock-cn.felord.payment.wechat.v3.model.busifavor.BusiFavorCreateParams-">createStock(BusiFavorCreateParams)</a></span> - 类 中的方法cn.felord.payment.wechat.v3.<a href="cn/felord/payment/wechat/v3/WechatMarketingBusiFavorApi.html" title="cn.felord.payment.wechat.v3中的类">WechatMarketingBusiFavorApi</a></dt>
<dd>

View File

@@ -35,7 +35,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.13.RELEASE</version>
<version>1.0.20.RELEASE</version>
</dependency>
```
## 采用技术
@@ -51,4 +51,4 @@
## **免责声明**
**<span style="color:red;">本项目涉及到资金交易开发,开发者需要经严格测试后方能用于生产环境,本项目不对使用者的行为负责。</span>**
**<span style="color:red;">本项目涉及到资金交易开发,开发者需要经严格测试后方能用于生产环境,本项目不对使用者的行为负责。</span>**

View File

@@ -2,6 +2,6 @@
* [项目简介](README.md)
* [快速接入](quick_start.md)
* [JavaDoc](apidocs/index.html ':ignore')
* [微信支付V3接口文档](wechat_v3_api.md)
* [Payment微信支付V3接口文档](wechat_v3_api.md)
* [日常踩坑](stackoverflow.md)
* [更新日志](changelog.md)

View File

@@ -1,3 +1,58 @@
## 1.0.18.RELEASE
### 微信支付
- enhance: 使用`ResourceLoader`加载资源以改善Docker容器环境下的文件挂载问题
- enhance: 修改了微信支付配置加载机制,现在可以借助于`WechatTenantService`实现不停机维护微信支付参数的能力
- factor: 移除过时的V2退款API相关参数`RefundModel``RefundQueryModel`
- docs: 更新文档地址到[dromara.org](https://gitee.com/dromara),现在你可以通过[https://dromara.org/payment-spring-boot/](https://dromara.org/payment-spring-boot/)访问项目文档
- docs: 修正文档描述错误
## 1.0.17.RELEASE
### 微信支付
- feat: 直连商户合单支付增加查询单笔退款
- feat: 支付分增加退款独立的API
- factor: 营销图片上传API现在由WechatMediaApi#marketingImageUpload实现以代替WechatMarketingFavorApi#marketingImageUpload,旧实现已标记为过时
- factor:时间格式优化移除时区限制为东八区由LocalDateTime改为OffsetDateTime
- docs: 现在可以通过API清单检索API了
## 1.0.16.RELEASE
### 微信支付
- feat: 直连商户-委托营销相关API实现
- enhance:基础支付增加电子发票入口开放标识
- enhance:商家转账到零钱-发起商家转账 增加转账场景ID
- enhance: 增加抽象接口`WechatTenantService`负责从配置文件或者其它数据源检索租户配置信息,提供默认实现`InMemoryWechatTenantService`向下兼容 #88
- refactor: 服务商商户进件请求不再需要银行证明材料信息`BankAccountInfo`,已标记为废弃,涉及特约商户进件和电商收付通
- upgrade: bcprov-jdk15to18 1.67 升级到 1.69
## 1.0.15.RELEASE
### 微信支付
- feat: 增加服务商退款API
- feat: 微信服务商分账-连锁品牌分账 [#82](https://github.com/NotFound403/payment-spring-boot/issues/82)
- fix: 多租户证书无法复用的问题,刷新时正确移除证书 [#77](https://github.com/NotFound403/payment-spring-boot/issues/77)
- fix: 批量转账到零钱API入参NPE问题修复 [#85](https://github.com/NotFound403/payment-spring-boot/issues/85)
- fix: 商家券-修改批次预算API请求方法应该为Patch [#79](https://github.com/NotFound403/payment-spring-boot/issues/79)
- enhance: 部分时间格式优化更好地兼容Java Time API
- enhance: 微信代金券样式的背景颜色枚举更新 [#84](https://github.com/NotFound403/payment-spring-boot/issues/84)
- upgrade: Spring Boot 版本升级到2.7.7
## 1.0.14.RELEASE
### 微信支付
- fix: 批量转账到零钱查询BUG [#I5E2X7](https://gitee.com/felord/payment-spring-boot/issues/I5E2X7)
- feat: 移除了被标记过期的API包括基于微信支付V2版本的分账实现使用相关接口的同学需要针对性的进行迁移
- feat: 增加证书绝对路径实现
- 配置项增加`certAbsolutePath`字段用来定义证书的绝对路径,优先级高于`certPath`当这两个路径都不配置时采用classpath路径`wechat/apiclient_cert.p12` [#73](https://github.com/NotFound403/payment-spring-boot/issues/73)
#### 服务商
- feat: 实现服务商商户进件-特约商户进件相关API
- feat: 实现点金计划,适用于服务商
- feat: 实现行业方案-电商收付通
- feat: 实现行业方案-智慧商圈
- feat: 实现其它能力-银行组件(服务商)
- enhance: 服务商分账新增下载账单接口
- enhance: 新增服务商退款回调接口
#### 通用能力
- feat: 实现其它能力-图片、视频上传
- feat: 支付即服务,适用于服务商和直连商户
## 1.0.13.RELEASE
### 微信支付
@@ -148,4 +203,4 @@
- 多租户
- 支付宝
- 仅仅引入支付宝SDK后续维护以支付宝SDK变动为准
- 支付宝暂时不支持多租户
- 支付宝暂时不支持多租户

View File

@@ -4,7 +4,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.13.RELEASE</version>
<version>1.0.20.RELEASE</version>
</dependency>
```
> 基于 **Spring Boot 2.x**
@@ -174,4 +174,4 @@ public class PayConfig {
System.out.println("execute = " + execute.getBody());
}
```
```

View File

@@ -1,112 +1,236 @@
## 入口类
`WechatApiProvider`是本项目微信支付的入口类,已被注入**Spring IoC**。它目前包含以下几个**API**(后续会增加)。
`WechatApiProvider`是本项目微信支付的入口类,已被注入**Spring IoC**,由它来初始化微信支付相关的**API**,具体分为**直连商户
**和**服务商**两个体系。
### 代金券API
> 以下清单请搭配微信支付文档使用。
`WechatMarketingFavorApi`是微信支付营销工具-[代金券相关API](https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/convention.shtml)的封装。
### 直连商户
#### 创建代金券批次API
#### 基础支付
`WechatResponseEntity<ObjectNode> createStock(StocksCreateParams params)`
- [x] `WechatDirectPayApi` 基础支付,通过`WechatApiProvider#directPayApi`初始化
- [x] `jsPay` JSAPI/小程序下单
- [x] `appPay` APP下单
- [x] `h5Pay` H5下单
- [x] `nativePay` Native下单
- [x] 查询订单
1. `queryTransactionById` 微信支付订单号查询
2. `queryTransactionByOutTradeNo` 商户订单号查询
- [x] `close` 关闭订单
- [x] `WechatPayCallback#transactionCallback` 支付通知,参见下面回调说明
- [x] `refund` 申请退款
- [x] `queryRefundInfo` 查询单笔退款
- [x] `WechatPayCallback#refundCallback` 退款结果通知,参见下面回调说明
- [x] `downloadTradeBill` 申请交易账单直接下载为gzip或者txt文件
- [x] `downloadFundFlowBill` 申请资金账单直接下载为gzip或者txt文件
- [x] `WechatCombinePayApi` 合单支付,通过`WechatApiProvider#combinePayApi`初始化
- [x] `jsPay` 合单JSAPI/小程序下单
- [x] `appPay` 合单APP下单
- [x] `h5Pay` 合单H5下单
- [x] `nativePay` 合单Native下单
- [x] `queryTransactionByOutTradeNo` 查询订单,**合单支付目前只支持商户订单号查询**
- [x] `close` 合单关闭订单
- [x] `WechatPayCallback#combineTransactionCallback` 合单支付通知,参见下面回调说明
- [x] `refund` 合单申请退款
- [x] `queryRefundInfo` 合单查询单笔退款
- [x] `WechatPayCallback#refundCallback` 退款结果通知,参见下面回调说明
- [x] `downloadTradeBill` 申请交易账单直接下载为gzip或者txt文件
- [x] `downloadFundFlowBill` 申请资金账单直接下载为gzip或者txt文件
- [ ] ~~付款码支付~~暂时没有V3接口可通过payment spring boot 提供的V2扩展功能自行实现。
#### 激活代金券批次API
#### 经营能力
`WechatResponseEntity<ObjectNode> startStock(String stockId)`
##### 微信支付分
#### 发放代金券API
- [x] `WechatPayScoreApi` 微信支付分,通过`WechatApiProvider#payScoreApi`初始化
- [x] 公共API
- [x] `createServiceOrder` 创建支付分订单
- [x] `queryServiceOrder` 查询支付分订单
- [x] `cancelServiceOrder` 取消支付分订单
- [x] `modifyServiceOrder` 修改订单金额
- [x] `completeServiceOrder` 完结支付分订单
- [x] `syncServiceOrder` 同步服务订单信息
- [x] `WechatPayCallback#payscoreUserOrderCallback` 支付成功回调通知,参见下面回调说明
- [x] `refund` 支付分申请退款
- [x] `queryRefundInfo` 支付分查询单笔退款
- [x] `WechatPayCallback#refundCallback` 支付分退款结果通知,参见下面回调说明
- [x] 免确认预授权模式
- [x] `permissions` 商户预授权
- [x] `queryPermissionsByAuthCode` 查询与用户授权记录(授权协议号)
- [x] `terminatePermissionsByAuthCode` 解除用户授权关系(授权协议号)
- [x] `queryPermissionsByOpenId` 查询与用户授权记录openid
- [x] `terminatePermissionsByOpenId` 解除用户授权关系openid
- [x] `WechatPayCallback#permissionCallback` 开启/解除授权服务回调通知,参见下面回调说明
- [x] 需确认模式
- [x] `WechatPayCallback#payscoreUserOrderCallback` 确认订单回调通知,参见下面回调说明
`WechatResponseEntity<ObjectNode> sendStock(StocksSendParams params)`
##### 支付即服务
#### 暂停代金券批次API
- [x] `WechatSmartGuideApi` 支付即服务,通过`WechatApiProvider#smartGuideApi`初始化
- [x] `register` 服务人员注册
- [x] `assign` 服务人员分配
- [x] `query` 服务人员查询
- [x] `modify` 服务人员信息更新
`WechatResponseEntity<ObjectNode> pauseStock(String stockId)`
#### 行业方案
#### 重启代金券批次API
##### 智慧商圈
`WechatResponseEntity<ObjectNode> restartStock(String stockId)`
- [x] `WechatBusinessCircleApi` 智慧商圈,通过`WechatApiProvider#businessCircleApi`初始化
- [ ] 商圈会员积分服务授权结果通知回调(未实现)
- [x] `WechatPayCallback#mallTransactionCallback` 商圈会员场内支付结果通知,参见下面回调说明
- [x] `apply` 商圈积分同步
- [x] `WechatPayCallback#mallRefundCallback` 商圈会员场内退款通知,参见下面回调说明
- [x] `queryAuthStatus` 商圈积分授权查询
- [ ] 商圈会员待积分状态查询(未实现)
- [ ] 商圈会员停车状态同步(未实现)
#### 条件查询批次列表API
通过此接口可查询多个批次的信息,包括批次的配置信息以及批次概况数据。
##### 微信支付分停车服务
`WechatResponseEntity<ObjectNode> queryStocksByMch(StocksQueryParams params)`
- [x] `WechatPayScoreParkingApi` 微信支付分停车服务,通过`WechatApiProvider#payScoreParkingApi`初始化
- [x] `find` 查询车牌服务开通信息
- [x] `parking` 创建停车入场
- [x] `transactionsParking` 扣费受理
- [x] `queryTransactionByOutTradeNo` 查询订单
- [x] `WechatPayCallback#payscoreParkingCallback` 停车入场状态变更通知,参见下面回调说明
- [x] `WechatPayCallback#payscoreTransParkingCallback` 订单支付结果通知,参见下面回调说明
- [x] `refund` 申请退款
- [x] `queryRefundInfo` 查询单笔退款
- [x] `WechatPayCallback#refundCallback` 退款结果通知,参见下面回调说明
#### 查询批次详情API
#### 营销工具
`WechatResponseEntity<ObjectNode> queryStockDetail(String stockId)`
##### 代金券
#### 查询代金券详情API
- [x] `WechatMarketingFavorApi` 代金券,通过`WechatApiProvider#payScoreParkingApi`初始化
- [x] `createStock` 创建代金券批次
- [x] `startStock` 激活代金券批次
- [x] `sendStock` 发放代金券
- [x] `pauseStock` 暂停代金券批次
- [x] `restartStock` 重启代金券批次
- [x] `queryStocksByMch` 条件查询批次列表
- [x] `queryStockDetail` 查询批次详情
- [x] `queryCouponDetails` 查询代金券详情
- [x] `queryMerchantsByStockId` 查询代金券可用商户
- [x] `queryStockItems` 查询代金券可用单品
- [x] `queryUserCouponsByMchId` 根据商户号查用户的券
- [x] `downloadStockUseFlow` 下载批次核销明细
- [x] `downloadStockRefundFlow` 下载批次退款明细
- [x] `setMarketingFavorCallback` 设置消息通知地址
- [x] `WechatPayCallback#couponCallback` 核销事件回调通知,参见下面回调说明
- [x] `sendCouponsCard` 发放消费卡
`WechatResponseEntity<ObjectNode> queryCouponDetails(CouponDetailsQueryParams params)`
> `sendCouponsCard` 发放消费卡,功能仅向指定邀约商户开放,如有需要请联系微信支付运营经理。
#### 查询代金券可用商户API
##### 商家券
`WechatResponseEntity<ObjectNode> queryMerchantsByStockId(StocksQueryParams params)`
- [x] `WechatMarketingBusiFavorApi` 商家券,通过`WechatApiProvider#busiFavorApi`初始化
- [x] `createStock` 创建商家券券批次
- [x] `queryStockDetail` 查询商家券详情
- [x] `use` 核销用户券
- [x] `queryUserStocks` 根据过滤条件查询用户券
- [x] `queryUserCoupon` 查询用户单张券详情
- [x] `uploadCouponCodes` 上传预存code
- [x] `setCallbacks` 设置商家券事件通知地址
- [x] `getCallbacks` 查询商家券事件通知地址
- [x] `associate` 关联订单信息
- [x] `disassociate` 取消关联订单信息
- [x] `budget` 修改批次预算
- [x] `updateStock` 修改商家券基本信息
- [x] `refund` 申请退券
- [x] `deactivate` 使券失效
- [x] `payMakeup` 营销补差付款
- [x] `queryMakeup` 查询营销补差付款单详情
- [x] `payMakeup` 营销补差付款
- [x] `WechatPayCallback#busiFavorReceiveCallback` 领券事件回调通知,参见下面回调说明
#### 查询代金券可用单品API
##### 委托营销
`WechatResponseEntity<ObjectNode> queryStockItems(StocksQueryParams params)`
- [x] `WechatMarketingPartnershipApi` 委托营销,通过`WechatApiProvider#marketingshipApi`初始化
- [x] `build` 建立合作关系
- [x] `query` 查询合作关系列表
#### 根据商户号查用户的券API
##### 支付有礼
`WechatResponseEntity<ObjectNode> queryUserCouponsByMchId(UserCouponsQueryParams params)`
- [x] `WechatMarketingPayGiftActivityApi` 支付有礼,通过`WechatApiProvider#marketingPayGiftActivityApi`初始化
- [x] `create` 创建全场满额送活动
- [x] `details` 查询活动详情接口
- [x] `merchants` 查询活动发券商户号
- [x] `goods` 查询活动指定商品列表
- [x] `terminate` 终止活动
- [x] `addMches` 新增活动发券商户号
- [x] `page` 获取支付有礼活动列表
- [x] `deleteMch` 删除活动发券商户号
#### 下载批次核销明细API
##### 图片上传(营销专用)
`WechatResponseEntity<ObjectNode> downloadStockUseFlow(String stockId)`
- [x] 参见 **其它能力**
#### 下载批次退款明细API
##### 现金红包基于V2
`WechatResponseEntity<ObjectNode> downloadStockRefundFlow(String stockId)`
- [x] `WechatPayRedpackApi` 现金红包,通过`WechatApiProvider#redpackApi`初始化
- [x] `sendRedpack` 发放随机红包
- [x] `sendRedpack` 发放裂变红包
- [x] `redpackInfo` 查询红包信息
#### 营销图片上传API
> 重要:**基于V2实现因此需要在配置文件中配置v2支付对应的`appSecret`参数**
`WechatResponseEntity<ObjectNode> marketingImageUpload(MultipartFile file)`
#### 资金应用
#### 代金券核销回调通知API
##### 商家转账到零钱
`WechatResponseEntity<ObjectNode> setMarketingFavorCallback(String notifyUrl)`
- [x] `WechatBatchTransferApi` 商家转账到零钱,通过`WechatApiProvider#batchTransferApi`初始化
- [x] `batchTransfer` 发起批量转账
- [x] 查询转账批次单
1. `queryBatchByBatchId` 通过微信批次单号查询批次单
2. `queryBatchByOutBatchNo` 通过商家批次单号查询批次单
- [x] 查询转账明细单
1. `queryBatchDetailByWechat` 通过微信明细单号查询明细单
2. `queryBatchDetailByMch` 通过商家明细单号查询明细单
- [x] 申请转账电子回单
1. `receiptBill` 转账账单电子回单申请受理接口
2. `downloadBill` 查询转账账单电子回单接口,附带下载能力
- [x] 申请转账明细电子回单
1. `transferElectronic` 受理转账明细电子回单
2. `queryTransferElectronicResult` 查询转账账单电子回单接口
### 普通支付-直连模式API
##### 分账
`WechatDirectPayApi`是微信基础支付工具-[普通支付-直连模式API](https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/transactions.shtml)的封装。
- [x] `WechatProfitsharingApi` 分账,通过`WechatApiProvider#profitsharingApi`初始化
- [x] `profitsharingOrders` 请求分账
- [x] `queryProfitsharingOrder` 查询分账结果
- [x] `returnOrders` 请求分账回退
- [x] `queryReturnOrders` 查询分账回退结果
- [x] `unfreeze` 解冻剩余资金
- [x] `queryAmounts` 查询剩余待分金额
- [x] `addReceivers` 添加分账接收方
- [x] `deleteReceivers` 删除分账接收方
- [x] `downloadMerchantBills` 申请分账账单
#### APP下单API
#### 风险合规
`WechatResponseEntity<ObjectNode> appPay(PayParams payParams)`
##### 消费者投诉2.0
#### JSAPI/小程序下单API
- [ ] 功能实现中……
`WechatResponseEntity<ObjectNode> jsPay(PayParams payParams)`
#### 其它能力
#### Native下单API
##### 清关报关
`WechatResponseEntity<ObjectNode> nativePay(PayParams payParams)`
- [ ] 清关报关 暂时没有V3接口可通过payment spring boot 提供的V2扩展功能自行实现。
#### H5下单API
##### 媒体上传
`WechatResponseEntity<ObjectNode> h5Pay(PayParams payParams)`
> 包含图片上传和视频上传
#### 微信支付订单号查询API
- [x] `WechatMediaApi` 媒体上传,通过`WechatApiProvider#mediaApi`初始化
- [x] `mediaImageUpload` 图片上传
- [x] `mediaVideoUpload` 视频上传
- [x] `marketingImageUpload` 营销图片上传
`WechatResponseEntity<ObjectNode> queryTransactionById(TransactionQueryParams params)`
> 通过营销**图片上传API**上传图片后可获得图片url地址。图片url可在微信支付营销相关的API使用包括商家券、代金券、支付有礼等。
#### 商户订单号查询API
### 服务商
`WechatResponseEntity<ObjectNode> queryTransactionByOutTradeNo(TransactionQueryParams params)`
#### 关单API
`WechatResponseEntity<ObjectNode> close(String outTradeNo)`
### 回调API
所有需要回调处理的微信支付业务通过`WechatPayCallback`来进行处理。
#### 微信支付代金券核销回调API
`Map<String, ?> couponCallback(ResponseSignVerifyParams params, Consumer<CouponConsumeData> couponConsumeDataConsumer)`
#### 微信支付普通支付回调API
`Map<String, ?> transactionCallback(ResponseSignVerifyParams params, Consumer<TransactionConsumeData> couponConsumeDataConsumer)`
施工中……

View File

@@ -1,15 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2019-2022 felord.cn
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~ Website:
~ https://felord.cn
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.13.RELEASE</version>
<version>1.0.20.RELEASE</version>
</parent>
<artifactId>payment-spring-boot-autoconfigure</artifactId>
<version>1.0.13.RELEASE</version>
<version>1.0.20.RELEASE</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -75,4 +92,4 @@
</plugin>
</plugins>
</build>
</project>
</project>

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.alipay;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.alipay;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.autoconfigure;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,12 +13,12 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.autoconfigure;
import cn.felord.payment.alipay.AliPayConfiguration;
import cn.felord.payment.wechat.WechatPayConfiguration;
import cn.felord.payment.wechat.WechatTenantServiceConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -28,6 +27,6 @@ import org.springframework.context.annotation.Import;
* @since 1.0.0.RELEASE
*/
@Configuration
@Import({WechatPayConfiguration.class, AliPayConfiguration.class})
@Import({WechatPayConfiguration.class, WechatTenantServiceConfiguration.class, AliPayConfiguration.class})
public class PayConfiguration {
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat;
import cn.felord.payment.wechat.v3.KeyPairFactory;
import cn.felord.payment.wechat.v3.WechatMetaBean;
import lombok.AllArgsConstructor;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 从配置文件中加载租户信息,默认实现,可被覆盖
*
* @author dax
* @since 2023/2/3 11:40
*/
@AllArgsConstructor
public class InMemoryWechatTenantService implements WechatTenantService {
private final WechatPayProperties wechatPayProperties;
private final ResourceLoader resourceLoader;
private final Set<WechatMetaBean> cache = new HashSet<>();
@Override
public Set<WechatMetaBean> loadTenants() {
if (CollectionUtils.isEmpty(cache)) {
Map<String, WechatPayProperties.V3> v3Map = wechatPayProperties.getV3();
KeyPairFactory keyPairFactory = new KeyPairFactory();
Set<WechatMetaBean> beans = v3Map.entrySet()
.stream()
.map(entry -> {
WechatPayProperties.V3 v3 = entry.getValue();
String tenantId = entry.getKey();
String certPath = v3.getCertPath();
String certAbsolutePath = v3.getCertAbsolutePath();
String mchId = v3.getMchId();
Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) :
resourceLoader.getResource(certPath == null ? "classpath:wechat/apiclient_cert.p12" :
certPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? certPath : ResourceUtils.CLASSPATH_URL_PREFIX + certPath);
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
wechatMetaBean.setV3(v3);
wechatMetaBean.setTenantId(tenantId);
return wechatMetaBean;
})
.collect(Collectors.toSet());
cache.addAll(beans);
}
return cache;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,20 +13,18 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat;
import cn.felord.payment.wechat.v3.*;
import cn.felord.payment.wechat.v3.SignatureProvider;
import cn.felord.payment.wechat.v3.WechatApiProvider;
import cn.felord.payment.wechat.v3.WechatMetaContainer;
import cn.felord.payment.wechat.v3.WechatPayClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* The type Wechat pay configuration.
*
@@ -35,37 +32,18 @@ import java.util.Map;
* @since 1.0.0.RELEASE
*/
@Configuration(proxyBeanMethods = false)
@Conditional(WechatPayConfiguredCondition.class)
@EnableConfigurationProperties(WechatPayProperties.class)
public class WechatPayConfiguration {
/**
* The constant CERT_ALIAS.
*/
private static final String CERT_ALIAS = "Tenpay Certificate";
/**
* 微信支付公私钥 以及序列号等元数据.
*
* @param wechatPayProperties the wechat pay properties
* @param wechatTenantService the wechat tenant service
* @return the wechat cert bean
*/
@Bean
@ConditionalOnMissingBean
WechatMetaContainer wechatMetaContainer(WechatPayProperties wechatPayProperties) {
Map<String, WechatPayProperties.V3> v3Map = wechatPayProperties.getV3();
WechatMetaContainer container = new WechatMetaContainer();
KeyPairFactory keyPairFactory = new KeyPairFactory();
v3Map.keySet().forEach(tenantId -> {
WechatPayProperties.V3 v3 = v3Map.get(tenantId);
String certPath = v3.getCertPath();
String mchId = v3.getMchId();
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(certPath, CERT_ALIAS, mchId);
wechatMetaBean.setV3(v3);
wechatMetaBean.setTenantId(tenantId);
container.addWechatMeta(tenantId, wechatMetaBean);
});
return container;
WechatMetaContainer wechatMetaContainer(WechatTenantService wechatTenantService) {
return new WechatMetaContainer(wechatTenantService);
}
/**

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat;
@@ -70,6 +68,10 @@ public class WechatPayProperties {
* wechat pay certificate Path
*/
private String certPath;
/**
* wechat pay absolute certificate Path
*/
private String certAbsolutePath;
/**
* your pay server domain
*/

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat;

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat;
import cn.felord.payment.wechat.v3.WechatMetaBean;
import java.util.Set;
/**
* 加载租户信息服务
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
@FunctionalInterface
public interface WechatTenantService {
Set<WechatMetaBean> loadTenants();
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
/**
* The type Wechat tenant service configuration.
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
@Configuration(proxyBeanMethods = false)
@Conditional(WechatPayConfiguredCondition.class)
@EnableConfigurationProperties(WechatPayProperties.class)
public class WechatTenantServiceConfiguration {
/**
* Wechat tenant service wechat tenant service.
*
* @param wechatPayProperties the wechat pay properties
* @return the wechat tenant service
*/
@Bean
@ConditionalOnMissingBean
public WechatTenantService wechatTenantService(WechatPayProperties wechatPayProperties, ResourceLoader resourceLoader) {
return new InMemoryWechatTenantService(wechatPayProperties, resourceLoader);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Activity status.
*
* @author dax
* @since 1.0.19.RELEASE
*/
public enum ActivityStatus {
/**
* 状态未知
*/
ACT_STATUS_UNKNOWN,
/**
* 已创建
*/
CREATE_ACT_STATUS,
/**
* 运行中
*/
ONGOING_ACT_STATUS,
/**
* 已终止
*/
TERMINATE_ACT_STATUS,
/**
* 已暂停
*/
STOP_ACT_STATUS,
/**
* 已过期
*/
OVER_TIME_ACT_STATUS,
/**
* 创建活动失败
*/
CREATE_ACT_FAILED
}

View File

@@ -15,11 +15,17 @@
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model;
package cn.felord.payment.wechat.enumeration;
/**
* @author felord.cn
* @since 1.0.4.RELEASE
* The enum Award type.
*
* @author dax
* @since 1.0.19.RELEASE
*/
public class RefundQueryModel {
public enum AwardType {
/**
* 商家券
*/
BUSIFAVOR
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Business cert type.
*
* @author dax
* @since 2023 /7/1 8:34
*/
public enum BusinessCertType {
/**
* 事业单位法人证书
*/
CERTIFICATE_TYPE_2388,
/**
* 统一社会信用代码证书
*/
CERTIFICATE_TYPE_2389,
/**
* 社会团体法人登记证书
*/
CERTIFICATE_TYPE_2394,
/**
* 民办非企业单位登记证书
*/
CERTIFICATE_TYPE_2395,
/**
* 基金会法人登记证书
*/
CERTIFICATE_TYPE_2396,
/**
* 宗教活动场所登记证
*/
CERTIFICATE_TYPE_2399,
/**
* 政府部门下发的其他有效证明文件
*/
CERTIFICATE_TYPE_2400,
/**
* 执业许可证/执业证
*/
CERTIFICATE_TYPE_2520,
/**
* 基层群众性自治组织特别法人统一社会信用代码证
*/
CERTIFICATE_TYPE_2521,
/**
* 农村集体经济组织登记证
*/
CERTIFICATE_TYPE_2522
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Business type.
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
public enum BusinessType {
/**
* 代金券批次(暂不支持合作方为商户的场景)
*/
FAVOR_STOCK,
/**
* 商家券批次
*/
BUSIFAVOR_STOCK
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 超级管理员类型
*
* @since 1.0.14.RELEASE
*/
public enum ContactType {
/**
* 经营者或者法人
* <p>
* 主体为个体工商户/企业/政府机关/事业单位/社会组织
*/
LEGAL,
/**
* 经办人
* <p>
* 经商户授权办理微信支付业务的人员
*/
SUPER
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,42 +28,57 @@ public enum CouponBgColor {
/**
* Color 010 coupon bg color.
*/
Color010,
COLOR010("Color010"),
/**
* Color 020 coupon bg color.
* COLOR 020 coupon bg color.
*/
Color020,
COLOR020("Color010"),
/**
* Color 030 coupon bg color.
* COLOR 030 coupon bg color.
*/
Color030,
COLOR030("Color010"),
/**
* Color 040 coupon bg color.
* COLOR 040 coupon bg color.
*/
Color040,
COLOR040("Color010"),
/**
* Color 050 coupon bg color.
* COLOR 050 coupon bg color.
*/
Color050,
COLOR050("Color010"),
/**
* Color 060 coupon bg color.
* COLOR 060 coupon bg color.
*/
Color060,
COLOR060("Color010"),
/**
* Color 070 coupon bg color.
* COLOR 070 coupon bg color.
*/
Color070,
COLOR070("Color010"),
/**
* Color 080 coupon bg color.
* COLOR 080 coupon bg color.
*/
Color080,
COLOR080("Color010"),
/**
* Color 090 coupon bg color.
* COLOR 090 coupon bg color.
*/
Color090,
COLOR090("Color010"),
/**
* Color 100 coupon bg color.
* COLOR 100 coupon bg color.
*/
Color100
COLOR100("Color010");
private final String value;
CouponBgColor(String value) {
this.value = value;
}
/**
* Gets value.
*
* @return the value
*/
public String getValue() {
return value;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Delivery purpose.
*
* @author felord.cn
* @since 1.0.19.RELEASE
*/
public enum DeliveryPurpose {
/**
* 拉用户回店消费
*/
OFF_LINE_PAY,
/**
* 引导用户前往小程序消费
*/
JUMP_MINI_APP
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* @author dax
* @since 1.0.19.RELEASE
*/
public enum DeliveryUserCategory {
/**
* 所有用户
*/
DELIVERY_ALL_PERSON,
/**
* 会员用户
*/
DELIVERY_MEMBER_PERSON
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 金融机构类型需与营业执照/登记证书上一致,可参考选择 <a href="https://kf.qq.com/faq/220215IrMRZ3220215n6buiU.html">金融机构指引</a>。
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public enum FinanceType {
/**
* 银行业, 适用于商业银行、政策性银行、农村合作银行、村镇银行、开发性金融机构等
*/
BANK_AGENT,
/**
* 支付机构, 适用于非银行类支付机构
*/
PAYMENT_AGENT,
/**
* 保险业, 适用于保险、保险中介、保险代理、保险经纪等保险类业务
*/
INSURANCE,
/**
* 交易及结算类金融机构, 适用于交易所、登记结算类机构、银行卡清算机构、资金清算中心等
*/
TRADE_AND_SETTLE,
/**
* 其他金融机构, 适用于财务公司、信托公司、金融资产管理公司、金融租赁公司、汽车金融公司、贷款公司、货币经纪公司、消费金融公司、证券业、金融控股公司、股票、期货、货币兑换、小额贷款公司、金融资产管理、担保公司、商业保理公司、典当行、融资租赁公司、财经咨询等其他金融业务
*/
OTHER
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 超级管理员证件类型
* <p>
* 当超级管理员类型是经办人时,请上传超级管理员证件类型。
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public enum IdDocType {
/**
* 中国大陆居民-身份证
*/
IDENTIFICATION_TYPE_IDCARD,
/**
* 其他国家或地区居民-护照
*/
IDENTIFICATION_TYPE_OVERSEA_PASSPORT,
/**
* 中国香港居民-来往内地通行证
*/
IDENTIFICATION_TYPE_HONGKONG_PASSPORT,
/**
* 中国澳门居民-来往内地通行证
*/
IDENTIFICATION_TYPE_MACAO_PASSPORT,
/**
* 中国台湾居民-来往大陆通行证
*/
IDENTIFICATION_TYPE_TAIWAN_PASSPORT,
/**
* 外国人居留证
*/
IDENTIFICATION_TYPE_FOREIGN_RESIDENT,
/**
* 港澳居民证
*/
IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT,
/**
* 台湾居民证
*/
IDENTIFICATION_TYPE_TAIWAN_RESIDENT
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Partner type.
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
public enum PartnerType {
/**
* 合作方为APPID
*/
APPID,
/**
* 合作方为商户
*/
MERCHANT
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 合作状态
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
public enum PartnershipState {
/**
* 已建立合作状态
*/
ESTABLISHED,
/**
* 已终止合作状态
*/
TERMINATED
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 felord.cn
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Send content.
*
* @author dax
* @since 1.0.19.RELEASE
*/
public enum SendContent {
/**
* 单张券
*/
SINGLE_COUPON,
/**
* 礼包
*/
GIFT_PACKAGE
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 营业执照/登记证书、经营者/法人的证件的主体类型
*
* @author felord.cn
* @see <a href="https://kf.qq.com/faq/180910IBZVnQ180910naQ77b.html">主体类型指引</a>
* @since 1.0.14.RELEASE
*/
public enum SubjectType {
/**
* 个体户
* <p>
* 营业执照上的主体类型一般为个体户、个体工商户、个体经营;
*/
SUBJECT_TYPE_INDIVIDUAL,
/**
* 小微商户
*/
SUBJECT_TYPE_MICRO,
/**
* 企业
* <p>
* 营业执照上的主体类型一般为有限公司、有限责任公司;
*/
SUBJECT_TYPE_ENTERPRISE,
/**
* 政府机关
* <p>
* 包括各级、各类政府机关,如机关党委、税务、民政、人社、工商、商务、市监等;
*/
SUBJECT_TYPE_GOVERNMENT,
/**
* 事业单位
* <p>
* 包括国内各类事业单位,如:医疗、教育、学校等单位;
*/
SUBJECT_TYPE_INSTITUTIONS,
/**
* 社会组织
* <p>
* 包括社会团体、民办非企业、基金会、基层群众性自治组织、农村集体经济组织等组织
*/
SUBJECT_TYPE_OTHERS
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
import lombok.Getter;
/**
* @author dax
* @since 2023/2/1 8:59
*/
@Getter
public enum WechatPayAlgorithms {
RSA("WECHATPAY2-SHA256-RSA2048"),
SM3("WECHATPAY2-SM2-WITH-SM3");
private final String algorithm;
WechatPayAlgorithms(String algorithm) {
this.algorithm = algorithm;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.enumeration;
@@ -54,7 +52,18 @@ public enum WechatPayV3Type {
* @since 1.0.3.RELEASE
*/
FUND_FLOW_BILL(HttpMethod.GET, "%s/v3/bill/fundflowbill"),
/**
* 图片上传API.
*
* @since 1.0.14.RELEASE
*/
MERCHANT_MEDIA_IMG(HttpMethod.POST, "%s/v3/merchant/media/upload"),
/**
* 视频上传API.
*
* @since 1.0.14.RELEASE
*/
MERCHANT_MEDIA_VIDEO(HttpMethod.POST, "%s/v3/merchant/media/video_upload"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
@@ -449,11 +458,11 @@ public enum WechatPayV3Type {
*/
MARKETING_BUSI_FAVOR_DISASSOCIATE(HttpMethod.POST, "%s/v3/marketing/busifavor/coupons/disassociate"),
/**
* 取消关联订单信息API.
* 修改批次预算API.
*
* @since 1.0.4.RELEASES
*/
MARKETING_BUSI_FAVOR_BUDGET(HttpMethod.POST, "%s/v3/marketing/busifavor/stocks/{stock_id}/budget"),
MARKETING_BUSI_FAVOR_BUDGET(HttpMethod.PATCH, "%s/v3/marketing/busifavor/stocks/{stock_id}/budget"),
/**
* 修改商家券基本信息API.
*
@@ -485,6 +494,69 @@ public enum WechatPayV3Type {
*/
MARKETING_BUSI_FAVOR_SUBSIDY_QUERY(HttpMethod.GET, "%s/v3/marketing/busifavor/subsidy/pay-receipts/{subsidy_receipt_id}"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 建立合作关系API.
*
* @since 1.0.16.RELEASES
*/
MARKETING_PARTNERSHIPS_BUILD(HttpMethod.POST, "%s/v3/marketing/partnerships/build"),
/**
* 查询合作关系列表API.
*
* @since 1.0.16.RELEASES
*/
MARKETING_PARTNERSHIPS_GET(HttpMethod.GET, "%s/v3/marketing/partnerships"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 创建全场满额送活动API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY(HttpMethod.POST, "%s/v3/marketing/paygiftactivity/unique-threshold-activity"),
/**
* 查询活动详情接口API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_DETAIL(HttpMethod.GET, "%s/v3/marketing/paygiftactivity/activities/{activity_id}"),
/**
* 查询活动发券商户号API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_MCH(HttpMethod.GET, "%s/v3/marketing/paygiftactivity/activities/{activity_id}/merchants"),
/**
* 查询活动指定商品列表API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_GOODS(HttpMethod.GET, "%s/v3/marketing/paygiftactivity/activities/{activity_id}/goods"),
/**
* 终止活动API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_TERMINATE(HttpMethod.POST, "%s/v3/marketing/paygiftactivity/activities/{activity_id}/terminate"),
/**
* 新增活动发券商户号API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_MCH_ADD(HttpMethod.POST, "%s/v3/marketing/paygiftactivity/activities/{activity_id}/merchants/add"),
/**
* 获取支付有礼活动列表API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_ACTIVITIES(HttpMethod.GET, "%s/v3/marketing/paygiftactivity/activities"),
/**
* 删除活动发券商户号API
*
* @since 1.0.19.RELEASES
*/
MARKETING_PAYGIFTACTIVITY_MCH_DEL(HttpMethod.POST, "%s/v3/marketing/paygiftactivity/activities/{activity_id}/merchants/delete"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 发起批量转账API.
*
@@ -668,7 +740,413 @@ public enum WechatPayV3Type {
*
* @since 1.0.13.RELEASE
*/
PROFITSHARING_BILLS(HttpMethod.GET, "%s/v3/profitsharing/bills");
PROFITSHARING_BILLS(HttpMethod.GET, "%s/v3/profitsharing/bills"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 请求品牌分账API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_ORDERS(HttpMethod.POST, "%s/v3/brand/profitsharing/orders"),
/**
* 查询品牌分账结果API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_RESULT(HttpMethod.GET, "%s/v3/brand/profitsharing/orders"),
/**
* 请求品牌分账回退API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_RETURN_ORDERS(HttpMethod.POST, "%s/v3/brand/profitsharing/returnorders"),
/**
* 查询品牌分账回退结果API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/brand/profitsharing/returnorders"),
/**
* 完结品牌分账API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_FINISH_ORDER(HttpMethod.POST, "%s/v3/brand/profitsharing/finish-order"),
/**
* 查询订单剩余待分金额API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_ORDER_AMOUNTS(HttpMethod.GET, "%s/v3/brand/profitsharing/orders/{transaction_id}/amounts"),
/**
* 查询最大分账比例API.
*
* @since 1.0.15.RELEASE
*/
BRAND_CONFIGS(HttpMethod.GET, "%s/v3/brand/profitsharing/brand-configs/{brand_mchid}"),
/**
* 添加品牌分账接收方API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_RECEIVERS_ADD(HttpMethod.POST, "%s/v3/brand/profitsharing/receivers/add"),
/**
* 删除分账接收方API.
*
* @since 1.0.15.RELEASE
*/
BRAND_PROFITSHARING_RECEIVERS_DELETE(HttpMethod.POST, "%s/v3/brand/profitsharing/receivers/delete"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 服务商-商户进件-特约商户进件-提交申请单API.
*
* @since 1.0.14.RELEASE
*/
SPEC_MCH_APPLY_PARTNER(HttpMethod.POST, "%s/v3/applyment4sub/applyment/"),
/**
* 服务商-商户进件-特约商户进件-通过业务申请编号查询申请状态API.
*
* @since 1.0.14.RELEASE
*/
SPEC_MCH_APPLY_QUERY_BUSINESS_CODE(HttpMethod.GET, "%s/v3/applyment4sub/applyment/business_code/{business_code}"),
/**
* 服务商-商户进件-特约商户进件-通过申请单号查询申请状态API.
*
* @since 1.0.14.RELEASE
*/
SPEC_MCH_APPLY_QUERY_APPLYMENT_ID(HttpMethod.GET, "%s/v3/applyment4sub/applyment/applyment_id/{applyment_id}"),
/**
* 服务商-商户进件-特约商户进件-修改结算账号API.
*
* @since 1.0.14.RELEASE
*/
SPEC_MCH_SUB_MODIFY(HttpMethod.POST, "%s/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement"),
/**
* 服务商-商户进件-特约商户进件-查询结算账户API.
*
* @since 1.0.14.RELEASE
*/
SPEC_MCH_SUB_SETTLEMENT(HttpMethod.GET, "%s/v3/apply4sub/sub_merchants/{sub_mchid}/settlement"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 经营能力-支付即服务-服务人员注册API.
*
* @since 1.0.14.RELEASE
*/
SMART_GUIDES(HttpMethod.POST, "%s/v3/smartguide/guides"),
/**
* 经营能力-支付即服务-服务人员分配API.
*
* @since 1.0.14.RELEASE
*/
SMART_GUIDES_ASSIGN(HttpMethod.POST, "%s/v3/smartguide/guides/{guide_id}/assign"),
/**
* 经营能力-支付即服务-服务人员查询API.
*
* @since 1.0.14.RELEASE
*/
SMART_GUIDES_GET(HttpMethod.GET, "%s/v3/smartguide/guides"),
/**
* 经营能力-支付即服务-服务人员查询API.
*
* @since 1.0.14.RELEASE
*/
SMART_GUIDES_MODIFY(HttpMethod.PATCH, "%s/v3/smartguide/guides/{guide_id}"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 经营能力-点金计划-点金计划管理API.
*
* @since 1.0.14.RELEASE
*/
GOLD_PLAN_CHANGE(HttpMethod.POST, "%s/v3/goldplan/merchants/changegoldplanstatus"),
/**
* 经营能力-点金计划-商家小票管理API.
*
* @since 1.0.14.RELEASE
*/
GOLD_PLAN_CHANGE_CUSTOM(HttpMethod.POST, "%s/v3/goldplan/merchants/changecustompagestatus"),
/**
* 经营能力-点金计划-同业过滤标签管理API.
*
* @since 1.0.14.RELEASE
*/
GOLD_PLAN_FILTER(HttpMethod.POST, "%s/v3/goldplan/merchants/set-advertising-industry-filter"),
/**
* 经营能力-点金计划-开通广告展示API.
*
* @since 1.0.14.RELEASE
*/
GOLD_PLAN_ADV_OPEN(HttpMethod.POST, "%s/v3/goldplan/merchants/open-advertising-show"),
/**
* 经营能力-点金计划-关闭广告展示API.
*
* @since 1.0.14.RELEASE
*/
GOLD_PLAN_ADV_CLOSE(HttpMethod.POST, "%s/v3/goldplan/merchants/close-advertising-show"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 行业方案-电商收付通-商户进件-二级商户进件申请API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_APPLYMENT(HttpMethod.POST, "%s/v3/ecommerce/applyments/"),
/**
* 行业方案-电商收付通-商户进件-查询申请状态-通过申请单ID查询申请状态API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_APPLYMENT_ID(HttpMethod.GET, "%s/v3/ecommerce/applyments/{applyment_id}"),
/**
* 行业方案-电商收付通-商户进件-查询申请状态-通过业务申请编号查询申请状态API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_APPLYMENT_OUT_REQUEST_NO(HttpMethod.GET, "%s/v3/ecommerce/applyments/out-request-no/{out_request_no}"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 行业方案-电商收付通-分账-请求分账API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_ORDERS(HttpMethod.POST, "%s/v3/ecommerce/profitsharing/orders"),
/**
* 行业方案-电商收付通-分账-查询分账结果API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_RESULT(HttpMethod.GET, "%s/v3/ecommerce/profitsharing/orders"),
/**
* 行业方案-电商收付通-分账-请求分账回退API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_RETURN_ORDERS(HttpMethod.POST, "%s/v3/ecommerce/profitsharing/returnorders"),
/**
* 行业方案-电商收付通-分账-查询分账回退结果API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/ecommerce/profitsharing/returnorders"),
/**
* 行业方案-电商收付通-分账-完结分账API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_FINISH_ORDER(HttpMethod.POST, "%s/v3/ecommerce/profitsharing/finish-order"),
/**
* 行业方案-电商收付通-分账-查询订单剩余待分金额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_ORDER_AMOUNTS(HttpMethod.GET, "%s/v3/ecommerce/profitsharing/orders/{transaction_id}/amounts"),
/**
* 行业方案-电商收付通-分账-添加分账接收方API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_RECEIVERS_ADD(HttpMethod.POST, "%s/v3/ecommerce/profitsharing/receivers/add"),
/**
* 行业方案-电商收付通-分账-删除分账接收方API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_PROFITSHARING_RECEIVERS_DELETE(HttpMethod.POST, "%s/v3/ecommerce/profitsharing/receivers/delete"),
/**
* 行业方案-电商收付通-补差-请求补差API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_SUBSIDIES_CREATE(HttpMethod.POST, "%s/v3/ecommerce/subsidies/create"),
/**
* 行业方案-电商收付通-补差-请求补差回退API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_SUBSIDIES_RETURN(HttpMethod.POST, "%s/v3/ecommerce/subsidies/return"),
/**
* 行业方案-电商收付通-补差-取消补差API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_SUBSIDIES_CANCEL(HttpMethod.POST, "%s/v3/ecommerce/subsidies/cancel"),
/**
* 行业方案-电商收付通-退款-申请退款API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_REFUNDS_APPLY(HttpMethod.POST, "%s/v3/ecommerce/refunds/apply"),
/**
* 行业方案-电商收付通-退款-查询退款API-通过微信支付退款单号查询退款.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_REFUNDS_ID(HttpMethod.GET, "%s/v3/ecommerce/refunds/id/{refund_id}"),
/**
* 行业方案-电商收付通-退款-查询退款API-通过商户退款单号查询退款.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_REFUNDS_OUT_REFUND_NO(HttpMethod.GET, "%s/v3/ecommerce/refunds/out-refund-no/{out_refund_no}"),
/**
* 行业方案-电商收付通-退款-垫付退款回补API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_REFUNDS_RETURN_ADVANCE(HttpMethod.POST, "%s/v3/ecommerce/refunds/{refund_id}/return-advance"),
/**
* 行业方案-电商收付通-退款-查询垫付回补结果API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_REFUNDS_RETURN_ADVANCE_RESULT(HttpMethod.GET, "%s/v3/ecommerce/refunds/{refund_id}/return-advance"),
/**
* 行业方案-电商收付通-余额查询-查询二级商户账户实时余额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_BALANCE_REAL_TIME(HttpMethod.GET, "%s/v3/ecommerce/fund/balance/{sub_mchid}"),
/**
* 行业方案-电商收付通-余额查询-查询二级商户账户日终余额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_BALANCE_END_DAY(HttpMethod.GET, "%s/v3/ecommerce/fund/enddaybalance/{sub_mchid}"),
/**
* 行业方案-电商收付通-余额查询-查询电商平台账户实时余额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_BALANCE_TYPE_REAL_TIME(HttpMethod.GET, "%s/v3/merchant/fund/balance/{account_type}"),
/**
* 行业方案-电商收付通-余额查询-查询电商平台账户日终余额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_BALANCE_TYPE_END_DAY(HttpMethod.GET, "%s/v3/merchant/fund/dayendbalance/{account_type}"),
/**
* 行业方案-电商收付通-商户提现-二级商户预约提现.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_WITHDRAW(HttpMethod.POST, "%s/v3/ecommerce/fund/withdraw"),
/**
* 行业方案-电商收付通-商户提现-二级商户查询预约提现状态API-微信支付预约提现单号查询.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_WITHDRAW_ID(HttpMethod.GET, "%s/v3/ecommerce/fund/withdraw/{withdraw_id}"),
/**
* 行业方案-电商收付通-商户提现-二级商户查询预约提现状态API-商户预约提现单号查询.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_WITHDRAW_OUT_REQUEST_NO(HttpMethod.GET, "%s/v3/ecommerce/fund/withdraw/out-request-no/{out_request_no}"),
/**
* 行业方案-电商收付通-商户提现-电商平台预约提现API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_MERCHANT_WITHDRAW(HttpMethod.POST, "%s/v3/merchant/fund/withdraw"),
/**
* 行业方案-电商收付通-商户提现-电商平台查询预约提现状态API-微信支付预约提现单号查询.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_MERCHANT_WITHDRAW_ID(HttpMethod.GET, "%s/v3/merchant/fund/withdraw/withdraw-id/{withdraw_id}"),
/**
* 行业方案-电商收付通-商户提现-电商平台查询预约提现状态API-商户预约提现单号查询.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_WITHDRAW_MERCHANT_OUT_REQUEST_NO(HttpMethod.GET, "%s/v3/merchant/fund/withdraw/out-request-no/{out_request_no}"),
/**
* 行业方案-电商收付通-商户提现-按日下载提现异常文件API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_WITHDRAW_ERROR_BILL(HttpMethod.GET, "%s/v3/merchant/fund/withdraw/bill-type/{bill_type}"),
/**
* 行业方案-电商收付通-下载账单-申请二级商户资金账单API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_FLOW_BILL(HttpMethod.GET, "%s/v3/ecommerce/bill/fundflowbill"),
/**
* 行业方案-电商收付通-跨境付款-查询订单剩余可出境余额API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_OVERSEA_BALANCE(HttpMethod.GET, "%s/v3/funds-to-oversea/transactions/{transaction_id}/available_abroad_amounts"),
/**
* 行业方案-电商收付通-跨境付款-申请资金出境API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_OVERSEA_ORDERS(HttpMethod.POST, "%s/v3/funds-to-oversea/orders"),
/**
* 行业方案-电商收付通-跨境付款-查询出境结果API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_OVERSEA_ORDERS_RESULT(HttpMethod.GET, "%s/v3/funds-to-oversea/orders/{out_order_id}"),
/**
* 行业方案-电商收付通-跨境付款-获取购付汇账单文件下载链接API.
*
* @since 1.0.14.RELEASE
*/
ECOMMERCE_FUND_OVERSEA_BILLS(HttpMethod.GET, "%s/v3/funds-to-oversea/bill-download-url"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 智慧商圈-商圈积分同步API
*
* @since 1.0.14.RELEASE
*/
MALL_SCORE_SYNC(HttpMethod.POST, "%s/v3/businesscircle/points/notify"),
/**
* 智慧商圈-商圈积分同步API
*
* @since 1.0.14.RELEASE
*/
MALL_SCORE_RESULT(HttpMethod.GET, "%s/v3/businesscircle/user-authorizations/{openid}"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 获取对私银行卡号开户银行API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_SEARCH(HttpMethod.GET, "%s/v3/capital/capitallhh/banks/search-banks-by-bank-account"),
/**
* 查询支持个人业务的银行列表API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_PERSONAL(HttpMethod.GET, "%s/v3/capital/capitallhh/banks/personal-banking"),
/**
* 查询支持对公业务的银行列表API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_CORPORATE(HttpMethod.GET, "%s/v3/capital/capitallhh/banks/corporate-banking"),
/**
* 查询省份列表API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_PROVINCES(HttpMethod.GET, "%s/v3/capital/capitallhh/areas/provinces"),
/**
* 查询城市列表API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_CITIES(HttpMethod.GET, "%s/v3/capital/capitallhh/areas/provinces/{province_code}/cities"),
/**
* 查询支行列表API
*
* @since 1.0.14.RELEASE
*/
CAPITAL_BRANCHES(HttpMethod.GET, "%s/v3/capital/capitallhh/banks/{bank_alias_code}/branches");
/**
* The Pattern.
*

View File

@@ -1,249 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.v2.model.BaseModel;
import cn.felord.payment.wechat.v2.model.allocation.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import java.util.List;
/**
* 微信支付分账
* <p>
*
* @author felord.cn
* @since 1.0.10.RELEASE
*/
@Slf4j
public class WechatAllocationApi {
/**
* The constant MAPPER.
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
.registerModule(new JavaTimeModule());
}
private final WechatV2Client wechatV2Client;
/**
* Instantiates a new Wechat allocation api.
*
* @param wechatV2Client the wechat v 2 client
*/
public WechatAllocationApi(WechatV2Client wechatV2Client) {
this.wechatV2Client = wechatV2Client;
}
/**
* 请求单次分账
*
* @param profitSharingModel the profit sharing model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharing(ProfitSharingModel profitSharingModel) {
ProfitSharingSModel model = new ProfitSharingSModel();
List<Receiver> receivers = profitSharingModel.getReceivers();
model.setReceivers(MAPPER.writeValueAsString(receivers));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
model.setAppid(v3.getAppId());
model.setMchId(v3.getMchId());
model.setTransactionId(profitSharingModel.getTransactionId());
model.setOutOrderNo(profitSharingModel.getOutOrderNo());
model.certPath(v3.getCertPath());
model.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(model,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharing");
}
/**
* 请求单次分账
*
* @param multiProfitSharingModel the multi profit sharing model
* @return json node
*/
@SneakyThrows
public JsonNode multiProfitSharing(MultiProfitSharingModel multiProfitSharingModel) {
MultiProfitSharingSModel multiProfitSharingSModel = new MultiProfitSharingSModel();
List<Receiver> receivers = multiProfitSharingModel.getReceivers();
multiProfitSharingSModel.setReceivers(MAPPER.writeValueAsString(receivers));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
multiProfitSharingSModel.setAppid(v3.getAppId());
multiProfitSharingSModel.setMchId(v3.getMchId());
multiProfitSharingSModel.setTransactionId(multiProfitSharingModel.getTransactionId());
multiProfitSharingSModel.setOutOrderNo(multiProfitSharingModel.getOutOrderNo());
multiProfitSharingSModel.certPath(v3.getCertPath());
multiProfitSharingSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(multiProfitSharingSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/multiprofitsharing");
}
/**
* 查询分账结果
*
* @param profitSharingQueryModel the profit sharing query model
* @return json node
*/
public JsonNode profitSharingQuery(ProfitSharingQueryModel profitSharingQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingQueryModel.setMchId(v3.getMchId());
profitSharingQueryModel.certPath(v3.getCertPath());
profitSharingQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingquery");
}
/**
* 添加分账接收方
*
* @param profitSharingAddReceiverModel the profit sharing add receiver model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharingAddReceiver(ProfitSharingAddReceiverModel profitSharingAddReceiverModel) {
ProfitSharingAddReceiverSModel profitSharingAddReceiverSModel = new ProfitSharingAddReceiverSModel();
ProfitSharingAddReceiverModel.Receiver receiver = profitSharingAddReceiverModel.getReceiver();
profitSharingAddReceiverSModel.setReceiver(MAPPER.writeValueAsString(receiver));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingAddReceiverSModel.setAppid(v3.getAppId());
profitSharingAddReceiverSModel.setMchId(v3.getMchId());
profitSharingAddReceiverSModel.certPath(v3.getCertPath());
profitSharingAddReceiverSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingAddReceiverSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver");
}
/**
* 删除分账接收方
*
* @param profitSharingRemoveReceiverModel the profit sharing remove receiver model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharingRemoveReceiver(ProfitSharingRemoveReceiverModel profitSharingRemoveReceiverModel) {
ProfitSharingRemoveReceiverSModel profitSharingRemoveReceiverSModel = new ProfitSharingRemoveReceiverSModel();
ProfitSharingRemoveReceiverModel.Receiver receiver = profitSharingRemoveReceiverModel.getReceiver();
profitSharingRemoveReceiverSModel.setReceiver(MAPPER.writeValueAsString(receiver));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingRemoveReceiverSModel.setAppid(v3.getAppId());
profitSharingRemoveReceiverSModel.setMchId(v3.getMchId());
profitSharingRemoveReceiverSModel.certPath(v3.getCertPath());
profitSharingRemoveReceiverSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingRemoveReceiverSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver");
}
/**
* 完结分账
*
* @param profitSharingFinishModel the profit sharing finish model
* @return json node
*/
public JsonNode profitSharingFinish(ProfitSharingFinishModel profitSharingFinishModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingFinishModel.setAppid(v3.getAppId());
profitSharingFinishModel.setMchId(v3.getMchId());
profitSharingFinishModel.certPath(v3.getCertPath());
profitSharingFinishModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingFinishModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish");
}
/**
* 查询订单待分账金额
*
* @param profitSharingOrderAmountQueryModel the profit sharing order amount query model
* @return json node
*/
public JsonNode profitSharingOrderAmountQuery(ProfitSharingOrderAmountQueryModel profitSharingOrderAmountQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingOrderAmountQueryModel.setMchId(v3.getMchId());
profitSharingOrderAmountQueryModel.certPath(v3.getCertPath());
profitSharingOrderAmountQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingOrderAmountQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingorderamountquery");
}
/**
* 分账回退
*
* @param profitSharingReturnModel the profit sharing return model
* @return json node
*/
public JsonNode profitSharingReturn(ProfitSharingReturnModel profitSharingReturnModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingReturnModel.setAppid(v3.getAppId());
profitSharingReturnModel.setMchId(v3.getMchId());
profitSharingReturnModel.certPath(v3.getCertPath());
profitSharingReturnModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingReturnModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn");
}
/**
* 回退结果查询
*
* @param profitSharingReturnQueryModel the profit sharing return query model
* @return json node
*/
public JsonNode profitSharingReturnQuery(ProfitSharingReturnQueryModel profitSharingReturnQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingReturnQueryModel.setAppid(v3.getAppId());
profitSharingReturnQueryModel.setMchId(v3.getMchId());
profitSharingReturnQueryModel.certPath(v3.getCertPath());
profitSharingReturnQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingReturnQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingreturnquery");
}
}

View File

@@ -42,6 +42,8 @@ public class WechatV2Client {
WechatPayProperties.V3 v3 = wechatMetaBean.getV3();
return model
.appSecret(v3.getAppSecret())
.certPath(v3.getCertPath())
.certAbsolutePath(v3.getCertAbsolutePath())
.request(v3.getMchId(), method, url);
}

View File

@@ -24,7 +24,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.Getter;
import lombok.SneakyThrows;
@@ -37,6 +37,8 @@ import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
@@ -79,11 +81,11 @@ public abstract class BaseModel {
// 忽略null
XML_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL)
// 属性使用 驼峰首字母小写
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
OBJECT_MAPPER
// .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
}
@@ -97,6 +99,8 @@ public abstract class BaseModel {
@JsonIgnore
private String certPath;
@JsonIgnore
private String certAbsolutePath;
@JsonIgnore
private String signType;
public BaseModel appSecret(String appSecret) {
@@ -109,6 +113,10 @@ public abstract class BaseModel {
return this;
}
public BaseModel certAbsolutePath(String certAbsolutePath) {
this.certAbsolutePath = certAbsolutePath;
return this;
}
public BaseModel signType(String signType) {
this.signType = signType;
@@ -211,8 +219,9 @@ public abstract class BaseModel {
private RestTemplate getRestTemplateClientAuthentication(String mchId)
throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException,
KeyStoreException, KeyManagementException {
ClassPathResource resource = new ClassPathResource(certPath == null ? "wechat/apiclient_cert.p12" : certPath);
Resource resource = certAbsolutePath != null ? new FileSystemResource(certAbsolutePath) :
new ClassPathResource(certPath == null ? "wechat/apiclient_cert.p12" : certPath);
char[] pem = mchId.toCharArray();
KeyStore store = KeyStore.getInstance("PKCS12");

View File

@@ -1,95 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing add receiver model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingAddReceiverModel extends BaseProfitSharingReceiverModel {
private Receiver receiver;
/**
* The type Receiver.
*/
@Data
public static class Receiver {
/**
* 分账接收方类型.
* <p>
* MERCHANT_ID商户号mch_id或者sub_mch_id
* PERSONAL_OPENID个人openid
*/
private Type type;
/**
* 分账接收方帐号.
* <p>
* 类型是MERCHANT_ID时是商户号mch_id或者sub_mch_id
* 类型是PERSONAL_OPENID时是个人openid
*/
private String account;
/**
* 分账接收方全称.
* <p>
* 分账接收方类型是MERCHANT_ID时是商户全称必传当商户是小微商户或个体户时是开户人姓名
* 分账接收方类型是PERSONAL_OPENID时是个人姓名选传传则校验
*/
private String name;
/**
* 与分账方的关系类型.
* <p>
* 子商户与接收方的关系。
* 本字段值为枚举:
* SERVICE_PROVIDER服务商
* STORE门店
* STAFF员工
* STORE_OWNER店主
* PARTNER合作伙伴
* HEADQUARTER总部
* BRAND品牌方
* DISTRIBUTOR分销商
* USER用户
* SUPPLIER供应商
* CUSTOM自定义
*/
private RelationType relationType;
/**
* 自定义的分账关系.
* <p>
* 子商户与接收方具体的关系本字段最多10个字。
* 当字段relation_type的值为CUSTOM时本字段必填
* 当字段relation_type的值不为CUSTOM时本字段无需填写
*/
private String customRelation;
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing finish model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingFinishModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
/**
* 商户分账单号.
* <p>
* 查询分账结果,输入申请分账时的商户分账单号; 查询分账完结执行的结果,输入发起分账完结时的商户分账单号
*/
private String outOrderNo;
/**
* 分账完结描述.
* <p>
* 分账完结的原因描述
*/
private String description;
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 单次分账请求按照传入的分账接收方账号和资金进行分账,同时会将订单剩余的待分账金额解冻给本商户。
* 故操作成功后,订单不能再进行分账,也不能进行分账完结。
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingModel extends BaseProfitSharingModel {
/**
* 分账接收方列表不超过50个json对象不能设置分账方作为分账接受方
*/
private List<Receiver> receivers;
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing query model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingQueryModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
/**
* 商户分账单号.
* <p>
* 查询分账结果,输入申请分账时的商户分账单号; 查询分账完结执行的结果,输入发起分账完结时的商户分账单号
*/
private String outOrderNo;
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing return model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingReturnModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
private String orderId;
private String outOrderNo;
private String outReturnNo;
private String returnAccountType;
private String returnAccount;
private String returnAmount;
private String description;
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing return query model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingReturnQueryModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
/**
* 微信分账订单号.
* <p>
* 原发起分账请求时,微信返回的微信分账单号,与商户分账单号一一对应。
* 微信分账单号与商户分账单号二选一填写
*/
private String orderId;
/**
* 商户分账单号.
* <p>
* 原发起分账请求时使用的商户系统内部的分账单号。
* 微信分账单号与商户分账单号二选一填写
*/
private String outOrderNo;
/**
* 商户回退单号.
* <p>
* 调用回退接口提供的商户系统内部的回退单号
*/
private String outReturnNo;
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
import lombok.Data;
/**
* The type Receiver.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@Data
public class Receiver {
/**
* 分账接收方类型.
* <p>
* MERCHANT_ID商户号mch_id或者sub_mch_id
* PERSONAL_OPENID个人openid
*/
private Type type;
/**
* 分账接收方帐号.
* <p>
* 类型是MERCHANT_ID时是商户号mch_id或者sub_mch_id
* 类型是PERSONAL_OPENID时是个人openid
*/
private String account;
/**
* 分账金额.
* <p>
* 单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
*/
private Integer amount;
/**
* 分账描述.
* <p>
* 分账的原因描述,分账账单中需要体现
*/
private String description;
/**
* 分账个人接收方姓名.
* <p>
* 可选项,在接收方类型为个人的时可选填,若有值,会检查与 name 是否实名匹配,不匹配会拒绝分账请求.
* 1、分账接收方类型是PERSONAL_OPENID时是个人姓名选传传则校验
*/
private String name;
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v2.model.allocation;
/**
* The enum Relation type.
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public enum RelationType {
/**
* Service provider relation type.
*/
SERVICE_PROVIDER,
/**
* Store relation type.
*/
STORE,
/**
* Staff relation type.
*/
STAFF,
/**
* Store owner relation type.
*/
STORE_OWNER,
/**
* Partner relation type.
*/
PARTNER,
/**
* Headquarter relation type.
*/
HEADQUARTER,
/**
* Brand relation type.
*/
BRAND,
/**
* Distributor relation type.
*/
DISTRIBUTOR,
/**
* User relation type.
*/
USER,
/**
* Supplier relation type.
*/
SUPPLIER,
/**
* Custom relation type.
*/
CUSTOM
}

View File

@@ -1,20 +0,0 @@
package cn.felord.payment.wechat.v2.model.allocation;
/**
* The enum Type.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public enum Type {
/**
* 商户号mch_id或者sub_mch_id
*/
MERCHANT_ID,
/**
* 个人openid
*/
PERSONAL_OPENID
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -30,9 +28,12 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
@@ -46,6 +47,8 @@ import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Optional;
@@ -94,13 +97,16 @@ public abstract class AbstractApi {
* @param mapper the mapper
*/
private void applyObjectMapper(ObjectMapper mapper) {
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE
)
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// empty string error
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(new JavaTimeModule());
.registerModule(javaTimeModule);
}
@@ -158,7 +164,8 @@ public abstract class AbstractApi {
*/
protected RequestEntity<?> Post(URI uri, Object params) {
try {
return RequestEntity.post(uri).header("Pay-TenantId", tenantId)
return RequestEntity.post(uri)
.header("Pay-TenantId", tenantId)
.body(mapper.writeValueAsString(params));
} catch (JsonProcessingException e) {
throw new PayException("wechat app pay json failed");
@@ -191,7 +198,8 @@ public abstract class AbstractApi {
* @return the request entity
*/
protected RequestEntity<?> Get(URI uri) {
return RequestEntity.get(uri).header("Pay-TenantId", tenantId)
return RequestEntity.get(uri)
.header("Pay-TenantId", tenantId)
.build();
}
@@ -210,7 +218,7 @@ public abstract class AbstractApi {
}
/**
* 构建Post请求对象.
* 构建Patch请求对象.
*
* @param uri the uri
* @param params the params
@@ -218,7 +226,27 @@ public abstract class AbstractApi {
*/
protected RequestEntity<?> Patch(URI uri, Object params) {
try {
return RequestEntity.patch(uri).header("Pay-TenantId", tenantId)
return RequestEntity.patch(uri)
.header("Pay-TenantId", tenantId)
.body(mapper.writeValueAsString(params));
} catch (JsonProcessingException e) {
throw new PayException("wechat app pay json failed");
}
}
/**
* 构建Patch请求对象.
*
* @param uri the uri
* @param params the params
* @param httpHeaders the http headers
* @return the request entity
*/
protected RequestEntity<?> Patch(URI uri, Object params, HttpHeaders httpHeaders) {
try {
return RequestEntity.patch(uri)
.header("Pay-TenantId", tenantId)
.headers(httpHeaders)
.body(mapper.writeValueAsString(params));
} catch (JsonProcessingException e) {
throw new PayException("wechat app pay json failed");
@@ -230,7 +258,7 @@ public abstract class AbstractApi {
*
* @param link the link
* @return 对账单内容 ,有可能为空字符 “”
* @see AbstractApi#billResource(String) AbstractApi#billResource(String)AbstractApi#billResource(String)AbstractApi#billResource(String)
* @see AbstractApi#billResource(String) AbstractApi#billResource(String)AbstractApi#billResource(String)AbstractApi#billResource(String)AbstractApi#billResource(String)AbstractApi#billResource(String)
*/
protected String billCsvDownload(String link) {
return this.client().withType(WechatPayV3Type.FILE_DOWNLOAD, link)
@@ -349,7 +377,7 @@ public abstract class AbstractApi {
/**
* 调用{@code /v3/billdownload/file}直接下载为文件.
*
* @param downloadUrl 格式为 {@code https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx}
* @param downloadUrl 格式为 {@code https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx}
* @param filename 文件名称包含扩展名
* @return the response entity
*/

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.v3.model.PageParams;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author felord.cn
* @since 1.0.14.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BranchBanksPageParams extends PageParams {
private String bankAliasCode;
private Integer cityCode;
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +13,18 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.PayException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.security.*;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
/**
@@ -30,30 +32,33 @@ import java.security.cert.X509Certificate;
*
* @author felord.cn
* @since 1.0.0.RELEASE
**/
*/
public class KeyPairFactory {
private static final String CERT_ALIAS = "Tenpay Certificate";
private static final KeyStore PKCS12_KEY_STORE;
static {
try {
PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12");
} catch (KeyStoreException e) {
throw new PayException(" wechat pay keystore initialization failed");
}
}
static {
try {
PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12");
} catch (KeyStoreException e) {
throw new PayException(" wechat pay keystore initialization failed");
}
}
public WechatMetaBean initWechatMetaBean(Resource resource, String keyPass) {
return this.initWechatMetaBean(resource, CERT_ALIAS, keyPass);
}
/**
* 获取公私钥.
*
* @param keyPath the key path
* @param resource the resource
* @param keyAlias the key alias
* @param keyPass password
* @return the key pair
*/
public WechatMetaBean initWechatMetaBean(String keyPath, String keyAlias, String keyPass) {
ClassPathResource resource = new ClassPathResource(keyPath);
public WechatMetaBean initWechatMetaBean(Resource resource, String keyAlias, String keyPass) {
char[] pem = keyPass.toCharArray();
try {
PKCS12_KEY_STORE.load(resource.getInputStream(), pem);

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -52,10 +50,8 @@ import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
@@ -88,7 +84,7 @@ public class SignatureProvider {
/**
* 微信平台证书容器 key = 序列号 value = 证书对象
*/
private static final Map<String, X509WechatCertificateInfo> CERTIFICATE_MAP = new ConcurrentHashMap<>();
private static final Set<X509WechatCertificateInfo> CERTIFICATE_SET = Collections.synchronizedSet(new HashSet<>());
/**
* 加密算法提供方 - BouncyCastle
*/
@@ -134,7 +130,7 @@ public class SignatureProvider {
@SneakyThrows
public String requestSign(String tenantId, String method, String canonicalUrl, String body) {
long timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
long timestamp = Instant.now().getEpochSecond();
String nonceStr = nonceStrGenerator.generateId()
.toString()
.replaceAll("-", "");
@@ -163,7 +159,7 @@ public class SignatureProvider {
public String doRequestSign(PrivateKey privateKey, String... orderedComponents) {
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initSign(privateKey);
final String signatureStr = createSign(true, orderedComponents);
final String signatureStr = createSign(orderedComponents);
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(signer.sign());
}
@@ -174,21 +170,29 @@ public class SignatureProvider {
* @param params the params
* @return the boolean
*/
@SneakyThrows
public boolean responseSignVerify(ResponseSignVerifyParams params) {
String wechatpaySerial = params.getWechatpaySerial();
if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
X509WechatCertificateInfo certificate = CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
.findAny()
.orElseGet(() -> {
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
return CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
.findAny()
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
});
try {
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(certificate.getX509Certificate());
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
} catch (Exception e) {
throw new PayException("An exception occurred during the response verification, the cause: " + e.getMessage());
}
Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial).getX509Certificate();
final String signatureStr = createSign(true, params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(certificate);
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
}
@@ -226,8 +230,9 @@ public class SignatureProvider {
throw new PayException("cant obtain the response body");
}
ArrayNode certificates = bodyObjectNode.withArray("data");
if (certificates.isArray() && certificates.size() > 0) {
CERTIFICATE_MAP.remove(tenantId);
if (certificates.isArray() && !certificates.isEmpty()) {
CERTIFICATE_SET.removeIf(x509WechatCertificateInfo ->
Objects.equals(tenantId, x509WechatCertificateInfo.getTenantId()));
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", BC_PROVIDER);
certificates.forEach(objectNode -> {
JsonNode encryptCertificate = objectNode.get("encrypt_certificate");
@@ -245,7 +250,7 @@ public class SignatureProvider {
x509WechatCertificateInfo.setWechatPaySerial(responseSerialNo);
x509WechatCertificateInfo.setTenantId(tenantId);
x509WechatCertificateInfo.setX509Certificate((X509Certificate) certificate);
CERTIFICATE_MAP.put(responseSerialNo, x509WechatCertificateInfo);
CERTIFICATE_SET.add(x509WechatCertificateInfo);
} catch (CertificateException e) {
throw new PayException("An error occurred while generating the wechat v3 certificate, reason : " + e.getMessage());
}
@@ -288,7 +293,8 @@ public class SignatureProvider {
throw new PayException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
InvalidAlgorithmParameterException | NoSuchProviderException e) {
throw new PayException(e);
}
}
@@ -315,6 +321,29 @@ public class SignatureProvider {
}
}
/**
* 对响应的敏感字段进行解密
*
* @param message the message
* @param tenantId the tenant id
* @return encrypt message
* @since 1.0.14.RELEASE
*/
public String decryptResponseMessage(String message, String tenantId) {
try {
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId);
PrivateKey privateKey = wechatMetaBean.getKeyPair().getPrivate();
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] data = Base64Utils.decodeFromString(message);
byte[] cipherData = cipher.doFinal(data);
return new String(cipherData, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new PayException(e);
}
}
/**
* Get certificate x 509 wechat certificate info.
*
@@ -322,22 +351,17 @@ public class SignatureProvider {
* @return the x 509 wechat certificate info
*/
public X509WechatCertificateInfo getCertificate(String tenantId) {
for (String serial : CERTIFICATE_MAP.keySet()) {
X509WechatCertificateInfo wechatCertificateInfo = CERTIFICATE_MAP.get(serial);
X509Certificate x509Cert = wechatCertificateInfo.getX509Certificate();
if (wechatCertificateInfo.getTenantId().equals(tenantId)){
try {
x509Cert.checkValidity();
return wechatCertificateInfo;
} catch (Exception e) {
log.warn("the wechat certificate is invalid , {}", e.getMessage());
// Async?
return CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
.findAny()
.orElseGet(() -> {
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
}
}
}
throw new PayException("failed to obtain wechat pay x509Certificate ");
return CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
.findAny()
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
});
}
@@ -366,11 +390,9 @@ public class SignatureProvider {
* @param components the components
* @return string string
*/
private static String createSign(boolean newLine, String... components) {
String suffix = newLine ? "\n" : "";
private static String createSign(String... components) {
return Arrays.stream(components)
.collect(Collectors.joining("\n", "", suffix));
.collect(Collectors.joining("\n", "", "\n"));
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,14 +13,13 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.v2.WechatAllocationApi;
import cn.felord.payment.wechat.v2.WechatPayRedpackApi;
import cn.felord.payment.wechat.v2.WechatPayTransfersApi;
import cn.felord.payment.wechat.v2.WechatV2Client;
import cn.felord.payment.wechat.v3.ecommerce.WechatEcommerceApi;
/**
* 微信支付工具.
@@ -44,17 +42,6 @@ public class WechatApiProvider {
this.wechatPayClient = wechatPayClient;
}
/**
* 代金券.
*
* @param tenantId the tenant id
* @return the wechat marketing favor api
* @since 1.0.0.RELEASE
*/
public WechatMarketingFavorApi favorApi(String tenantId) {
return new WechatMarketingFavorApi(this.wechatPayClient, tenantId);
}
/**
* 普通支付-直连模式.
*
@@ -66,7 +53,6 @@ public class WechatApiProvider {
return new WechatDirectPayApi(wechatPayClient, tenantId);
}
/**
* 普通支付-服务商模式.
*
@@ -122,6 +108,17 @@ public class WechatApiProvider {
return new WechatDiscountCardApi(wechatPayClient, tenantId);
}
/**
* 代金券.
*
* @param tenantId the tenant id
* @return the wechat marketing favor api
* @since 1.0.0.RELEASE
*/
public WechatMarketingFavorApi favorApi(String tenantId) {
return new WechatMarketingFavorApi(this.wechatPayClient, tenantId);
}
/**
* 微信支付商家券.
*
@@ -133,6 +130,27 @@ public class WechatApiProvider {
return new WechatMarketingBusiFavorApi(wechatPayClient, tenantId);
}
/**
* 委托营销-直连商户
*
* @param tenantId the tenant id
* @return the wechat marketing partnership api
*/
public WechatMarketingPartnershipApi marketingshipApi(String tenantId) {
return new WechatMarketingPartnershipApi(this.wechatPayClient, tenantId);
}
/**
* 支付有礼-直连商户
*
* @param tenantId the tenant id
* @return the wechat marketing pay gift activity api
* @since 1.0.19.RELEASE
*/
public WechatMarketingPayGiftActivityApi marketingPayGiftActivityApi(String tenantId) {
return new WechatMarketingPayGiftActivityApi(this.wechatPayClient, tenantId);
}
/**
* 批量转账到零钱.
* <p>
@@ -189,21 +207,6 @@ public class WechatApiProvider {
return new WechatPayTransfersApi(wechatV2Client);
}
/**
* 微信支付分账基于V2
*
* @param tenantId the tenant id
* @return wechat allocation api
* @since 1.0.10.RELEASE
*/
public WechatAllocationApi allocationApi(String tenantId) {
WechatMetaBean wechatMeta = wechatPayClient.signatureProvider()
.wechatMetaContainer()
.getWechatMeta(tenantId);
WechatV2Client wechatV2Client = new WechatV2Client(wechatMeta);
return new WechatAllocationApi(wechatV2Client);
}
/**
* 直连商户微信支付分账基于V3
*
@@ -215,7 +218,7 @@ public class WechatApiProvider {
}
/**
* 服务商微信支付分账基于V3
* 服务商-微信支付分账基于V3
*
* @param tenantId the tenant id
* @return the wechat partner profitsharing api
@@ -223,4 +226,112 @@ public class WechatApiProvider {
public WechatPartnerProfitsharingApi partnerProfitsharingApi(String tenantId) {
return new WechatPartnerProfitsharingApi(wechatPayClient, tenantId);
}
/**
* 服务商-品牌分账
*
* @param tenantId the tenant id
* @return the wechat brand profitsharing api
*/
public WechatBrandProfitsharingApi brandProfitsharingApi(String tenantId) {
return new WechatBrandProfitsharingApi(wechatPayClient, tenantId);
}
/**
* 微信V3服务商-商户进件-特约商户进件
*
* @param tenantId the tenant id
* @return wechat partner special mch api
* @since 1.0.14.RELEASE
*/
public WechatPartnerSpecialMchApi partnerSpecialMchApi(String tenantId) {
return new WechatPartnerSpecialMchApi(wechatPayClient, tenantId);
}
/**
* 服务商或者直连商户-经营能力-支付即服务
*
* @param tenantId the tenant id
* @return wechat smart guide api
* @since 1.0.14.RELEASE
*/
public WechatSmartGuideApi smartGuideApi(String tenantId) {
return new WechatSmartGuideApi(wechatPayClient, tenantId);
}
/**
* 服务商-经营能力-点金计划
*
* @param tenantId the tenant id
* @return the wechat gold plan api
* @since 1.0.14.RELEASE
*/
public WechatGoldPlanApi goldPlanApi(String tenantId) {
return new WechatGoldPlanApi(wechatPayClient, tenantId);
}
/**
* 服务商-行业方案-电商收付通
*
* @param tenantId the tenant id
* @return the wechat ecommerce api
* @since 1.0.14.RELEASE
*/
public WechatEcommerceApi ecommerceApi(String tenantId) {
return new WechatEcommerceApi(wechatPayClient, tenantId);
}
/**
* 服务商-智慧商圈
*
* @param tenantId the tenant id
* @return the wechat business circle api
* @since 1.0.14.RELEASE
*/
public WechatPartnerBusinessCircleApi partnerBusinessCircleApi(String tenantId) {
return new WechatPartnerBusinessCircleApi(wechatPayClient, tenantId);
}
/**
* 直连商户-智慧商圈
*
* @param tenantId the tenant id
* @return the wechat business circle api
* @since 1.0.14.RELEASE
*/
public WechatBusinessCircleApi businessCircleApi(String tenantId) {
return new WechatBusinessCircleApi(wechatPayClient, tenantId);
}
/**
* 其它能力-媒体上传
*
* @param tenantId the tenant id
* @return the wechat media api
* @since 1.0.14.RELEASE
*/
public WechatMediaApi mediaApi(String tenantId) {
return new WechatMediaApi(wechatPayClient, tenantId);
}
/**
* 其它能力-银行组件(服务商)
*
* @param tenantId the tenant id
* @return the wechat media api
* @since 1.0.14.RELEASE
*/
public WechatCapitalApi capitalApi(String tenantId) {
return new WechatCapitalApi(wechatPayClient, tenantId);
}
/**
* 风险合规-消费者投诉2.0
*
* @param tenantId the tenant id
* @return the wechat complaints api
*/
public WechatComplaintsApi complaintsApi(String tenantId) {
return new WechatComplaintsApi(wechatPayClient, tenantId);
}
}

View File

@@ -82,8 +82,10 @@ public class WechatBatchTransferApi extends AbstractApi {
List<CreateBatchTransferParams.TransferDetailListItem> encrypted = transferDetailList.stream()
.peek(transferDetailListItem -> {
String userName = transferDetailListItem.getUserName();
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, x509Certificate);
transferDetailListItem.setUserName(encryptedUserName);
if (StringUtils.hasText(userName)) {
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, x509Certificate);
transferDetailListItem.setUserName(encryptedUserName);
}
String userIdCard = transferDetailListItem.getUserIdCard();
if (StringUtils.hasText(userIdCard)) {
String encryptedUserIdCard = signatureProvider.encryptRequestMessage(userIdCard, x509Certificate);
@@ -101,7 +103,7 @@ public class WechatBatchTransferApi extends AbstractApi {
}
/**
* 微信批次单号查询批次单API
* 通过微信批次单号查询批次单API
*
* @param queryBatchTransferParams the queryBatchTransferParams
* @return the wechat response entity
@@ -130,33 +132,7 @@ public class WechatBatchTransferApi extends AbstractApi {
}
/**
* 微信明细单号查询明细单API
*
* @param queryBatchTransferDetailParams the queryBatchTransferDetailParams
* @return the wechat response entity
* @since 1.0.6.RELEASE
*/
public WechatResponseEntity<ObjectNode> queryBatchDetailByWechat(QueryBatchTransferDetailParams queryBatchTransferDetailParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BATCH_TRANSFER_DETAIL_WECHAT, queryBatchTransferDetailParams)
.function((type, params) -> {
Map<String, String> pathParams = new HashMap<>(2);
pathParams.put("batch_id", params.getBatchIdOrOutBatchNo());
pathParams.put("detail_id", params.getDetailIdOrOutDetailNo());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(pathParams)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 微信批次单号查询批次单API
* 通过商家批次单号查询批次单API
*
* @param queryBatchTransferParams the queryBatchTransferParams
* @return the wechat response entity
@@ -185,7 +161,33 @@ public class WechatBatchTransferApi extends AbstractApi {
}
/**
* 商家明细单号查询明细单API
* 通过微信明细单号查询明细单API
*
* @param queryBatchTransferDetailParams the queryBatchTransferDetailParams
* @return the wechat response entity
* @since 1.0.6.RELEASE
*/
public WechatResponseEntity<ObjectNode> queryBatchDetailByWechat(QueryBatchTransferDetailParams queryBatchTransferDetailParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BATCH_TRANSFER_DETAIL_WECHAT, queryBatchTransferDetailParams)
.function((type, params) -> {
Map<String, String> pathParams = new HashMap<>(2);
pathParams.put("batch_id", params.getBatchIdOrOutBatchNo());
pathParams.put("detail_id", params.getDetailIdOrOutDetailNo());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(pathParams)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 通过商家明细单号查询明细单API
*
* @param queryBatchTransferDetailParams the queryBatchTransferDetailParams
* @return the wechat response entity
@@ -196,8 +198,8 @@ public class WechatBatchTransferApi extends AbstractApi {
this.client().withType(WechatPayV3Type.BATCH_TRANSFER_DETAIL_MCH, queryBatchTransferDetailParams)
.function((type, params) -> {
Map<String, String> pathParams = new HashMap<>(2);
pathParams.put("batch_id", params.getBatchIdOrOutBatchNo());
pathParams.put("detail_id", params.getDetailIdOrOutDetailNo());
pathParams.put("out_batch_no", params.getBatchIdOrOutBatchNo());
pathParams.put("out_detail_no", params.getDetailIdOrOutDetailNo());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
@@ -258,7 +260,7 @@ public class WechatBatchTransferApi extends AbstractApi {
}
/**
* 转账明细电子回单受理API
* 受理转账明细电子回单API
* <p>
* 受理转账明细电子回单接口,商户通过该接口可以申请受理转账明细单电子回单服务。
* <p>

View File

@@ -0,0 +1,327 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.TarType;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.ecommerce.BrandReceiver;
import cn.felord.payment.wechat.v3.model.ecommerce.BrandReceiverDeleteParams;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceFinishOrder;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceReturnOrderParams;
import cn.felord.payment.wechat.v3.model.profitsharing.BrandProfitsharingOrder;
import cn.felord.payment.wechat.v3.model.profitsharing.PartnerProfitsharingBillParams;
import cn.felord.payment.wechat.v3.model.profitsharing.PartnerQueryOrderParams;
import cn.felord.payment.wechat.v3.model.profitsharing.PartnerReturnOrdersParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
/**
* 服务商-资金应用-连锁品牌分账
*
* @author felord.cn
* @since 1.0.15
*/
public class WechatBrandProfitsharingApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatBrandProfitsharingApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 请求分账API
*
* @param brandProfitsharingOrder the brand profitsharing order
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> profitsharingOrders(BrandProfitsharingOrder brandProfitsharingOrder) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_ORDERS, brandProfitsharingOrder)
.function((wechatPayV3Type, params) -> {
params.setAppid(this.wechatMetaBean().getV3().getAppId());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, params);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询分账结果API
* <p>
* 发起分账请求后,可调用此接口查询分账结果
* <p>
* 注意:
* <ul>
* <li>发起解冻剩余资金请求后,可调用此接口查询解冻剩余资金的结果</li>
* </ul>
*
* @param queryOrderParams the query order params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryProfitsharingOrder(PartnerQueryOrderParams queryOrderParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_RESULT, queryOrderParams)
.function((wechatPayV3Type, params) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("sub_mchid", params.getSubMchid());
queryParams.add("transaction_id", params.getTransactionId());
queryParams.add("out_order_no", params.getOutOrderNo());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 请求分账回退API
* <p>
* 如果订单已经分账,在退款时,可以先调此接口,将已分账的资金从分账接收方的账户回退给分账方,再发起退款
*
* @param returnOrdersParams the return orders params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> returnOrders(PartnerReturnOrdersParams returnOrdersParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_RETURN_ORDERS, returnOrdersParams)
.function((wechatPayV3Type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, params);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询分账回退结果API
* <p>
* 商户需要核实回退结果,可调用此接口查询回退结果
* <p>
* 注意:
* <ul>
* <li>如果分账回退接口返回状态为处理中,可调用此接口查询回退结果</li>
* </ul>
*
* @param queryReturnOrderParams the query return order params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryReturnOrders(EcommerceReturnOrderParams queryReturnOrderParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_RETURN_ORDERS_RESULT, queryReturnOrderParams)
.function((wechatPayV3Type, params) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("sub_mchid", params.getSubMchid());
String orderId = params.getOrderId();
if (orderId != null) {
queryParams.add("order_id", orderId);
}
String outOrderNo = params.getOutOrderNo();
if (outOrderNo != null) {
queryParams.add("out_order_no", outOrderNo);
}
queryParams.add("out_return_no", params.getOutReturnNo());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 完结分账API
* <p>
* 不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给二级商户。
*
* @param finishOrder the finish order
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> finishOrder(EcommerceFinishOrder finishOrder) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_FINISH_ORDER, finishOrder)
.function((wechatPayV3Type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, params);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询订单剩余待分金额API
* <p>
* 可调用此接口查询订单剩余待分金额
*
* @param transactionId the transaction id
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryOrderAmounts(String transactionId) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_ORDER_AMOUNTS, transactionId)
.function((wechatPayV3Type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.expand(id)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询最大分账比例API
*
* @param brandMchid the brandMchid
* @return wechat response entity
*/
public WechatResponseEntity<ObjectNode> brandConfigs(String brandMchid) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_CONFIGS, brandMchid)
.function((wechatPayV3Type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.expand(id)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 添加分账接收方API
* <p>
* 商户发起添加分账接收方请求,建立分账接收方列表。后续可通过发起分账请求,将分账方商户结算后的资金,分到该分账接收方
*
* @param brandReceiver the brandReceiver
* @return wechat response entity
*/
public WechatResponseEntity<ObjectNode> addReceivers(BrandReceiver brandReceiver) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_RECEIVERS_ADD, brandReceiver)
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setAppid(v3.getAppId());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, params);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 删除分账接收方API
* <p>
* 商户发起删除分账接收方请求。删除后,不支持将分账方商户结算后的资金,分到该分账接收方
*
* @param delReceiversParams the del receivers params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> deleteReceivers(BrandReceiverDeleteParams delReceiversParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.BRAND_PROFITSHARING_RECEIVERS_DELETE, delReceiversParams)
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setAppid(v3.getAppId());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, params);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 申请分账账单API
*
* @param billParams the bill params
* @return the response entity
*/
public ResponseEntity<Resource> downloadMerchantBills(PartnerProfitsharingBillParams billParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PROFITSHARING_BILLS, billParams)
.function(((wechatPayV3Type, params) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
String subMchid = params.getSubMchid();
if (subMchid != null) {
queryParams.add("sub_mchid", subMchid);
}
LocalDate billDate = params.getBillDate();
queryParams.add("bill_date", billDate.format(DateTimeFormatter.ISO_DATE));
TarType tarType = params.getTarType();
if (Objects.nonNull(tarType)) {
queryParams.add("tar_type", tarType.name());
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return Get(uri);
})).consumer(wechatResponseEntity::convert)
.request();
String downloadUrl = Objects.requireNonNull(wechatResponseEntity.getBody())
.get("download_url")
.asText();
String ext = Objects.equals(TarType.GZIP, billParams.getTarType()) ? ".gzip" : ".txt";
String filename = "profitsharingbill-" + billParams.getBillDate().toString() + ext;
return this.downloadBillResponse(downloadUrl, filename);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.busicircle.MallScoreParams;
import cn.felord.payment.wechat.v3.model.busicircle.MallScoreSyncRequest;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
/**
* 直连商户智慧商圈
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatBusinessCircleApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatBusinessCircleApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 商圈积分同步API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> apply(MallScoreSyncRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MALL_SCORE_SYNC, request)
.function((wechatPayV3Type, mallScoreSyncRequest) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, mallScoreSyncRequest);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 商圈积分授权查询API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryAuthStatus(MallScoreParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MALL_SCORE_RESULT, params)
.function((type, mallScoreParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("appid", mallScoreParams.getAppid())
.build()
.expand(mallScoreParams.getOpenid())
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.PageParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.security.cert.X509Certificate;
/**
* 其它能力-银行组件(服务商)
* <p>
* 具体参见 <a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_1.shtml">银行组件</a>
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatCapitalApi extends AbstractApi{
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatCapitalApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 获取对私银行卡号开户银行API
*
* @param accountNumber accountNumber
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> searchBanksByBankAccount(String accountNumber) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_SEARCH, accountNumber)
.function((type, param) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("account_number", signatureProvider.encryptRequestMessage(param,x509Certificate))
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询支持个人业务的银行列表API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryPersonalBanks(PageParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_PERSONAL, params)
.function((type, pageParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("offset", pageParams.getOffset())
.queryParam("limit", pageParams.getLimit())
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询支持对公业务的银行列表API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryCorporateBanks(PageParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_CORPORATE, params)
.function((type, pageParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("offset", pageParams.getOffset())
.queryParam("limit", pageParams.getLimit())
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询省份列表API
*
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryProvinces() {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_PROVINCES, "")
.function((type, pageParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询城市列表API
*
* @param provinceCode provinceCode
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryCitiesByProvince(Integer provinceCode) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_CITIES, provinceCode)
.function((type, code) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(code)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询支行列表API
*
* @param params branchBanksPageParams
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryBranchBanks(BranchBanksPageParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CAPITAL_BRANCHES, params)
.function((type, pageParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("city_code", pageParams.getCityCode())
.queryParam("offset", pageParams.getOffset())
.queryParam("limit", pageParams.getLimit())
.build()
.expand(pageParams.getBankAliasCode())
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -211,4 +209,26 @@ public class WechatCombinePayApi extends AbstractApi {
.request();
return wechatResponseEntity;
}
/**
* 查询单笔退款API
*
* @param outRefundNo the out refund no
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> queryRefundInfo(String outRefundNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.QUERY_REFUND, outRefundNo)
.function(((type, param) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(param)
.toUri();
return Get(uri);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
/**
* 风险合规-消费者投诉2.0
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
public class WechatComplaintsApi extends AbstractApi{
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatComplaintsApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.goldplan.GoldPlanChangeParams;
import cn.felord.payment.wechat.v3.model.goldplan.GoldPlanAdvertisingParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.Collections;
/**
* 经营能力-点金计划
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatGoldPlanApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatGoldPlanApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 点金计划管理API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> change(GoldPlanChangeParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.GOLD_PLAN_CHANGE, params)
.function((wechatPayV3Type, goldPlanChangeParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, goldPlanChangeParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 商家小票管理API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> changeCustom(GoldPlanChangeParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.GOLD_PLAN_CHANGE_CUSTOM, params)
.function((wechatPayV3Type, goldPlanChangeParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, goldPlanChangeParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 同业过滤标签管理API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> filter(GoldPlanAdvertisingParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.GOLD_PLAN_CHANGE_CUSTOM, params)
.function((wechatPayV3Type, goldPlanChangeParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, goldPlanChangeParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 开通广告展示API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> openAdv(GoldPlanAdvertisingParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.GOLD_PLAN_ADV_OPEN, params)
.function((wechatPayV3Type, goldPlanChangeParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, goldPlanChangeParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 关闭广告展示API
*
* @param subMchid the sub mchid
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> closeAdv(String subMchid) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.GOLD_PLAN_ADV_CLOSE, subMchid)
.function((wechatPayV3Type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, Collections.singletonMap("sub_mchid",id));
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -13,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -360,7 +359,7 @@ public class WechatMarketingBusiFavorApi extends AbstractApi {
.expand(budgetParams.getStockId())
.toUri();
budgetParams.setStockId(null);
return Post(uri, budgetParams);
return Patch(uri, budgetParams);
})
.consumer(wechatResponseEntity::convert)
.request();

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -159,7 +158,9 @@ public class WechatMarketingFavorApi extends AbstractApi {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setAppid(v3.getAppId());
params.setStockCreatorMchid(v3.getMchId());
if (StringUtils.hasText(params.getStockCreatorMchid())){
params.setStockCreatorMchid(v3.getMchId());
}
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(params.getOpenid())
@@ -546,13 +547,17 @@ public class WechatMarketingFavorApi extends AbstractApi {
/**
* 营销图片上传API
* <p>
* 该接口标记过时,用{@link WechatMediaApi#marketingImageUpload(MultipartFile)}代替
* <p>
* 媒体图片只支持JPG、BMP、PNG格式文件大小不能超过2M。
* <p>
* 通过本接口上传图片后可获得图片url地址。图片url可在微信支付营销相关的API使用包括商家券、代金券、支付有礼等。
*
* @param file the file
* @return the wechat response entity
* @see WechatMediaApi#marketingImageUpload(MultipartFile)
*/
@Deprecated
public WechatResponseEntity<ObjectNode> marketingImageUpload(MultipartFile file) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_IMAGE_UPLOAD, file)

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.PayException;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.partnership.Partner;
import cn.felord.payment.wechat.v3.model.partnership.PartnershipParams;
import cn.felord.payment.wechat.v3.model.partnership.PartnershipQueryParams;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* 委托营销-直连商户
*
* @author felord.cn
* @since 1.0.16.RELEASE
*/
public class WechatMarketingPartnershipApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatMarketingPartnershipApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 建立合作关系API
* <p>
* 该接口主要为商户提供营销资源的授权能力,可授权给其他商户或小程序,方便商户间的互利合作。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> build(PartnershipParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PARTNERSHIPS_BUILD, params)
.function((type, partnershipParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
String idempotencyKey = partnershipParams.getIdempotencyKey();
partnershipParams.clearKey();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Idempotency-Key", idempotencyKey);
return Post(uri, partnershipParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询合作关系列表API
* <p>
* 该接口主要为商户提供合作关系列表的查询能力。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> query(PartnershipQueryParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PARTNERSHIPS_GET, params)
.function((type, partnershipParams) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
Partner partner = params.getPartner();
try {
ObjectMapper mapper = this.getMapper();
if (Objects.nonNull(partner)) {
String partnerJson = mapper.writeValueAsString(partner);
queryParams.add("partner", UriUtils.encode(partnerJson, StandardCharsets.UTF_8));
}
String authorizedDataJson = mapper.writeValueAsString(params.getAuthorizedData());
queryParams.add("authorized_data", UriUtils.encode(authorizedDataJson, StandardCharsets.UTF_8));
} catch (JsonProcessingException e) {
throw new PayException(e);
}
Integer limit = params.getLimit();
if (Objects.nonNull(limit)) {
queryParams.add("limit", limit.toString());
}
Integer offset = params.getOffset();
if (Objects.nonNull(offset)) {
queryParams.add("offset", offset.toString());
}
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build(false)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.paygiftactivity.ActivitiesListPageRequest;
import cn.felord.payment.wechat.v3.model.paygiftactivity.ActivitiesPageRequest;
import cn.felord.payment.wechat.v3.model.paygiftactivity.DeleteActivityMchRequest;
import cn.felord.payment.wechat.v3.model.paygiftactivity.GiftActivityParams;
import cn.felord.payment.wechat.v3.model.paygiftactivity.NewActivityMchRequest;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 支付有礼
*
* @author dax
* @since 1.0.19.RELEASE
*/
public class WechatMarketingPayGiftActivityApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatMarketingPayGiftActivityApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 创建全场满额送活动API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> create(GiftActivityParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY, params)
.function((type, activityParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, activityParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询活动详情接口API
*
* @param activityId the activity id
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> details(String activityId) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_DETAIL, activityId)
.function((type, param) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(param)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询活动发券商户号API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> merchants(ActivitiesPageRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_MCH, request)
.function((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("offset", params.getOffset())
.queryParam("limit", params.getLimit())
.build()
.expand(params.getActivityId())
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询活动指定商品列表API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> goods(ActivitiesPageRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_GOODS, request)
.function((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("offset", params.getOffset())
.queryParam("limit", params.getLimit())
.build()
.expand(params.getActivityId())
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 终止活动API
*
* @param activityId the activity id
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> terminate(String activityId) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_TERMINATE, activityId)
.function((type, param) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(param)
.toUri();
return Post(uri, Collections.emptyMap());
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 新增活动发券商户号API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> addMches(NewActivityMchRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_MCH_ADD, request)
.function((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(params.getActivityId())
.toUri();
Map<String, Object> body = new HashMap<>();
body.put("merchant_id_list", params.getMerchantIdList());
body.put("add_request_no", params.getAddRequestNo());
return Post(uri, body);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 获取支付有礼活动列表API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> page(ActivitiesListPageRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_ACTIVITIES, request)
.function((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("offset", params.getOffset())
.queryParam("limit", params.getLimit())
.queryParam("activity_name", params.getActivityName())
.queryParam("activity_status", params.getActivityStatus())
.queryParam("award_type", params.getAwardType())
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 删除活动发券商户号API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> deleteMch(DeleteActivityMchRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_PAYGIFTACTIVITY_MCH_DEL, request)
.function((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(params.getActivityId())
.toUri();
Map<String, Object> body = new HashMap<>();
body.put("merchant_id_list", params.getMerchantIdList());
body.put("delete_request_no", params.getDeleteRequestNo());
return Post(uri, body);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.SneakyThrows;
import org.bouncycastle.jcajce.provider.digest.SHA256;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 其它能力-媒体上传
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatMediaApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatMediaApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 图片上传API
*
* @param file the file
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> mediaImageUpload(MultipartFile file) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MERCHANT_MEDIA_IMG, file)
.function(this::uploadFunction)
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 视频上传API
*
* @param file the file
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> mediaVideoUpload(MultipartFile file) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MERCHANT_MEDIA_VIDEO, file)
.function(this::uploadFunction)
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
@SneakyThrows
private RequestEntity<?> uploadFunction(WechatPayV3Type type, MultipartFile file) {
Map<String, Object> meta = new LinkedHashMap<>(2);
String originalFilename = file.getOriginalFilename();
String filename = StringUtils.hasText(originalFilename) ? originalFilename : file.getName();
meta.put("filename", filename);
byte[] digest = SHA256.Digest.getInstance("SHA-256").digest(file.getBytes());
meta.put("sha256", Hex.toHexString(digest));
MultiValueMap<Object, Object> body = new LinkedMultiValueMap<>();
body.add("meta", meta);
body.add("file", file.getResource());
// 签名
String metaStr = this.getMapper().writeValueAsString(meta);
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
return RequestEntity.post(uri)
.header("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE)
.header("Meta-Info", metaStr)
.header("Pay-TenantId", tenantId())
.body(body);
}
/**
* 营销图片上传API
* <p>
* 媒体图片只支持JPG、BMP、PNG格式文件大小不能超过2M。
* <p>
* 通过本接口上传图片后可获得图片url地址。图片url可在微信支付营销相关的API使用包括商家券、代金券、支付有礼等。
*
* @param file the file
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> marketingImageUpload(MultipartFile file) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MARKETING_IMAGE_UPLOAD, file)
.function(this::uploadFunction)
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,12 +13,19 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
import java.util.*;
import cn.felord.payment.wechat.WechatTenantService;
import lombok.AllArgsConstructor;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 配置容器
@@ -27,32 +33,23 @@ import java.util.*;
* @author felord.cn
* @since 1.0.0.RELEASE
*/
@AllArgsConstructor
public class WechatMetaContainer {
private final Map<String, WechatMetaBean> wechatMetaBeanMap = new HashMap<>();
private final Set<String> tenantIds = new HashSet<>();
private final Map<String, WechatMetaBean> wechatMetaBeanMap = new ConcurrentHashMap<>();
private final WechatTenantService wechatTenantService;
/**
* Add wechat meta boolean.
* Add wechat metas.
*
* @param tenantId the tenantId
* @param wechatMetaBean the wechat meta bean
* @return the boolean
* @param wechatMetaBeans the wechat meta beans
*/
public WechatMetaBean addWechatMeta(String tenantId, WechatMetaBean wechatMetaBean) {
tenantIds.add(tenantId);
return this.wechatMetaBeanMap.put(tenantId, wechatMetaBean);
public void addWechatMetas(Collection<WechatMetaBean> wechatMetaBeans) {
wechatMetaBeans.forEach(this::addMeta);
}
/**
* Remove wechat meta wechat meta bean.
*
* @param tenantId the tenantId
* @return the wechat meta bean
*/
public WechatMetaBean removeWechatMeta(String tenantId) {
tenantIds.remove(tenantId);
return this.wechatMetaBeanMap.remove(tenantId);
private void addMeta(WechatMetaBean wechatMetaBean) {
String tenantId = wechatMetaBean.getTenantId();
wechatMetaBeanMap.put(tenantId, wechatMetaBean);
}
/**
@@ -62,7 +59,14 @@ public class WechatMetaContainer {
* @return the wechat meta
*/
public WechatMetaBean getWechatMeta(String tenantId) {
return Objects.requireNonNull(this.wechatMetaBeanMap.get(tenantId));
WechatMetaBean wechatMetaBean = this.wechatMetaBeanMap.get(tenantId);
if (Objects.nonNull(wechatMetaBean)) {
return wechatMetaBean;
} else {
this.addWechatMetas(wechatTenantService.loadTenants());
return Objects.requireNonNull(this.wechatMetaBeanMap.get(tenantId),
"cant obtain the config with tenant: "+tenantId);
}
}
/**
@@ -71,6 +75,9 @@ public class WechatMetaContainer {
* @return the properties keys
*/
public Set<String> getTenantIds() {
return tenantIds;
return wechatTenantService.loadTenants()
.stream()
.map(WechatMetaBean::getTenantId)
.collect(Collectors.toSet());
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.busicircle.PartnerMallScoreParams;
import cn.felord.payment.wechat.v3.model.busicircle.PartnerMallScoreSyncRequest;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
/**
* 服务商智慧商圈
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatPartnerBusinessCircleApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatPartnerBusinessCircleApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 商圈积分同步API
*
* @param request the request
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> apply(PartnerMallScoreSyncRequest request) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MALL_SCORE_SYNC, request)
.function((wechatPayV3Type, mallScoreSyncRequest) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, mallScoreSyncRequest);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 商圈积分授权查询API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryAuthStatus(PartnerMallScoreParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.MALL_SCORE_RESULT, params)
.function((type, mallScoreParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("sub_mchid", mallScoreParams.getSubMchid())
.queryParam("appid", mallScoreParams.getAppid())
.build()
.expand(mallScoreParams.getOpenid())
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -21,6 +21,8 @@ import cn.felord.payment.PayException;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.RefundParams;
import cn.felord.payment.wechat.v3.model.RefundQueryParams;
import cn.felord.payment.wechat.v3.model.TransactionQueryParams;
import cn.felord.payment.wechat.v3.model.partner.CloseTransParams;
import cn.felord.payment.wechat.v3.model.partner.PartnerPayParams;
@@ -78,7 +80,7 @@ public class WechatPartnerPayApi extends AbstractApi {
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId());
PrivateKey privateKey = wechatMetaBean.getKeyPair().getPrivate();
String subAppid = partnerPayParams.getSubAppid();
String spAppid = partnerPayParams.getSpAppid();
long epochSecond = LocalDateTime.now()
.toEpochSecond(ZoneOffset.of("+8"));
String timestamp = String.valueOf(epochSecond);
@@ -87,9 +89,8 @@ public class WechatPartnerPayApi extends AbstractApi {
.toString()
.replaceAll("-", "");
String prepayId = body.get("prepay_id").asText();
String paySign = signatureProvider.doRequestSign(privateKey, subAppid, timestamp, nonceStr, prepayId);
body.put("appid", subAppid);
String paySign = signatureProvider.doRequestSign(privateKey, spAppid, timestamp, nonceStr, prepayId);
body.put("appid", spAppid);
body.put("partnerid", partnerPayParams.getSubMchid());
body.put("prepayid", prepayId);
body.put("package", "Sign=WXPay");
@@ -127,7 +128,7 @@ public class WechatPartnerPayApi extends AbstractApi {
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId());
PrivateKey privateKey = wechatMetaBean.getKeyPair().getPrivate();
String subAppid = partnerPayParams.getSubAppid();
String spAppid = partnerPayParams.getSpAppid();
long epochSecond = LocalDateTime.now()
.toEpochSecond(ZoneOffset.of("+8"));
String timestamp = String.valueOf(epochSecond);
@@ -136,9 +137,8 @@ public class WechatPartnerPayApi extends AbstractApi {
.toString()
.replaceAll("-", "");
String packageStr = "prepay_id=" + body.get("prepay_id").asText();
String paySign = signatureProvider.doRequestSign(privateKey, subAppid, timestamp, nonceStr, packageStr);
body.put("appId", subAppid);
String paySign = signatureProvider.doRequestSign(privateKey, spAppid, timestamp, nonceStr, packageStr);
body.put("appid", spAppid);
body.put("timeStamp", timestamp);
body.put("nonceStr", nonceStr);
body.put("package", packageStr);
@@ -212,6 +212,61 @@ public class WechatPartnerPayApi extends AbstractApi {
return wechatResponseEntity;
}
/**
* 申请退款API
*
* @param refundParams the refund params
* @return the wechat response entity
* @since 1.0.15-SNAPSHOT
*/
public WechatResponseEntity<ObjectNode> refund(RefundParams refundParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.REFUND, refundParams)
.function(((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setNotifyUrl(v3.getDomain().concat(params.getNotifyUrl()));
return Post(uri, params);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 商户退款订单查询API
*
* @param params the params
* @return the wechat response entity
* @since 1.0.15-SNAPSHOT
*/
public WechatResponseEntity<ObjectNode> queryRefundInfo(RefundQueryParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.QUERY_REFUND, params)
.function(this::queryRefundFunction)
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
private RequestEntity<?> queryRefundFunction(WechatPayV3Type type, RefundQueryParams params) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
// queryParams.add("out_refund_no", params.getRefundOrderNo());
queryParams.add("sub_mchid", params.getSubMchid());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.expand(params.getRefundOrderNo())
.toUri();
return Get(uri);
}
/**
* 商户订单号查询API
*

View File

@@ -17,11 +17,15 @@
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.ReceiverType;
import cn.felord.payment.wechat.enumeration.TarType;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.profitsharing.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -30,7 +34,10 @@ import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -117,9 +124,8 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
this.client().withType(WechatPayV3Type.PROFITSHARING_ORDERS_RESULT, queryOrderParams)
.function((wechatPayV3Type, params) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("sub_mchid", params.getSubMchid());
queryParams.add("transaction_id", params.getTransactionId());
Optional.ofNullable(params.getSubMchid())
.ifPresent(mchId -> queryParams.add("sub_mchid", params.getSubMchid()));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
@@ -291,9 +297,9 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
String name = params.getName();
if (StringUtils.hasText(name)) {
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
if (ReceiverType.MERCHANT_ID.equals(params.getType())) {
String encryptedName = signatureProvider.encryptRequestMessage(params.getName(), x509Certificate);
params.setName(encryptedName);
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
@@ -331,4 +337,42 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.request();
return wechatResponseEntity;
}
/**
* 申请分账账单API
*
* @param billParams the bill params
* @return the response entity
*/
public ResponseEntity<Resource> downloadMerchantBills(PartnerProfitsharingBillParams billParams){
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PROFITSHARING_BILLS,billParams)
.function(((wechatPayV3Type, params) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
String subMchid = params.getSubMchid();
if (subMchid !=null){
queryParams.add("sub_mchid",subMchid);
}
LocalDate billDate = params.getBillDate();
queryParams.add("bill_date", billDate.format(DateTimeFormatter.ISO_DATE));
TarType tarType = params.getTarType();
if (Objects.nonNull(tarType)) {
queryParams.add("tar_type", tarType.name());
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return Get(uri);
})).consumer(wechatResponseEntity::convert)
.request();
String downloadUrl = Objects.requireNonNull(wechatResponseEntity.getBody())
.get("download_url")
.asText();
String ext = Objects.equals(TarType.GZIP, billParams.getTarType()) ? ".gzip" : ".txt";
String filename = "profitsharingbill-" + billParams.getBillDate().toString() + ext;
return this.downloadBillResponse(downloadUrl, filename);
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.specmch.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.List;
/**
* 微信V3服务商-商户进件-特约商户进件
* <p>
* 参见<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter7_1_1.shtml">产品介绍</a>
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatPartnerSpecialMchApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatPartnerSpecialMchApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 提交申请单API
* <p>
* 服务商(银行、支付机构、电商平台不可用)使用该接口提交商家资料,帮助商家入驻成为微信支付的特约商户。
* 流程指引请看 <a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter7_1_2.shtml#part-6">特约商户进件流程</a>
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> apply(ApplymentParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_PARTNER, params)
.function((wechatPayV3Type, applymentParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
ApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, applyRequestParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 通过业务申请编号查询申请状态
*
* @param businessCode the business code
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryByBusinessCode(String businessCode) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_QUERY_BUSINESS_CODE, businessCode)
.function((type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(id)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 通过申请单号查询申请状态
*
* @param applymentId the applyment id
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryByApplymentId(String applymentId) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_QUERY_APPLYMENT_ID, applymentId)
.function((type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(id)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 修改结算账号API
* <p>
* 服务商/电商平台(不包括支付机构、银行),可使用本接口,修改其进件且已签约特约商户/二级商户的结算银行账户。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> modify(SubMchModifyParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SPEC_MCH_SUB_MODIFY, params)
.function((type, subMchModifyParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(subMchModifyParams.getSubMchid())
.toUri();
subMchModifyParams.setSubMchid(null);
subMchModifyParams.setAccountNumber(signatureProvider.encryptRequestMessage(subMchModifyParams.getAccountNumber(), x509Certificate));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, subMchModifyParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询结算账户API
* <p>
* 服务商/电商平台(不包括支付机构、银行),可使用本接口,查询其进件且已签约特约商户/二级商户的结算账户信息(敏感信息掩码)。
* 该接口可用于核实是否成功修改结算账户信息、及查询系统汇款验证结果。
*
* @param subMchid the sub mchid
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> querySettlement(String subMchid) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SPEC_MCH_SUB_SETTLEMENT, subMchid)
.function((type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(id)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
private ApplymentParams convert(ApplymentParams applymentParams, SignatureProvider signatureProvider, final X509Certificate x509Certificate) {
ContactInfo contactInfo = applymentParams.getContactInfo();
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
String contactIdNumber = contactInfo.getContactIdNumber();
if (contactIdNumber != null) {
contactInfo.setContactIdNumber(signatureProvider.encryptRequestMessage(contactIdNumber, x509Certificate));
}
String openid = contactInfo.getOpenid();
if (openid != null) {
contactInfo.setOpenid(signatureProvider.encryptRequestMessage(openid, x509Certificate));
}
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), x509Certificate));
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactInfo.getContactEmail(), x509Certificate));
SubjectInfo subjectInfo = applymentParams.getSubjectInfo();
IdentityInfo identityInfo = subjectInfo.getIdentityInfo();
IdCardInfo idCardInfo = identityInfo.getIdCardInfo();
if (idCardInfo != null) {
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
String idCardAddress = idCardInfo.getIdCardAddress();
if (StringUtils.hasText(idCardAddress)){
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
}
}
IdDocInfo idDocInfo = identityInfo.getIdDocInfo();
if (idDocInfo != null) {
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
String idDocAddress = idDocInfo.getIdDocAddress();
if (StringUtils.hasText(idDocAddress)){
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
}
}
List<UboInfoListItem> uboInfoList = subjectInfo.getUboInfoList();
if (!CollectionUtils.isEmpty(uboInfoList)) {
uboInfoList.forEach(uboInfoListItem -> {
uboInfoListItem.setUboIdDocName(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocName(), x509Certificate));
uboInfoListItem.setUboIdDocNumber(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocNumber(), x509Certificate));
uboInfoListItem.setUboIdDocAddress(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocAddress(), x509Certificate));
});
}
BankAccountInfo bankAccountInfo = applymentParams.getBankAccountInfo();
bankAccountInfo.setAccountName(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountName(), x509Certificate));
bankAccountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountNumber(), x509Certificate));
return applymentParams;
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +17,9 @@
package cn.felord.payment.wechat.v3;
import cn.felord.payment.PayException;
import cn.felord.payment.wechat.v3.model.CallbackParams;
import cn.felord.payment.wechat.v3.model.CouponConsumeData;
import cn.felord.payment.wechat.v3.model.ProfitSharingConsumeData;
import cn.felord.payment.wechat.v3.model.RefundConsumeData;
import cn.felord.payment.wechat.v3.model.ResponseSignVerifyParams;
import cn.felord.payment.wechat.v3.model.TransactionConsumeData;
import cn.felord.payment.wechat.v3.model.*;
import cn.felord.payment.wechat.v3.model.busicircle.MallRefundConsumeData;
import cn.felord.payment.wechat.v3.model.busicircle.MallTransactionConsumeData;
import cn.felord.payment.wechat.v3.model.busifavor.BusiFavorReceiveConsumeData;
import cn.felord.payment.wechat.v3.model.combine.CombineTransactionConsumeData;
import cn.felord.payment.wechat.v3.model.discountcard.DiscountCardAcceptedConsumeData;
@@ -36,12 +32,13 @@ import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPaidConsumeData;
import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPermissionConsumeData;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingCallback;
import cn.felord.payment.wechat.v3.model.payscore.parking.TransParkingCallback;
import cn.felord.payment.wechat.v3.model.profitsharing.PartnerProfitsharingConsumeData;
import cn.felord.payment.wechat.v3.model.profitsharing.ProfitsharingConsumeData;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@@ -78,7 +75,7 @@ public class WechatPayCallback {
private final String tenantId;
static {
MAPPER.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
@@ -243,7 +240,8 @@ public class WechatPayCallback {
* <li>如果在所有通知频率后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。</li>
* </ul>
* 特别提醒:商户系统对于支付成功通知的内容一定要做签名验证,并校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
* @param params the params
*
* @param params the params
* @param transParkingCallbackConsumer the transParkingCallbackConsumer
* @return the map
* @since 1.0.13.RELEASE
@@ -388,7 +386,35 @@ public class WechatPayCallback {
}
/**
* 微信支付分账V3动账通知
* 服务商退款结果通知API电商收付通复用
* <p>
* 退款状态改变后,微信会把相关退款结果发送给商户。
*
* @param params the params
* @param consumeDataConsumer the consume data consumer
* @return map map
*/
@SneakyThrows
public Map<String, String> partnerRefundCallback(ResponseSignVerifyParams params, Consumer<PartnerRefundConsumeData> consumeDataConsumer) {
CallbackParams callbackParams = resolve(params);
String eventType = callbackParams.getEventType();
if (!(Objects.equals(eventType, EventType.REFUND_CLOSED.event) ||
Objects.equals(eventType, EventType.REFUND_ABNORMAL.event) ||
Objects.equals(eventType, EventType.REFUND_SUCCESS.event))) {
log.error("wechat pay event type is not matched, callbackParams {}", callbackParams);
throw new PayException(" wechat pay event type is not matched");
}
String data = this.decrypt(callbackParams);
PartnerRefundConsumeData consumeData = MAPPER.readValue(data, PartnerRefundConsumeData.class);
consumeDataConsumer.accept(consumeData);
return response();
}
/**
* 直连商户-微信支付分账V3动账通知
*
* @param params the params
* @param profitsharingConsumeDataConsumer the profitsharing consume data consumer
@@ -402,6 +428,55 @@ public class WechatPayCallback {
return response();
}
/**
* 服务商-微信支付分账V3动账通知电商收付通复用
*
* @param params the params
* @param profitsharingConsumeDataConsumer the profitsharing consume data consumer
* @return map map
* @since 1.0.14.RELEASE
*/
@SneakyThrows
public Map<String, String> partnerProfitsharingCallback(ResponseSignVerifyParams params, Consumer<PartnerProfitsharingConsumeData> profitsharingConsumeDataConsumer) {
String callback = this.callback(params, EventType.TRANSACTION_SUCCESS);
PartnerProfitsharingConsumeData consumeData = MAPPER.readValue(callback, PartnerProfitsharingConsumeData.class);
profitsharingConsumeDataConsumer.accept(consumeData);
return response();
}
/**
* 服务商、直连商户 智慧商圈支付回调
* <p>
* 无需开发者判断,只有扣款成功微信才会回调此接口
*
* @param params the params
* @param consumeDataConsumer the consume data consumer
* @return the map
* @since 1.0.14.RELEASE
*/
@SneakyThrows
public Map<String, String> mallTransactionCallback(ResponseSignVerifyParams params, Consumer<MallTransactionConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.MALL_TRANSACTION_SUCCESS);
MallTransactionConsumeData consumeData = MAPPER.readValue(data, MallTransactionConsumeData.class);
consumeDataConsumer.accept(consumeData);
return response();
}
/**
* 服务商、直连商户 智慧商圈退款回调
*
* @param params the params
* @param consumeDataConsumer the consume data consumer
* @return the map
* @since 1.0.14.RELEASE
*/
@SneakyThrows
public Map<String, String> mallRefundCallback(ResponseSignVerifyParams params, Consumer<MallRefundConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.MALL_REFUND_SUCCESS);
MallRefundConsumeData consumeData = MAPPER.readValue(data, MallRefundConsumeData.class);
consumeDataConsumer.accept(consumeData);
return response();
}
/**
* Callback.
*
@@ -552,6 +627,12 @@ public class WechatPayCallback {
* @since 1.0.0.RELEASE
*/
TRANSACTION_SUCCESS("TRANSACTION.SUCCESS"),
/**
* 智慧商圈支付
*
* @since 1.0.14.RELEASE
*/
MALL_TRANSACTION_SUCCESS("MALL_TRANSACTION.SUCCESS"),
/**
* 支付分停车支付失败通知
*/
@@ -567,6 +648,12 @@ public class WechatPayCallback {
* @since 1.0.6.RELEASE
*/
REFUND_SUCCESS("REFUND.SUCCESS"),
/**
* 智慧商圈退款成功事件.
*
* @since 1.0.14.RELEASE
*/
MALL_REFUND_SUCCESS("MALL_REFUND.SUCCESS"),
/**
* 退款异常事件.

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -96,6 +94,7 @@ public class WechatPayClient {
* The V3 pay type.
*/
private final WechatPayV3Type wechatPayV3Type;
/**
* The Rest operations.
*/
@@ -216,7 +215,9 @@ public class WechatPayClient {
HttpHeaders headers = requestEntity.getHeaders();
String body = requestEntity.hasBody() ? Objects.requireNonNull(requestEntity.getBody()).toString() : "";
if (WechatPayV3Type.MARKETING_IMAGE_UPLOAD.pattern().contains(canonicalUrl)) {
if (WechatPayV3Type.MARKETING_IMAGE_UPLOAD.pattern().contains(canonicalUrl) ||
WechatPayV3Type.MERCHANT_MEDIA_IMG.pattern().contains(canonicalUrl) ||
WechatPayV3Type.MERCHANT_MEDIA_VIDEO.pattern().contains(canonicalUrl)) {
body = Objects.requireNonNull(headers.get("Meta-Info")).get(0);
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;
@@ -22,6 +20,7 @@ import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.TarType;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.RefundParams;
import cn.felord.payment.wechat.v3.model.payscore.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.util.LinkedMultiValueMap;
@@ -248,21 +247,18 @@ public class WechatPayScoreApi extends AbstractApi {
}
/**
* 商户发起催收扣款API
* 同步服务订单信息API
* <p>
* 前条件:服务订单支付状态处于“待支付”状态
* 前条件:同步商户渠道收款成功信息时,即场景类型=“Order_Paid”订单的状态需为[MCH_COMPLETE:商户完结订单]
* <p>
* 当微信支付分订单支付状态处于“待支付”时,商户可使用该接口向用户发起收款
* <p>
* 注意:
* • 此能力不影响微信支付分代商户向用户发起收款的策略。
* 由于收款商户进行的某些“线下操作”会导致微信支付侧的订单状态与实际情况不符。例如,用户通过线下付款的方式已经完成支付,而微信支付侧并未支付成功,此时可能导致用户重复支付。因此商户需要通过订单同步接口将订单状态同步给微信支付,修改订单在微信支付系统中的状态
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> payServiceOrder(PayServiceOrderParams params) {
public WechatResponseEntity<ObjectNode> syncServiceOrder(SyncServiceOrderParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_PAY_USER_SERVICE_ORDER, params)
this.client().withType(WechatPayV3Type.PAY_SCORE_SYNC_USER_SERVICE_ORDER, params)
.function((wechatPayV3Type, orderParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
@@ -280,18 +276,69 @@ public class WechatPayScoreApi extends AbstractApi {
}
/**
* 同步服务订单信息API
* 申请退款API
*
* @param refundParams the refund params
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> refund(RefundParams refundParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.REFUND, refundParams)
.function(((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
String notifyUrl = params.getNotifyUrl();
if (StringUtils.hasText(notifyUrl)) {
params.setNotifyUrl(v3.getDomain().concat(notifyUrl));
}
return Post(uri, params);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询单笔退款API
*
* @param outRefundNo the out refund no
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> queryRefundInfo(String outRefundNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.QUERY_REFUND, outRefundNo)
.function(((type, param) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(param)
.toUri();
return Get(uri);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 商户发起催收扣款API
* <p>
* 前条件:同步商户渠道收款成功信息时,即场景类型=“Order_Paid”订单的状态需为[MCH_COMPLETE:商户完结订单]
* 前条件:服务订单支付状态处于“待支付”状态
* <p>
* 由于收款商户进行的某些“线下操作”会导致微信支付侧的订单状态与实际情况不符。例如,用户通过线下付款的方式已经完成支付,而微信支付侧并未支付成功,此时可能导致用户重复支付。因此商户需要通过订单同步接口将订单状态同步给微信支付,修改订单在微信支付系统中的状态
* 当微信支付分订单支付状态处于“待支付”时,商户可使用该接口向用户发起收款
* <p>
* 注意:
* • 此能力不影响微信支付分代商户向用户发起收款的策略。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> syncServiceOrder(SyncServiceOrderParams params) {
public WechatResponseEntity<ObjectNode> payServiceOrder(PayServiceOrderParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_SYNC_USER_SERVICE_ORDER, params)
this.client().withType(WechatPayV3Type.PAY_SCORE_PAY_USER_SERVICE_ORDER, params)
.function((wechatPayV3Type, orderParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
@@ -490,7 +537,7 @@ public class WechatPayScoreApi extends AbstractApi {
queryParams.add("bill_date", billDate.format(DateTimeFormatter.ISO_DATE));
queryParams.add("tar_type", TarType.GZIP.name());
queryParams.add("encryption_algorithm", "AEAD_AES_256_GCM");
queryParams.add("service_id",billParams.getServiceId());
queryParams.add("service_id", billParams.getServiceId());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)

View File

@@ -20,6 +20,7 @@ package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.RefundParams;
import cn.felord.payment.wechat.v3.model.ResponseSignVerifyParams;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingServiceQueryParams;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingParams;
@@ -27,6 +28,7 @@ import cn.felord.payment.wechat.v3.model.payscore.parking.TransParkingParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
@@ -74,6 +76,7 @@ public class WechatPayScoreParkingApi extends AbstractApi {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.encode()
.build()
.toUri();
return Get(uri);
@@ -157,4 +160,53 @@ public class WechatPayScoreParkingApi extends AbstractApi {
.request();
return wechatResponseEntity;
}
/**
* 申请退款API
*
* @param refundParams the refund params
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> refund(RefundParams refundParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.REFUND, refundParams)
.function(((type, params) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
String notifyUrl = params.getNotifyUrl();
if (StringUtils.hasText(notifyUrl)) {
params.setNotifyUrl(v3.getDomain().concat(notifyUrl));
}
return Post(uri, params);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询单笔退款API
*
* @param outRefundNo the out refund no
* @return the wechat response entity
* @since 1.0.17.RELEASE
*/
public WechatResponseEntity<ObjectNode> queryRefundInfo(String outRefundNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.QUERY_REFUND, outRefundNo)
.function(((type, param) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(param)
.toUri();
return Get(uri);
}))
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -22,7 +22,9 @@ import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.profitsharing.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -316,7 +318,7 @@ public class WechatProfitsharingApi extends AbstractApi {
* @return the wechat response entity
* @since 1.0.13.RELEASE
*/
public WechatResponseEntity<ObjectNode> downloadMerchantBills(ProfitsharingBillParams billParams){
public ResponseEntity<Resource> downloadMerchantBills(ProfitsharingBillParams billParams){
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PROFITSHARING_BILLS,billParams)
.function(((wechatPayV3Type, params) -> {
@@ -335,7 +337,13 @@ public class WechatProfitsharingApi extends AbstractApi {
return Get(uri);
})).consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
String downloadUrl = Objects.requireNonNull(wechatResponseEntity.getBody())
.get("download_url")
.asText();
String ext = Objects.equals(TarType.GZIP, billParams.getTarType()) ? ".gzip" : ".txt";
String filename = "profitsharingbill-" + billParams.getBillDate().toString() + ext;
return this.downloadBillResponse(downloadUrl, filename);
}
}

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -1,5 +1,4 @@
/*
*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.felord.payment.wechat.v3;

View File

@@ -0,0 +1,196 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.smartguide.PartnerAssignParams;
import cn.felord.payment.wechat.v3.model.smartguide.PartnerSmartGuidesParams;
import cn.felord.payment.wechat.v3.model.smartguide.PartnerSmartGuidesQueryParams;
import cn.felord.payment.wechat.v3.model.smartguide.SmartGuidesModifyParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
/**
* 微信V3服务商或者直连商户-经营能力-支付即服务
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class WechatSmartGuideApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatSmartGuideApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 服务人员注册API
* <p>
* 用于开发者为商户注册服务人员使用。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> register(PartnerSmartGuidesParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SMART_GUIDES, params)
.function((wechatPayV3Type, smartGuidesParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, smartGuidesParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 服务人员分配API
* <p>
* 用于开发者在顾客下单后为顾客分配服务人员使用。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> assign(PartnerAssignParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SMART_GUIDES_ASSIGN, params)
.function((wechatPayV3Type, assignParams) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.expand(assignParams.getGuideId())
.toUri();
Map<String, String> map = new HashMap<>(2);
map.put("sub_mchid", assignParams.getSubMchid());
map.put("out_trade_no", assignParams.getOutTradeNo());
return Post(uri, map);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 服务人员查询API
* <p>
* 用于商户开发者查询已注册的服务人员ID等信息。
* <p>
* 成功返回后请自行使用{@link SignatureProvider#decryptResponseMessage(String, String)}解密敏感字段。
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> query(PartnerSmartGuidesQueryParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SMART_GUIDES_GET, params)
.function((wechatPayV3Type, smartGuidesQueryParams) -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Pay-TenantId",this.tenantId());
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
String subMchid = smartGuidesQueryParams.getSubMchid();
if (subMchid != null) {
queryParams.add("sub_mchid", subMchid);
}
queryParams.add("store_id", String.valueOf(smartGuidesQueryParams.getStoreId()));
String userid = smartGuidesQueryParams.getUserid();
if (userid != null) {
queryParams.add("userid", userid);
}
String mobile = smartGuidesQueryParams.getMobile();
if (mobile != null) {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
queryParams.add("mobile", signatureProvider.encryptRequestMessage(mobile, x509Certificate));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
}
String workId = smartGuidesQueryParams.getWorkId();
if (workId != null) {
queryParams.add("work_id", workId);
}
Integer offset = smartGuidesQueryParams.getOffset();
if (offset != null) {
queryParams.add("offset", String.valueOf(offset));
}
Integer limit = smartGuidesQueryParams.getLimit();
if (limit != null) {
queryParams.add("limit", String.valueOf(limit));
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return RequestEntity.get(uri).headers(httpHeaders)
.build();
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 服务人员信息更新API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> modify(SmartGuidesModifyParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.SMART_GUIDES_MODIFY, params)
.function((wechatPayV3Type, smartGuidesParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Patch(uri, smartGuidesParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.ecommerce;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.AbstractApi;
import cn.felord.payment.wechat.v3.SignatureProvider;
import cn.felord.payment.wechat.v3.WechatPartnerSpecialMchApi;
import cn.felord.payment.wechat.v3.WechatPayClient;
import cn.felord.payment.wechat.v3.WechatResponseEntity;
import cn.felord.payment.wechat.v3.X509WechatCertificateInfo;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceAccountInfo;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceApplymentParams;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceContactInfo;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceIdCardInfo;
import cn.felord.payment.wechat.v3.model.ecommerce.EcommerceIdDocInfo;
import cn.felord.payment.wechat.v3.model.ecommerce.UboInfo;
import cn.felord.payment.wechat.v3.model.specmch.SubMchModifyParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.security.cert.X509Certificate;
/**
* 电商收付通-商户进件
*
* @author felord.cn
* @since 1.0.14.RELEASE
*/
public class ApplymentApi extends AbstractApi {
private final WechatPartnerSpecialMchApi wechatPartnerSpecialMchApi;
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
ApplymentApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
this.wechatPartnerSpecialMchApi = new WechatPartnerSpecialMchApi(wechatPayClient, tenantId);
}
/**
* 二级商户进件申请API
*
* @param params the params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> apply(EcommerceApplymentParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT, params).function((wechatPayV3Type, applymentParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
EcommerceApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)).build().toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, applyRequestParams, httpHeaders);
}).consumer(wechatResponseEntity::convert).request();
return wechatResponseEntity;
}
/**
* 通过申请单ID查询申请状态API
*
* @param applymentId the applyment id
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryByApplymentId(String applymentId) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT_ID, applymentId).function((type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)).build().expand(id).toUri();
return Get(uri);
}).consumer(wechatResponseEntity::convert).request();
return wechatResponseEntity;
}
/**
* 通过业务申请编号查询申请状态API
*
* @param outRequestNo the outRequestNo
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryByBusinessCode(String outRequestNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT_OUT_REQUEST_NO, outRequestNo).function((type, id) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA)).build().expand(id).toUri();
return Get(uri);
}).consumer(wechatResponseEntity::convert).request();
return wechatResponseEntity;
}
/**
* 修改结算账号API
*
* @param params the params
* @return wechat response entity
* @see WechatPartnerSpecialMchApi#modify(SubMchModifyParams)
*/
public WechatResponseEntity<ObjectNode> modify(SubMchModifyParams params) {
return this.wechatPartnerSpecialMchApi.modify(params);
}
/**
* 查询结算账户API
* <p>
* 服务商/电商平台(不包括支付机构、银行),可使用本接口,查询其进件且已签约特约商户/二级商户的结算账户信息(敏感信息掩码)。
* 该接口可用于核实是否成功修改结算账户信息、及查询系统汇款验证结果。
*
* @param subMchid the sub mchid
* @return the wechat response entity
* @see WechatPartnerSpecialMchApi#querySettlement(String)
*/
public WechatResponseEntity<ObjectNode> querySettlement(String subMchid) {
return this.wechatPartnerSpecialMchApi.querySettlement(subMchid);
}
private EcommerceApplymentParams convert(EcommerceApplymentParams applymentParams, SignatureProvider signatureProvider, X509Certificate x509Certificate) {
EcommerceIdCardInfo idCardInfo = applymentParams.getIdCardInfo();
if (idCardInfo != null) {
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
String idCardAddress = idCardInfo.getIdCardAddress();
if (StringUtils.hasText(idCardAddress)) {
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
}
}
EcommerceIdDocInfo idDocInfo = applymentParams.getIdDocInfo();
if (idDocInfo != null) {
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
String idDocAddress = idDocInfo.getIdDocAddress();
if (StringUtils.hasText(idDocAddress)) {
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
}
}
UboInfo uboInfo = applymentParams.getUboInfo();
if (uboInfo != null) {
UboInfo.IdCardInfo cardInfo = uboInfo.getIdCardInfo();
if (cardInfo != null) {
cardInfo.setIdCardName(signatureProvider.encryptRequestMessage(cardInfo.getIdCardName(), x509Certificate));
cardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(cardInfo.getIdCardNumber(), x509Certificate));
}
UboInfo.IdDocInfo docInfo = uboInfo.getIdDocInfo();
if (docInfo != null) {
docInfo.setIdDocName(signatureProvider.encryptRequestMessage(docInfo.getIdDocName(), x509Certificate));
docInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(docInfo.getIdDocNumber(), x509Certificate));
}
}
EcommerceAccountInfo accountInfo = applymentParams.getAccountInfo();
if (accountInfo != null) {
accountInfo.setAccountName(signatureProvider.encryptRequestMessage(accountInfo.getAccountName(), x509Certificate));
accountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(accountInfo.getAccountNumber(), x509Certificate));
}
EcommerceContactInfo contactInfo = applymentParams.getContactInfo();
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
contactInfo.setContactIdCardNumber(signatureProvider.encryptRequestMessage(contactInfo.getContactIdCardNumber(), x509Certificate));
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), x509Certificate));
String contactEmail = contactInfo.getContactEmail();
if (contactEmail != null) {
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactEmail, x509Certificate));
}
return applymentParams;
}
}

Some files were not shown because too many files have changed in this diff Show More