wechat-pay 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'wechat-pay/helper'
5
+ require 'wechat-pay/ecommerce/withdraw'
6
+ require 'wechat-pay/ecommerce/balance'
7
+ require 'wechat-pay/ecommerce/applyment'
8
+ require 'wechat-pay/ecommerce/order'
9
+ require 'wechat-pay/ecommerce/combine_order'
10
+ require 'wechat-pay/ecommerce/profitsharing'
11
+ require 'wechat-pay/ecommerce/subsidies'
12
+ require 'wechat-pay/ecommerce/refund'
13
+ require 'wechat-pay/ecommerce/bill'
14
+
15
+ module WechatPay
16
+ # # 服务商相关接口封装(电商平台,服务商有许多接口共用)
17
+ # 文档: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter3_3_3.shtml
18
+ #
19
+ # PS: 电商收付通的所有接口已经封装完毕,有需要再补充。
20
+ #
21
+ module Ecommerce
22
+ include WechatPayHelper
23
+
24
+ class<<self
25
+ # 视频上传
26
+ #
27
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_2.shtml
28
+ #
29
+ # Example:
30
+ #
31
+ # ``` ruby
32
+ # WechatPay::Ecommerce.media_video_upload(File.open('Your Video'))
33
+ # ```
34
+ #
35
+ def media_video_upload(video)
36
+ url = '/v3/merchant/media/video_upload'
37
+ method = 'POST'
38
+ meta = {
39
+ filename: video.to_path,
40
+ sha256: Digest::SHA256.hexdigest(video.read)
41
+ }
42
+
43
+ video.rewind
44
+ payload = {
45
+ meta: meta.to_json,
46
+ file: video
47
+ }
48
+
49
+ make_request(
50
+ method: method,
51
+ path: url,
52
+ for_sign: meta.to_json,
53
+ payload: payload,
54
+ extra_headers: {
55
+ 'Content-Type' => nil
56
+ }
57
+ )
58
+ end
59
+
60
+ # 图片上传
61
+ #
62
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_1.shtml
63
+ #
64
+ # Example:
65
+ #
66
+ # ``` ruby
67
+ # WechatPay::Ecommerce.media_upload(File.open('Your Image'))
68
+ # ```
69
+ def media_upload(image)
70
+ url = '/v3/merchant/media/upload'
71
+ method = 'POST'
72
+ meta = {
73
+ filename: image.to_path,
74
+ sha256: Digest::SHA256.hexdigest(image.read)
75
+ }
76
+
77
+ image.rewind
78
+ payload = {
79
+ meta: meta.to_json,
80
+ file: image
81
+ }
82
+
83
+ make_request(
84
+ method: method,
85
+ path: url,
86
+ for_sign: meta.to_json,
87
+ payload: payload,
88
+ extra_headers: {
89
+ 'Content-Type' => nil # Pass nil to remove the Content-Type
90
+ }
91
+ )
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WechatPay
4
+ module Ecommerce
5
+ class << self
6
+ # 二级商户进件
7
+ #
8
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_1.shtml
9
+ #
10
+ # Example:
11
+ #
12
+ # ``` ruby
13
+ # params = {
14
+ # "organization_type": "2",
15
+ # "business_license_info": {
16
+ # "business_license_copy": "47ZC6GC-vnrbEg05InE4d2I6_H7I4",
17
+ # "business_license_number": "123456789012345678",
18
+ # "merchant_name": "腾讯科技有限公司",
19
+ # "legal_person": "张三"
20
+ # },
21
+ # "organization_cert_info": {
22
+ # "organization_copy": "47ZC6GC-vnrbEny__Ie_An5-tCpqxuGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4 ",
23
+ # "organization_time": "[\"2014-01-01\",\"长期\"]",
24
+ # "organization_number": "12345679-A"
25
+ # },
26
+ # "id_card_info": {
27
+ # "id_card_copy": "jTpGmxUX3FBWVQ5NJTZvlKC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ",
28
+ # "id_card_national": "47ZC6GC-vnrbEny__Ie_AnGprrKhpVBDIUv0OF4wFNIO4kqg05InE4d2I6_H7I4",
29
+ # "id_card_name": "pVd1HJ6z7UtC + xriudjD5AqhZ9evAM + Jv1z0NVa8MRtelw / wDa4SzfeespQO / 0 kjiwfqdfg =",
30
+ # "id_card_number": "UZFETyabYFFlgvGh6R4vTzDRgzvA2HtP5VHahNhSUqhR9iuGTunRPRVFg ==",
31
+ # "id_card_valid_time": "2026-06-06"
32
+ # },
33
+ # "need_account_info": true,
34
+ # "account_info": {
35
+ # "bank_account_type": "74",
36
+ # "account_name": "fTA4TXc8yMOwFCYeGPktOOSbOBei3KAmUWHGxCQo2hfaC7xumTqXR7 / NyRHpFKXURQFcmmw ==",
37
+ # "account_bank": "工商银行",
38
+ # "bank_address_code": "110000",
39
+ # "bank_branch_id": "402713354941",
40
+ # "bank_name": "施秉县农村信用合作联社城关信用社",
41
+ # "account_number": "d+xT+MQCvrLHUVD5Fnx30mr4L8sPndjXTd75kPkyjqnoMRrEEaYQE8ZRGYoeorwC"
42
+ # },
43
+ # "contact_info": {
44
+ # "contact_type": "65",
45
+ # "contact_name": "pVd1HJ6zyvPedzGaV+Xy7UDa4SzfeespQO / 0 kjiwfqdfg ==",
46
+ # "contact_id_card_number": "UZFETyabYFFlgvGh6R4vTzDEOiZZ4ka9+5RgzvA2rJx+NztYUbN209rqR9iuGTunRPRVFg ==",
47
+ # "mobile_phone": "Uy5Hb0c5Se/orEbrWze/ROHu9EPAs/CigDlJ2fnyzC1ppJNBrqcBszhYQUlu5zn6o2uZpBhAsQwd3QAjw==",
48
+ # "contact_email": "Uy5Hb0c5Se/orEbrWze/ROHu9EPAs/CigDlJ2fnyzC1ppJNaLZExOEzmUn6o2uZpBhAsQwd3QAjw=="
49
+ # },
50
+ # "sales_scene_info": {
51
+ # "store_name": "爱烧烤",
52
+ # "store_url": "http://www.qq.com",
53
+ # "store_qr_code": "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAujqhThn4ReFxikqJ5YW6zFQ"
54
+ # },
55
+ # "merchant_shortname": "爱烧烤",
56
+ # "out_request_no": "APPLYMENT_00000000001",
57
+ # "qualifications": "[\"jTpGmxUX3FBWVQ5NJInE4d2I6_H7I4\"]",
58
+ # "business_addition_pics": "[\"jTpGmg05InE4d2I6_H7I4\"]",
59
+ # "business_addition_desc": "特殊情况,说明原因"
60
+ # }
61
+ # ```
62
+ #
63
+ # ``` ruby
64
+ # WechatPay::Ecommerce.applyment(params)
65
+ # ```
66
+ #
67
+ def applyment(payload)
68
+ url = '/v3/ecommerce/applyments/'
69
+ method = 'POST'
70
+
71
+ payload_json = payload.to_json
72
+
73
+ make_request(
74
+ method: method,
75
+ path: url,
76
+ for_sign: payload_json,
77
+ payload: payload_json,
78
+ extra_headers: {
79
+ 'Wechatpay-Serial' => WechatPay.platform_serial_no
80
+ }
81
+ )
82
+ end
83
+
84
+ QUERY_APPLYMENT_FIELDS = %i[applyment_id out_request_no].freeze # :nodoc:
85
+ #
86
+ # 通过商户的申请单或微信的申请单号查询
87
+ #
88
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_2.shtml
89
+ #
90
+ # Example:
91
+ #
92
+ # ``` ruby
93
+ # WechatPay::Ecommerce.query_applyment(out_request_no: 'APPLYMENT_00000000005') # by out_request_no
94
+ # WechatPay::Ecommerce.query_applyment(applyment_id: '200040444455566667') # by_applyment_id
95
+ # ```
96
+ #
97
+ def query_applyment(params)
98
+ if params[:applyment_id]
99
+ applyment_id = params.delete(:applyment_id)
100
+ url = "/v3/ecommerce/applyments/#{applyment_id}"
101
+ else
102
+ out_request_no = params.delete(:out_request_no)
103
+ url = "/v3/ecommerce/applyments/out-request-no/#{out_request_no}"
104
+ end
105
+ method = 'GET'
106
+
107
+ make_request(
108
+ method: method,
109
+ path: url,
110
+ extra_headers: {
111
+ 'Content-Type' => 'application/x-www-form-urlencoded'
112
+ }
113
+ )
114
+ end
115
+
116
+ # 证书获取
117
+ #
118
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_3.shtml
119
+ #
120
+ # Example:
121
+ #
122
+ # ``` ruby
123
+ # WechatPay::Ecommerce.get_certificates
124
+ # ```
125
+ #
126
+ def get_certificates
127
+ url = '/v3/certificates'
128
+ method = 'GET'
129
+
130
+ make_request(
131
+ method: method,
132
+ path: url,
133
+ extra_headers: {
134
+ 'Content-Type' => 'application/x-www-form-urlencoded'
135
+ }
136
+ )
137
+ end
138
+
139
+ INVOKE_QUERY_SETTLEMENT_FIELDS = [:sub_mchid].freeze # :nodoc:
140
+ #
141
+ # 查询结算账户
142
+ #
143
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_5.shtml
144
+ #
145
+ # Example:
146
+ #
147
+ # ``` ruby
148
+ # WechatPay::Ecommerce.query_settlement(sub_mchid: '16000000')
149
+ # ```
150
+ #
151
+ def query_settlement(params)
152
+ sub_mchid = params.delete(:sub_mchid)
153
+ url = "/v3/apply4sub/sub_merchants/#{sub_mchid}/settlement"
154
+ method = 'GET'
155
+
156
+ make_request(
157
+ method: method,
158
+ path: url,
159
+ extra_headers: {
160
+ 'Content-Type' => 'application/x-www-form-urlencoded'
161
+ }
162
+ )
163
+ end
164
+
165
+ INVOKE_MODIFY_SETTLEMENT_FIELDS = %i[sub_mchid account_type account_bank bank_address_code account_number].freeze # :nodoc:
166
+ #
167
+ # 修改结算账号
168
+ #
169
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_4.shtml
170
+ #
171
+ # Example:
172
+ #
173
+ # ``` ruby
174
+ # WechatPay::Ecommerce.modify_settlement(sub_mchid: '15000000', account_type: 'ACCOUNT_TYPE_PRIVATE', account_bank: '工商银行', bank_address_code: '110000', account_number: WechatPay::Sign.sign_important_info('755555555'))
175
+ # ```
176
+ #
177
+ def modify_settlement(params)
178
+ sub_mchid = params.delete(:sub_mchid)
179
+ url = "/v3/apply4sub/sub_merchants/#{sub_mchid}/modify-settlement"
180
+ method = 'POST'
181
+
182
+ payload_json = params.to_json
183
+
184
+ make_request(
185
+ method: method,
186
+ path: url,
187
+ for_sign: payload_json,
188
+ payload: payload_json,
189
+ extra_headers: {
190
+ 'Wechatpay-Serial' => WechatPay.platform_serial_no
191
+ }
192
+ )
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WechatPay
4
+ module Ecommerce
5
+ class<<self
6
+ QUERY_REALTIME_BALANCE_FIELDS = [:sub_mchid].freeze # :nodoc:
7
+ #
8
+ # 余额实时查询
9
+ #
10
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_1.shtml
11
+ #
12
+ # Example:
13
+ #
14
+ # ``` ruby
15
+ # WechatPay::Ecommerce.query_realtime_balance(sub_mchid: '1600000')
16
+ # ```
17
+ def query_realtime_balance(params)
18
+ sub_mchid = params.delete(:sub_mchid)
19
+ url = "/v3/ecommerce/fund/balance/#{sub_mchid}"
20
+ method = 'GET'
21
+
22
+ make_request(
23
+ path: url,
24
+ method: method,
25
+ extra_headers: {
26
+ 'Content-Type' => 'application/x-www-form-urlencoded'
27
+ }
28
+ )
29
+ end
30
+
31
+ QUERY_ENDDAY_BALANCE_FIELDS = %i[sub_mchid date].freeze # :nodoc:
32
+ #
33
+ # 日终余额查询
34
+ #
35
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_2.shtml
36
+ #
37
+ # Example:
38
+ #
39
+ # ``` ruby
40
+ # WechatPay::Ecommerce.query_endday_balance(sub_mchid: '1600000', date: '2019-08-17')
41
+ # ```
42
+ def query_endday_balance(params)
43
+ sub_mchid = params.delete(:sub_mchid)
44
+ path = "/v3/ecommerce/fund/balance/#{sub_mchid}"
45
+ method = 'GET'
46
+ query = build_query(params)
47
+ url = "#{path}?#{query}"
48
+
49
+ make_request(
50
+ path: url,
51
+ method: method,
52
+ extra_headers: {
53
+ 'Content-Type' => 'application/x-www-form-urlencoded'
54
+ }
55
+ )
56
+ end
57
+
58
+ QUERY_PLATFORM_REALTIME_BALANCE_FIELDS = %i[account_type].freeze # :nodoc:
59
+ #
60
+ # 平台商户实时余额
61
+ #
62
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_3.shtml
63
+ #
64
+ # Example:
65
+ #
66
+ # ``` ruby
67
+ # WechatPay::Ecommerce.query_platform_realtime_balance(account_type: 'BASIC') # basic account
68
+ # WechatPay::Ecommerce.query_platform_realtime_balance(account_type: 'FEES') # fees account
69
+ # ```
70
+ #
71
+ def query_platform_realtime_balance(params)
72
+ account_type = params.delete(:account_type)
73
+ url = "/v3/merchant/fund/balance/#{account_type}"
74
+ method = 'GET'
75
+
76
+ make_request(
77
+ path: url,
78
+ method: method,
79
+ extra_headers: {
80
+ 'Content-Type' => 'application/x-www-form-urlencoded'
81
+ }
82
+ )
83
+ end
84
+
85
+ QUERY_PLATFORM_ENDDAY_BALANCE_FIELDS = %i[account_type date].freeze #:nodoc:
86
+ #
87
+ # 平台商户日终余额
88
+ #
89
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_4.shtml
90
+ #
91
+ # Example:
92
+ #
93
+ # ``` ruby
94
+ # WechatPay::Ecommerce.query_platform_endday_balance(account_type: 'BASIC')
95
+ # WechatPay::Ecommerce.query_platform_endday_balance(account_type: 'FEES')
96
+ # ```
97
+ #
98
+ def query_platform_endday_balance(params)
99
+ account_type = params.delete(:account_type)
100
+ path = "/v3/merchant/fund/dayendbalance/#{account_type}"
101
+ method = 'GET'
102
+ query = build_query(params)
103
+ url = "#{path}?#{query}"
104
+
105
+ make_request(
106
+ path: url,
107
+ method: method,
108
+ extra_headers: {
109
+ 'Content-Type' => 'application/x-www-form-urlencoded'
110
+ }
111
+ )
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WechatPay
4
+ module Ecommerce
5
+ class<<self
6
+ TRADEBILL_FIELDS = [:bill_date].freeze # :nodoc:
7
+ #
8
+ # 申请交易账单
9
+ #
10
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_9_1.shtml
11
+ #
12
+ # Example:
13
+ #
14
+ # ``` ruby
15
+ # WechatPay::Ecommerce.tradebill(bill_date: '2021-04-30')
16
+ # ```
17
+ def tradebill(params)
18
+ path = '/v3/bill/tradebill'
19
+ method = 'GET'
20
+
21
+ query = build_query(params)
22
+ url = "#{path}?#{query}"
23
+
24
+ make_request(
25
+ path: url,
26
+ method: method,
27
+ extra_headers: {
28
+ 'Content-Type' => 'application/x-www-form-urlencoded'
29
+ }
30
+ )
31
+ end
32
+
33
+ FUNDFLOWBILL_FIELDS = [:bill_date].freeze # :nodoc:
34
+ #
35
+ # 申请资金账单
36
+ #
37
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_9_2.shtml
38
+ #
39
+ # Example:
40
+ #
41
+ # ``` ruby
42
+ # WechatPay::Ecommerce.fundflowbill(bill_date: '2021-04-30')
43
+ # ```
44
+ #
45
+ def fundflowbill(params)
46
+ path = '/v3/bill/fundflowbill'
47
+ method = 'GET'
48
+
49
+ query = build_query(params)
50
+ url = "#{path}?#{query}"
51
+
52
+ make_request(
53
+ path: url,
54
+ method: method,
55
+ extra_headers: {
56
+ 'Content-Type' => 'application/x-www-form-urlencoded'
57
+ }
58
+ )
59
+ end
60
+
61
+ ECOMMERCE_FUNDFLOWBILL_FIELDS = %i[bill_date account_type algorithm].freeze # :nodoc:
62
+ #
63
+ # 二级商户资金账单
64
+ #
65
+ # Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_9_5.shtml
66
+ #
67
+ # Example:
68
+ #
69
+ # ``` ruby
70
+ # WechatPay::Ecommerce.ecommerce_fundflowbill(bill_date: '2021-04-30', account_type: 'ALL', algorithm: 'AEAD_AES_256_GCM')
71
+ # ```
72
+ #
73
+ def ecommerce_fundflowbill(params)
74
+ path = '/v3/ecommerce/bill/fundflowbill'
75
+ method = 'GET'
76
+
77
+ query = build_query(params)
78
+ url = "#{path}?#{query}"
79
+
80
+ make_request(
81
+ path: url,
82
+ method: method,
83
+ extra_headers: {
84
+ 'Content-Type' => 'application/x-www-form-urlencoded'
85
+ }
86
+ )
87
+ end
88
+ end
89
+ end
90
+ end