wechat_payment 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|