wechat_payment 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +215 -13
- data/Rakefile +5 -0
- data/app/assets/config/wechat_payment_manifest.js +1 -0
- data/app/assets/stylesheets/wechat_payment/application.css +15 -0
- data/app/controllers/wechat_payment/application_controller.rb +5 -0
- data/app/controllers/wechat_payment/callback_controller.rb +30 -0
- data/app/helpers/wechat_payment/application_helper.rb +4 -0
- data/app/jobs/wechat_payment/application_job.rb +4 -0
- data/app/mailers/wechat_payment/application_mailer.rb +6 -0
- data/app/models/wechat_payment/application_record.rb +5 -0
- data/app/models/wechat_payment/payment_order.rb +228 -0
- data/app/models/wechat_payment/refund_order.rb +127 -0
- data/app/services/wechat_payment/service.rb +74 -0
- data/app/views/layouts/wechat_payment/application.html.erb +15 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20210706075217_create_wechat_payment_payment_orders.rb +22 -0
- data/db/migrate/20210706095205_create_wechat_payment_refund_orders.rb +20 -0
- data/lib/generators/wechat_payment/goods/USAGE +8 -0
- data/lib/generators/wechat_payment/goods/goods_generator.rb +5 -0
- data/lib/generators/wechat_payment/install/USAGE +8 -0
- data/lib/generators/wechat_payment/install/install_generator.rb +86 -0
- data/lib/generators/wechat_payment/install/templates/initializer.rb +19 -0
- data/lib/generators/wechat_payment/routes/USAGE +8 -0
- data/lib/generators/wechat_payment/routes/routes_generator.rb +7 -0
- data/lib/tasks/wechat_payment_tasks.rake +10 -0
- data/lib/wechat_payment.rb +40 -2
- data/lib/wechat_payment/client.rb +272 -0
- data/lib/wechat_payment/concern/goods.rb +80 -0
- data/lib/wechat_payment/concern/user.rb +22 -0
- data/lib/wechat_payment/concern/user_goods.rb +14 -0
- data/lib/wechat_payment/engine.rb +7 -0
- data/lib/wechat_payment/invoke_result.rb +35 -0
- data/lib/wechat_payment/missing_key_error.rb +4 -0
- data/lib/wechat_payment/r_logger.rb +36 -0
- data/lib/wechat_payment/service_result.rb +49 -0
- data/lib/wechat_payment/sign.rb +41 -0
- data/lib/wechat_payment/version.rb +1 -1
- metadata +68 -9
- data/lib/wechat_payment/railtie.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a2e445d0e1ce0d2cc83eef761a18bbd90ade6264e2798e2ce0a1bc1756b9139
|
4
|
+
data.tar.gz: bcfbaf1b877b6a7656cb378a894293c593e96862b018c9415eac13ed00063961
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3157ecac086e7f9d491d1359f4ce3de8208068f277a041c9a57d9b20abd6406d1648fce5d11c25f6cbc9d8f6aea64b24e2477383c73a775212b2ac11d42bf2c
|
7
|
+
data.tar.gz: 3e41d27212801e96e9c359cb60a6a51f6c7e63cd4dbcbcd3deaba2c0ee72c13a55423e538422b1ff952602ef05717cb5df3c6d0a75dda131c6f3befff9aa6dcd
|
data/README.md
CHANGED
@@ -1,28 +1,230 @@
|
|
1
1
|
# WechatPayment
|
2
|
-
|
2
|
+
微信支付的 engine
|
3
3
|
|
4
|
-
## Usage
|
5
|
-
How to use my plugin.
|
6
4
|
|
7
|
-
##
|
8
|
-
|
5
|
+
## Convention
|
6
|
+
在使用该 Engine 之前,需要先建立`用户模型`,`商品模型`,`用户商品关联模型`,用户表需要有 open_id 字段,
|
7
|
+
商品表需要有 price 和 name 字段。假设`商品模型`为`Product`,则用户和商品之间的关联模型为`UserProduct`,
|
8
|
+
关联模型属于`user`和`product`。
|
9
|
+
|
10
|
+
## Getting Started
|
11
|
+
1. 在`Gemfile`中添加
|
12
|
+
```ruby
|
13
|
+
gem 'wechat_payment'
|
14
|
+
```
|
15
|
+
|
16
|
+
2. 执行 `bundle install`
|
17
|
+
|
18
|
+
3. 初始化
|
19
|
+
```bash
|
20
|
+
# rails g wechat_payment:install [GoodsModel] [UserModel]
|
21
|
+
$ rails g wechat_payment:install Product User
|
22
|
+
$ rails db:migrate
|
23
|
+
```
|
24
|
+
|
25
|
+
## 配置
|
26
|
+
打开 `config/initializers/wechat_payment.rb`,將里边的配置改成你自己的小程序配置
|
27
|
+
|
28
|
+
## 支付
|
29
|
+
用户模型具有`buy`方法,而商品模型有`sell`方法,用户购买商品或商品售出都会产生一张订单,
|
30
|
+
调用订单的`pay`方法则会向微信发起下单请求,并将处理后的结果返回,此时返回的是一个`ServiceResult`对象,
|
31
|
+
执行该对象的`as_json`方法,得到的就是小程序需要拉起支付的参数
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
user = User.first
|
35
|
+
|
36
|
+
product = Product.first
|
37
|
+
|
38
|
+
# 微信要传一个用户调起支付的 ip: spbill_create_ip ,文档上写必传,但是传空、固定ip、不传都不会报错,
|
39
|
+
# 但是还是给他加上了,保存到用户模型的 last_spbill_create_ip 属性上,实际使用中可以
|
40
|
+
# 在控制器里边通过 request.remote_ip 获取请求的 ip
|
41
|
+
#
|
42
|
+
# user.spbill_create_ip = request.remote_ip
|
43
|
+
client_ip = "45.12.112.31"
|
44
|
+
user.spbill_create_ip = client_ip
|
45
|
+
|
46
|
+
order = user.buy(product)
|
47
|
+
|
48
|
+
result = order.pay
|
49
|
+
|
50
|
+
# 返回给前端调起支付的数据
|
51
|
+
result.as_json
|
52
|
+
```
|
53
|
+
|
54
|
+
## 退款
|
55
|
+
调用订单的`refund`,参数是退款金额,默认全额退款,执行成功后会创建一张退款订单,此时退款订单状态为 pending,
|
56
|
+
并返回退款下单的结果(`SerivceResult`对象),如果成功,触发用户商品关联模型的`refund_apply_success`,
|
57
|
+
失败则触发`refund_apply_failure`
|
9
58
|
|
10
59
|
```ruby
|
11
|
-
|
60
|
+
payment_order = User.first.payment_orders.last
|
61
|
+
result = payment_order.refund
|
62
|
+
|
63
|
+
if result.success?
|
64
|
+
# do something on success
|
65
|
+
else
|
66
|
+
# do something on failure
|
67
|
+
end
|
12
68
|
```
|
13
69
|
|
14
|
-
|
15
|
-
|
16
|
-
|
70
|
+
## 事件
|
71
|
+
当支付进行时,会产生一些相应的事件,事件会触发相应的钩子,如果有事先定义的话。钩子方法需定义在用户商品关联(如`UserProduct`)模型中,
|
72
|
+
且每个钩子接收一个参数 result ,事件和钩子的对应关系如下:
|
73
|
+
|
74
|
+
| 事件 | 钩子 |
|
75
|
+
| :-------------- | :--------------- |
|
76
|
+
| 支付下单成功 | payment_apply_success |
|
77
|
+
| 支付下单失败 | payment_apply_failure |
|
78
|
+
| 支付成功(回调) | payment_exec_success |
|
79
|
+
| 支付失败(回调) | payment_exec_failure |
|
80
|
+
| 申请退款成功 | refund_apply_success |
|
81
|
+
| 申请退款失败 | refund_apply_failure |
|
82
|
+
| 退款成功(回调) | refund_exec_success |
|
83
|
+
| 退款失败(回调) | refund_exec_failure |
|
84
|
+
|
85
|
+
一个简单的事件处理的例子
|
86
|
+
```ruby
|
87
|
+
# app/model/user_product.rb
|
88
|
+
class UserProduct
|
89
|
+
# result 结构见下文说明
|
90
|
+
def payment_exec_success(result)
|
91
|
+
update(state: :paid)
|
92
|
+
end
|
93
|
+
end
|
17
94
|
```
|
18
95
|
|
19
|
-
|
20
|
-
|
21
|
-
|
96
|
+
每个钩子接收的参数结构可能不一样:
|
97
|
+
|
98
|
+
### payment_apply_success:
|
99
|
+
```ruby
|
100
|
+
{
|
101
|
+
"return_code"=>"SUCCESS",
|
102
|
+
"return_msg"=>"OK",
|
103
|
+
"result_code"=>"SUCCESS",
|
104
|
+
"mch_id"=>"12312412312",
|
105
|
+
"appid"=>"wxc5acd06cc6a7ac12",
|
106
|
+
"sub_mch_id"=>"1526921451",
|
107
|
+
"sub_appid"=>"wxf89f912345823dcd",
|
108
|
+
"nonce_str"=>"ZUN2rEf6ATgYU8Lr",
|
109
|
+
"sign"=>"3A216DB61196CE2313CE21182D53FD1833F",
|
110
|
+
"prepay_id"=>"wx2815535651598812181c452eb3f26b90000",
|
111
|
+
"trade_type"=>"JSAPI"
|
112
|
+
}
|
22
113
|
```
|
23
114
|
|
115
|
+
### payment_apply_failure:
|
116
|
+
```ruby
|
117
|
+
{
|
118
|
+
"return_code"=>"SUCCESS",
|
119
|
+
"return_msg"=>"OK",
|
120
|
+
"result_code"=>"FAIL",
|
121
|
+
"err_code_des"=>"该订单已支付",
|
122
|
+
"err_code"=>"ORDERPAID",
|
123
|
+
"mch_id"=>"12312412312",
|
124
|
+
"appid"=>"wxc5acd06cc6a7ac12",
|
125
|
+
"sub_mch_id"=>"1526921451",
|
126
|
+
"sub_appid"=>"wxf89f912345823dcd",
|
127
|
+
"nonce_str"=>"1jWLkg2YZjwnOozl",
|
128
|
+
"sign"=>"3C210A1C9BD6CFDB7C37CCFCA1AAF9E274"
|
129
|
+
}
|
130
|
+
```
|
131
|
+
|
132
|
+
### payment_exec_success:
|
133
|
+
```ruby
|
134
|
+
{
|
135
|
+
"appid" => "wxc5acd06cc6a7ac12",
|
136
|
+
"bank_type" => "CMB_CREDIT",
|
137
|
+
"cash_fee" => "1",
|
138
|
+
"fee_type" => "CNY",
|
139
|
+
"is_subscribe" => "N",
|
140
|
+
"mch_id" => "12312412312",
|
141
|
+
"nonce_str" => "e42ad44489a1f4e6f8a09d1299cfa59f6",
|
142
|
+
"openid" => "oef2nsaOcYcBYrNq1x9eUucKy7NQ",
|
143
|
+
"out_trade_no" => "16267654023120174189",
|
144
|
+
"result_code" => "SUCCESS",
|
145
|
+
"return_code" => "SUCCESS",
|
146
|
+
"sign" => "608972A854024030332360B1E79511B4",
|
147
|
+
"sub_appid" => "wxf89f912345823dcd",
|
148
|
+
"sub_is_subscribe" => "N",
|
149
|
+
"sub_mch_id" => "1526921451",
|
150
|
+
"sub_openid" => "oef2nsaOcYcBYrNq1x9eUucKy7NQ",
|
151
|
+
"time_end" => "20210720151228",
|
152
|
+
"total_fee" => "1",
|
153
|
+
"trade_type" => "JSAPI",
|
154
|
+
"transaction_id" => "4200001153233202137201270712453"
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
158
|
+
### payment_exec_failure:
|
159
|
+
TODO 待补充
|
160
|
+
|
161
|
+
### refund_apply_success:
|
162
|
+
```ruby
|
163
|
+
{
|
164
|
+
"return_code"=>"SUCCESS",
|
165
|
+
"return_msg"=>"OK",
|
166
|
+
"appid"=>"wxc5acd06cc6a7ac12",
|
167
|
+
"mch_id"=>"12312412312",
|
168
|
+
"sub_mch_id"=>"1526921451",
|
169
|
+
"nonce_str"=>"RsXVcs0GMg2p5NRD",
|
170
|
+
"sign"=>"F10AB3929B900DE4E189CA93B12D9D7A",
|
171
|
+
"result_code"=>"SUCCESS",
|
172
|
+
"transaction_id"=>"420000119112202101210049902399",
|
173
|
+
"out_trade_no"=>"1624867410141191608",
|
174
|
+
"out_refund_no"=>"16248674504421685776",
|
175
|
+
"refund_id"=>"50301108952025421210183695009",
|
176
|
+
"refund_channel"=>"",
|
177
|
+
"refund_fee"=>"1",
|
178
|
+
"coupon_refund_fee"=>"0",
|
179
|
+
"total_fee"=>"1",
|
180
|
+
"cash_fee"=>"1",
|
181
|
+
"coupon_refund_count"=>"0",
|
182
|
+
"cash_refund_fee"=>"1"
|
183
|
+
}
|
184
|
+
```
|
185
|
+
|
186
|
+
### refund_apply_failure:
|
187
|
+
```ruby
|
188
|
+
{
|
189
|
+
"return_code"=>"SUCCESS",
|
190
|
+
"return_msg"=>"OK",
|
191
|
+
"appid"=>"wxc5acd06cc6a7ac12",
|
192
|
+
"mch_id"=>"12312412312",
|
193
|
+
"sub_mch_id"=>"1526921451",
|
194
|
+
"nonce_str"=>"gMDFilvaKanXW80W",
|
195
|
+
"sign"=>"BA24E81B18B12AAC112DF9F84CA5E21",
|
196
|
+
"result_code"=>"FAIL",
|
197
|
+
"err_code"=>"INVALID_REQUEST",
|
198
|
+
"err_code_des"=>"订单已全额退款"
|
199
|
+
}
|
200
|
+
|
201
|
+
```
|
202
|
+
|
203
|
+
### refund_exec_success:
|
204
|
+
```ruby
|
205
|
+
{
|
206
|
+
"out_refund_no"=>"16421102919350974",
|
207
|
+
"out_trade_no"=>"1626761001219492162",
|
208
|
+
"refund_account"=>"REFUND_SOURCE_RECHARGE_FUNDS",
|
209
|
+
"refund_fee"=>"1",
|
210
|
+
"refund_id"=>"503014086722221012110826014924",
|
211
|
+
"refund_recv_accout"=>"招商银行信用卡4012",
|
212
|
+
"refund_request_source"=>"API",
|
213
|
+
"refund_status"=>"SUCCESS",
|
214
|
+
"settlement_refund_fee"=>"1",
|
215
|
+
"settlement_total_fee"=>"1",
|
216
|
+
"success_time"=>"2021-07-20 15:11:52",
|
217
|
+
"total_fee"=>"1",
|
218
|
+
"transaction_id"=>"42000011872021002028121998431"
|
219
|
+
}
|
220
|
+
```
|
221
|
+
|
222
|
+
### refund_exec_failure:
|
223
|
+
TODO 待补充
|
224
|
+
|
225
|
+
|
24
226
|
## Contributing
|
25
227
|
Contribution directions go here.
|
26
228
|
|
27
229
|
## License
|
28
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
230
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/wechat_payment .css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
module WechatPayment
|
3
|
+
class CallbackController < WechatPayment::ApplicationController
|
4
|
+
|
5
|
+
# 微信支付回调
|
6
|
+
def payment
|
7
|
+
result = Hash.from_xml(request.body.read)["xml"]
|
8
|
+
|
9
|
+
process_result = WechatPayment::Service.handle_payment_notify(result)
|
10
|
+
if process_result.success?
|
11
|
+
render xml: { return_code: "SUCCESS" }.to_xml(root: 'xml', dasherize: false)
|
12
|
+
else
|
13
|
+
render xml: { return_code: "FAIL", return_msg: process_result.errors.first }.to_xml(root: 'xml', dasherize: false)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def refund
|
18
|
+
callback_info = Hash.from_xml(request.body.read)["xml"]["req_info"]
|
19
|
+
refund_result = WechatPayment::Service.handle_refund_notify(callback_info)
|
20
|
+
|
21
|
+
if refund_result.success?
|
22
|
+
render xml: {return_code: "SUCCESS"}.to_xml(root: 'xml', dasherize: false)
|
23
|
+
else
|
24
|
+
render xml: {return_code: "FAIL", return_msg: refund_result.errors.first}.to_xml(root: 'xml', dasherize: false)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
module WechatPayment
|
2
|
+
class PaymentOrder < ApplicationRecord
|
3
|
+
|
4
|
+
has_many :refund_orders
|
5
|
+
belongs_to :customer, polymorphic: true
|
6
|
+
|
7
|
+
before_save :set_customer_info
|
8
|
+
before_create :gen_out_trade_no
|
9
|
+
belongs_to :goods, polymorphic: true
|
10
|
+
|
11
|
+
enum state: {
|
12
|
+
paid: "paid",
|
13
|
+
pending: "pending",
|
14
|
+
refunded: "refunded",
|
15
|
+
failed: "failed"
|
16
|
+
}, _default: "pending"
|
17
|
+
|
18
|
+
# 将部分用户信息保存至订单
|
19
|
+
def set_customer_info
|
20
|
+
self.open_id = customer.open_id if open_id.blank?
|
21
|
+
self.spbill_create_ip = customer.spbill_create_ip
|
22
|
+
end
|
23
|
+
|
24
|
+
# 生成交易编号
|
25
|
+
def gen_out_trade_no
|
26
|
+
loop do
|
27
|
+
out_trade_no = "#{Time.current.to_i}#{SecureRandom.random_number(999_999_999)}"
|
28
|
+
records_count = WechatPayment::PaymentOrder.where(out_trade_no: out_trade_no).count
|
29
|
+
if records_count == 0
|
30
|
+
self.out_trade_no = out_trade_no
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# 创建退款订单
|
37
|
+
def create_refund_order(refund_fee)
|
38
|
+
refund_orders.create(
|
39
|
+
out_trade_no: out_trade_no,
|
40
|
+
refund_fee: refund_fee,
|
41
|
+
total_fee: total_fee,
|
42
|
+
goods: goods,
|
43
|
+
customer: customer
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def as_order_params
|
48
|
+
{
|
49
|
+
out_trade_no: out_trade_no,
|
50
|
+
spbill_create_ip: spbill_create_ip,
|
51
|
+
total_fee: total_fee,
|
52
|
+
body: body,
|
53
|
+
openid: open_id
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
# 发起支付
|
58
|
+
#
|
59
|
+
# @return [Hash]
|
60
|
+
#
|
61
|
+
# return example
|
62
|
+
# {
|
63
|
+
# "appId": "wxf89f9547da823dcd",
|
64
|
+
# "package": "prepay_id=wx28180521320799e04f6028c55c31bf0000",
|
65
|
+
# "nonceStr": "62350ff6c414946d0dc4c49b32ad3fd3",
|
66
|
+
# "timeStamp": "1624874721",
|
67
|
+
# "signType": "MD5",
|
68
|
+
# "paySign": "1F5CBC345B86E5DD055F235A22961422",
|
69
|
+
# "orderId": 17
|
70
|
+
# }
|
71
|
+
def pay
|
72
|
+
order_result = WechatPayment::Service.new(self).order
|
73
|
+
if order_result.success?
|
74
|
+
payload = WechatPayment::Client.gen_js_pay_payload(order_result.data).merge(orderId: id).with_indifferent_access
|
75
|
+
WechatPayment::ServiceResult.new(success: true, data: payload)
|
76
|
+
else
|
77
|
+
order_result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# 重新支付订单
|
82
|
+
def repay
|
83
|
+
gen_out_trade_no
|
84
|
+
save
|
85
|
+
pay
|
86
|
+
end
|
87
|
+
|
88
|
+
# 发起退款
|
89
|
+
# @param [Integer] refund_fee 需要退款的金额,单位:分
|
90
|
+
def refund(refund_fee = total_fee)
|
91
|
+
WechatPayment::Service.new(self).refund(refund_fee)
|
92
|
+
end
|
93
|
+
|
94
|
+
# 判断余额是否足够退款
|
95
|
+
def balance_enough_to_refund?(refund_fee)
|
96
|
+
total_fee - refunded_fee >= refund_fee
|
97
|
+
end
|
98
|
+
|
99
|
+
# 已退款的金额(包括正在退款的金额)
|
100
|
+
def refunded_fee
|
101
|
+
refund_orders.where(state: [:pending, :refunded]).sum(:refund_fee)
|
102
|
+
end
|
103
|
+
|
104
|
+
# 实际已退的金额
|
105
|
+
def actual_refunded_fee
|
106
|
+
refund_orders.where(state: :refunded).sum(:refund_fee)
|
107
|
+
end
|
108
|
+
|
109
|
+
# 订单是否可以退款
|
110
|
+
def refundable?
|
111
|
+
min_refund_fee = 1
|
112
|
+
paid? && balance_enough_to_refund?(min_refund_fee)
|
113
|
+
end
|
114
|
+
|
115
|
+
# 支付下单成功
|
116
|
+
# @param [Hash] result
|
117
|
+
#
|
118
|
+
# result example:
|
119
|
+
#
|
120
|
+
# {
|
121
|
+
# "return_code"=>"SUCCESS",
|
122
|
+
# "return_msg"=>"OK",
|
123
|
+
# "result_code"=>"SUCCESS",
|
124
|
+
# "mch_id"=>"12312412312",
|
125
|
+
# "appid"=>"wxc5f26065c6471234",
|
126
|
+
# "sub_mch_id"=>"1525911234",
|
127
|
+
# "sub_appid"=>"wxf89f912345823dcd",
|
128
|
+
# "nonce_str"=>"ZUN2rEf6ATgYU8Lr",
|
129
|
+
# "sign"=>"3A216DB61196CEC63CE282D53FD1833F",
|
130
|
+
# "prepay_id"=>"wx281553565159884f81c452eb3f26b90000",
|
131
|
+
# "trade_type"=>"JSAPI"
|
132
|
+
# }
|
133
|
+
def payment_apply_success(result)
|
134
|
+
update(prepay_id: result["prepay_id"])
|
135
|
+
|
136
|
+
if goods.respond_to? :payment_apply_success
|
137
|
+
goods.payment_apply_success(result)
|
138
|
+
end
|
139
|
+
|
140
|
+
result
|
141
|
+
end
|
142
|
+
|
143
|
+
# 支付下单失败
|
144
|
+
# @param [Hash] result
|
145
|
+
#
|
146
|
+
# result example:
|
147
|
+
#
|
148
|
+
# {
|
149
|
+
# "return_code"=>"SUCCESS",
|
150
|
+
# "return_msg"=>"OK",
|
151
|
+
# "result_code"=>"FAIL",
|
152
|
+
# "err_code_des"=>"该订单已支付",
|
153
|
+
# "err_code"=>"ORDERPAID",
|
154
|
+
# "mch_id"=>"1363241802",
|
155
|
+
# "appid"=>"wxc5f26065c6471bcf",
|
156
|
+
# "sub_mch_id"=>"1525918291",
|
157
|
+
# "sub_appid"=>"wxf89f9547da823dcd",
|
158
|
+
# "nonce_str"=>"1jWLkg2YZjwnOozl",
|
159
|
+
# "sign"=>"3C80A1C9BD6CFDB7C37CCFCEAAF9E274"
|
160
|
+
# }
|
161
|
+
def payment_apply_failure(result)
|
162
|
+
update(state: :failed)
|
163
|
+
|
164
|
+
if goods.respond_to? :payment_apply_failure
|
165
|
+
goods.payment_apply_failure(result)
|
166
|
+
end
|
167
|
+
|
168
|
+
result
|
169
|
+
end
|
170
|
+
|
171
|
+
# 支付成功(回调结果)
|
172
|
+
# @param [Hash] result
|
173
|
+
#
|
174
|
+
# result example:
|
175
|
+
#
|
176
|
+
# {
|
177
|
+
# "appid"=>"wxc5e21215c6471bcf",
|
178
|
+
# "bank_type"=>"CMB_CREDIT",
|
179
|
+
# "cash_fee"=>"1",
|
180
|
+
# "fee_type"=>"CNY",
|
181
|
+
# "is_subscribe"=>"N",
|
182
|
+
# "mch_id"=>"144223114",
|
183
|
+
# "nonce_str"=>"026b7ff3433f482f98610a67bbd8e159",
|
184
|
+
# "openid"=>"omf2nv3OgYXBYrNqdx9eUucKy7NQ",
|
185
|
+
# "out_trade_no"=>"1624866836218932068",
|
186
|
+
# "result_code"=>"SUCCESS",
|
187
|
+
# "return_code"=>"SUCCESS",
|
188
|
+
# "sign"=>"442098E6B670B82B88A843CC2A2AB54D",
|
189
|
+
# "sub_appid"=>"wxf89f95121da823dcd",
|
190
|
+
# "sub_is_subscribe"=>"N",
|
191
|
+
# "sub_mch_id"=>"1525911211",
|
192
|
+
# "sub_openid"=>"ogT7J5YddGnll-ippRvJq62Nv8W0",
|
193
|
+
# "time_end"=>"20210628155426",
|
194
|
+
# "total_fee"=>"1",
|
195
|
+
# "trade_type"=>"JSAPI",
|
196
|
+
# "transaction_id"=>"4200001174202106282207291730"
|
197
|
+
# }
|
198
|
+
def payment_exec_success(result)
|
199
|
+
update(
|
200
|
+
state: :paid,
|
201
|
+
transaction_id: result["transaction_id"],
|
202
|
+
paid_at: Time.current
|
203
|
+
)
|
204
|
+
|
205
|
+
if goods.respond_to? :payment_exec_success
|
206
|
+
goods.payment_exec_success(result)
|
207
|
+
end
|
208
|
+
|
209
|
+
result
|
210
|
+
end
|
211
|
+
|
212
|
+
# 支付失败(回调结果)
|
213
|
+
# @param [Hash] result
|
214
|
+
#
|
215
|
+
# result example:
|
216
|
+
#
|
217
|
+
def payment_exec_failure(result)
|
218
|
+
if goods.respond_to? :payment_exec_failure
|
219
|
+
goods.payment_exec_failure(result)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# 判断是否已经全额退款
|
224
|
+
def total_fee_refunded?
|
225
|
+
refunded_fee >= total_fee
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|