1 | # Notadd 支付插件
|
2 |
|
3 | 整合微信支付API、支付宝支付API,基于 Nest.js 框架构建的一个支付插件。
|
4 |
|
5 | ## 使用说明
|
6 |
|
7 | 使用前,请确保了解微信支付、支付宝支付的各类支付流程,且具备基本的 `debug` 能力。
|
8 |
|
9 | ### 安装
|
10 |
|
11 | `npm install @notadd/addon-pay`
|
12 |
|
13 | ### 配置 PayAddon
|
14 |
|
15 | ```typescript
|
16 | import { Module } from '@nestjs/common';
|
17 | import { PayAddon } from '@notadd/addon-pay';
|
18 |
|
19 | @Module({
|
20 | imports: [
|
21 | PayAddon.forRoot({
|
22 | wechatConfig: {
|
23 | appid: 'appid', // 公众号appi/应用appid/小程序appid
|
24 | mch_id: 'mch_id', // 商户号
|
25 | secretKey: 'secretKey', // 商户交易秘钥
|
26 | sign_type: 'MD5', // 微信支付签名类型('MD5' | 'HMAC-SHA256'),默认MD5,配置后,所有接口参数均会使用这个签名类型
|
27 | pfx: fs.readFileSync('path_to_p12_file'), // p12文件
|
28 | sandbox: true // 是否启用沙箱环境,默认不启用,用于商户支付验收测试
|
29 | }
|
30 | })
|
31 | ]
|
32 | })
|
33 | export class ApplicationModule {}
|
34 | ```
|
35 |
|
36 | ### 微信支付
|
37 |
|
38 | 接口使用前的必要声明:
|
39 |
|
40 | 1. 所有的接口请求参数和接口返回结果中的属性名全部使用的是 **`snake_case`**,其中属性名结尾带 **`?`** 的代表这个属性是可选的(非必填)。
|
41 | 2. 所有与金额相关的数据全部是 **`number`** 类型且单位为 **`分`**,需自行转换。
|
42 | 3. 所有接口参数中的 `mch_id`、`appid/wxappid`、`nonce_str`、`sign_type`、`sign` 数据均由插件自动填入,无需手动传入。
|
43 | 4. 所有请求的返回结果若有 `sign`,插件会自动验签。
|
44 | 5. 支付通知结果插件会自动验签,退款通知结果插件会自动解密 `req_info` 数据。
|
45 |
|
46 | #### 使用 WeChat`XXX`PayService 调用 API
|
47 |
|
48 | WeChat`XXX`PayService 类包含当前支付方式的支付、订单、退款相关 API,各支付类说明:
|
49 |
|
50 | - WeChatAppPayService —— APP支付
|
51 | - WeChatAppletPayService —— 小程序支付
|
52 | - WeChatJSAPIPayService —— JSAPI支付(用户通过微信扫码、关注公众号等方式进入商家H5页面,并在微信内调用JSSDK完成支付)
|
53 | - WeChatMicroPayService —— 付款码支付(用户打开微信钱包-付款码的界面,商户扫码后提交完成支付)
|
54 | - WeChatNativePayService —— Native支付(扫码支付)
|
55 | - WeChatWapPayService —— H5支付(用户在微信以外的手机浏览器请求微信支付的场景唤起微信支付)
|
56 | - WeChatRedpackService —— 现金红包
|
57 | - WeChatTransferService —— 企业付款
|
58 |
|
59 | 例子:Native支付(扫码支付)调用方式如下
|
60 |
|
61 | ```typescript
|
62 | import { Injectable, Inject } from '@nestjs/common';
|
63 | import { WeChatNativePayService, WeChatTradeType } from '@notadd/addon-pay';
|
64 |
|
65 | @Injectable()
|
66 | export class TestPay {
|
67 | constructor(@Inject(WeChatNativePayService) private readonly weChatNativePayService: WeChatNativePayService) { }
|
68 |
|
69 | async nativePay() {
|
70 | const ressult = await this.weChatNativePayService.pay({
|
71 | body: '支付一下',
|
72 | out_trade_no: '201811271512000001',
|
73 | total_fee: 301,
|
74 | spbill_create_ip: '127.0.0.1', // 支付请求方IP
|
75 | notify_url: 'your.domain.com/payment/wechat_order_notify', // 服务端支付通知地址
|
76 | trade_type: WeChatTradeType.JSAPI
|
77 | });
|
78 | }
|
79 | }
|
80 | ```
|
81 |
|
82 | #### 使用 WeChatNotifyParserUtil 解析支付/退款通知
|
83 |
|
84 | 支付/退款完成后,微信会把相关支付/退款结果和用户信息发送给商户,商户需要接收处理,并返回应答。
|
85 |
|
86 | 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
|
87 |
|
88 | 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
|
89 |
|
90 | 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处 理前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
|
91 |
|
92 | ```typescript
|
93 | import { Controller, Inject, Post, Req } from '@nestjs/common';
|
94 |
|
95 | import { WeChatNotifyParserUtil } from '@notadd/addon-pay';
|
96 |
|
97 | @Controller('payment')
|
98 | export class PaymentNotifyController {
|
99 | constructor(
|
100 | @Inject(WeChatNotifyParserUtil) private readonly weChatNotifyParserUtil: WeChatNotifyParserUtil
|
101 | ) { }
|
102 |
|
103 | /**
|
104 | * 微信支付统一下单通知路由
|
105 | *
|
106 | * 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。
|
107 | *
|
108 | * 技术人员可登进微信商户后台扫描加入接口报警群。
|
109 | *
|
110 | * @param req 通知请求
|
111 | */
|
112 | @Post('wechat_order_notify')
|
113 | async weChatOrderNotify(@Req() req) {
|
114 | // 当 data 为 undefined 时,表示通知请求中的 sign 验签失败
|
115 | const data = await this.weChatNotifyParserUtil.parsePayNotify(req);
|
116 |
|
117 | // 验签失败时
|
118 | if (!data) {
|
119 | // 微信会重新发起通知
|
120 | return this.weChatNotifyParserUtil.generateFailMessage('验签失败');
|
121 | }
|
122 |
|
123 | // 判断返回状态,失败时
|
124 | if(data.return_code === 'FAIL') {
|
125 | // 处理业务数据
|
126 | // ......
|
127 |
|
128 | // 根据情况返回成功或失败消息
|
129 | }
|
130 |
|
131 | // 判断业务状态,失败时
|
132 | if(data.result_code === 'FAIL') {
|
133 | // 处理业务数据
|
134 | // ......
|
135 |
|
136 | // 根据情况返回成功或失败消息
|
137 | }
|
138 |
|
139 | // 成功时返回
|
140 | return this.weChatNotifyParserUtil.generateSuccessMessage();
|
141 | }
|
142 |
|
143 | /**
|
144 | * 微信支付退款通知路由
|
145 | *
|
146 | * 特别说明:退款结果对重要的数据进行了加密,商户需要用商户秘钥进行解密后才能获得结果通知的内容。
|
147 | *
|
148 | * @param req 通知请求
|
149 | */
|
150 | @Post('wechat_refund_notify')
|
151 | async weChatRefundNotify(@Req() req) {
|
152 | // 当 data 为 undefined 时,表示通知请求中的 req_info 解密失败
|
153 | const data = await this.weChatNotifyParserUtil.parseRefundNotify(req);
|
154 |
|
155 | // 解密失败时
|
156 | if (!data) {
|
157 | // 微信会重新发起通知
|
158 | return this.weChatNotifyParserUtil.generateFailMessage('解密失败');
|
159 | }
|
160 |
|
161 | // 判断返回状态,失败时
|
162 | if(data.return_code === 'FAIL') {
|
163 | // 处理业务数据
|
164 | // ......
|
165 |
|
166 | // 根据情况返回成功或失败消息
|
167 | }
|
168 |
|
169 | // 成功时返回
|
170 | return this.weChatNotifyParserUtil.generateSuccessMessage();
|
171 | }
|
172 | }
|
173 | ```
|
174 |
|
175 | #### 如何使用支付验收 case ?
|
176 |
|
177 | 两种方式,如下:
|
178 |
|
179 | 1. 关注微信公众号:微信支付商户接入验收助手,并查阅相应支付验收 case 示例。
|
180 | 2. 下载支付验收case示例 pdf 文档。地址:[免充值产品测试验收用例](https://pay.weixin.qq.com/wiki/doc/api/download/mczyscsyl.pdf) 。
|
181 |
|
182 | ### 支付宝支付
|
183 |
|
184 | *TODO*
|
185 |
|
186 | ## 贡献说明
|
187 |
|
188 | 我们欢迎 Nest.js 使用者来参与这个插件的开发,作为一个贡献者,请您遵循以下原则:
|
189 |
|
190 | - 代码提交规范,参考 [Git Commit Message Conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
|
191 | - 始终从 develop checkout 一个新分支,命名规范为 feature/xxx,xxx 必须具有可读性,如:微信-普通商户版-扫码支付 => feature/wechat-native-pay
|
192 | - 在 checkout 新分支前,先在本地 develop 分支拉取远程 develop 分支的最新代码
|
193 | - 文件命名规则请参考项目目前的命名规则,如:微信支付中,order.interface.ts 代表所有订单相关的请求参数和返回结果的定义,micro.pay.service.ts 代表付款码支付的业务逻辑
|
194 |
|
195 | ## 功能开发
|
196 |
|
197 | 请先查阅 Roadmap,确保你想贡献的功能没有正在被实现。然后在 **issue** 里提交一个贡献请求,注明想要贡献的功能。
|
198 |
|
199 | ## 发现 Bug ?
|
200 |
|
201 | 如果你在源码中发现bug,请你先在本仓库的 **issue** 提交一个bug问题。在你提交完bug问题后,我们很乐意接受你提交一个 **PR** 来帮助我们修复这个bug。
|
202 |
|
203 | ## QQ 交流群
|
204 |
|
205 | 322247106,请注明加群目的!
|
206 |
|
207 | ## Roadmap
|
208 |
|
209 | - [x] **0.0.1** 贡献说明
|
210 | - [x] **0.1.0** 微信-普通商户版-APP支付
|
211 | - [x] **0.2.0** 微信-普通商户版-JSAPI支付、微信-普通商户版-Native支付、微信-普通商户版-H5支付、微信-普通商户版-小程序支付
|
212 | - [x] **0.3.0** 微信-普通商户版-付款码支付
|
213 | - [x] **0.4.0** 微信-普通商户版-现金红包
|
214 | - [x] **0.5.0** 微信-普通商户版-企业付款
|
215 | - [ ] **0.6.0** 支付宝-APP支付
|
216 | - [ ] **0.7.0** 支付宝-当面付
|
217 | - [ ] **0.8.0** 支付宝-手机网站支付
|
218 | - [ ] **0.9.0** 支付宝-电脑网站支付
|
219 | - [ ] **1.0.0** 完善使用说明、发布正式版v1.0.0 |
\ | No newline at end of file |