wx_pay 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 811646dddfb4af0870059948ab4d3e94f6107a23
4
- data.tar.gz: be26df10ae106084dac31c92f76e93e70d265578
3
+ metadata.gz: 6df0e8b3d430425942000bc1fc37e25938da78ef
4
+ data.tar.gz: 867fd2ea5babed3e08b9834f0df7d49879d2a986
5
5
  SHA512:
6
- metadata.gz: caeee55cd0c865032892ebafa34d9b44c7dab88c3652b496169303771954f8d147d51defb5821e8367b01c697e6b1758774b60095b2080808674bb27747c1062
7
- data.tar.gz: 4a3a785ec580149c98f688606b9f83f662bd24bd1728665d21126049ba2ad7b801027bc31006e1cb8668d824b68ea2cfe6da85c5e9f4d95507aad17cb46fe945
6
+ metadata.gz: 992d410cae14544df5f6d22bbffa25cd2869377c1cf8447e22bb34063d1e90ac15c35a4379e0fba35acc1264b2255a4a62ed8227833198890967870dd9f99248
7
+ data.tar.gz: 16122e459b3f67f910cbeea658e3bef39f90ddcac8ce95ec36cb50cbf0241535cdba5959c3c5897e77457e935f54b5839928aaba17eba88c759ad4f8ab3dd57b
data/lib/wx_pay/result.rb CHANGED
@@ -2,14 +2,16 @@ module WxPay
2
2
  class Result < ::Hash
3
3
  SUCCESS_FLAG = 'SUCCESS'.freeze
4
4
 
5
- def initialize(result)
6
- super
5
+ def self.[] result
6
+ hash = self.new
7
7
 
8
8
  if result['xml'].class == Hash
9
9
  result['xml'].each_pair do |k, v|
10
- self[k] = v
10
+ hash[k] = v
11
11
  end
12
12
  end
13
+
14
+ hash
13
15
  end
14
16
 
15
17
  def success?
@@ -6,16 +6,16 @@ module WxPay
6
6
  GATEWAY_URL = 'https://api.mch.weixin.qq.com'
7
7
 
8
8
  INVOKE_UNIFIEDORDER_REQUIRED_FIELDS = %i(body out_trade_no total_fee spbill_create_ip notify_url trade_type)
9
- def self.invoke_unifiedorder(params)
9
+ def self.invoke_unifiedorder(params, options = {})
10
10
  params = {
11
- appid: WxPay.appid,
12
- mch_id: WxPay.mch_id,
11
+ appid: options.delete(:appid) || WxPay.appid,
12
+ mch_id: options.delete(:mch_id) || WxPay.mch_id,
13
13
  nonce_str: SecureRandom.uuid.tr('-', '')
14
14
  }.merge(params)
15
15
 
16
16
  check_required_options(params, INVOKE_UNIFIEDORDER_REQUIRED_FIELDS)
17
17
 
18
- r = invoke_remote("#{GATEWAY_URL}/pay/unifiedorder", make_payload(params))
18
+ r = invoke_remote("#{GATEWAY_URL}/pay/unifiedorder", make_payload(params), options)
19
19
 
20
20
  yield r if block_given?
21
21
 
@@ -23,10 +23,10 @@ module WxPay
23
23
  end
24
24
 
25
25
  GENERATE_APP_PAY_REQ_REQUIRED_FIELDS = %i(prepayid noncestr)
26
- def self.generate_app_pay_req(params)
26
+ def self.generate_app_pay_req(params, options = {})
27
27
  params = {
28
- appid: WxPay.appid,
29
- partnerid: WxPay.mch_id,
28
+ appid: options.delete(:appid) || WxPay.appid,
29
+ partnerid: options.delete(:mch_id) || WxPay.mch_id,
30
30
  package: 'Sign=WXPay',
31
31
  timestamp: Time.now.to_i.to_s
32
32
  }.merge(params)
@@ -38,63 +38,149 @@ module WxPay
38
38
  params
39
39
  end
40
40
 
41
- INVOKE_REFUND_REQUIRED_FIELDS = %i(transaction_id out_trade_no out_refund_no total_fee refund_fee)
42
- def self.invoke_refund(params)
41
+ INVOKE_REFUND_REQUIRED_FIELDS = %i(out_refund_no total_fee refund_fee op_user_id)
42
+ def self.invoke_refund(params, options = {})
43
43
  params = {
44
- appid: WxPay.appid,
45
- mch_id: WxPay.mch_id,
44
+ appid: options.delete(:appid) || WxPay.appid,
45
+ mch_id: options.delete(:mch_id) || WxPay.mch_id,
46
46
  nonce_str: SecureRandom.uuid.tr('-', ''),
47
- op_user_id: WxPay.mch_id
48
47
  }.merge(params)
49
48
 
49
+ params[:op_user_id] ||= params[:mch_id]
50
+
50
51
  check_required_options(params, INVOKE_REFUND_REQUIRED_FIELDS)
51
52
 
52
- # 微信退款需要双向证书
53
- # https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
54
- # https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
53
+ options = {
54
+ ssl_client_cert: options.delete(:apiclient_cert) || WxPay.apiclient_cert,
55
+ ssl_client_key: options.delete(:apiclient_key) || WxPay.apiclient_key,
56
+ verify_ssl: OpenSSL::SSL::VERIFY_NONE
57
+ }.merge(options)
58
+
59
+ r = invoke_remote("#{GATEWAY_URL}/secapi/pay/refund", make_payload(params), options)
60
+
61
+ yield r if block_given?
62
+
63
+ r
64
+ end
65
+
66
+ INVOKE_TRANSFER_REQUIRED_FIELDS = %i(partner_trade_no openid check_name amount desc spbill_create_ip)
67
+ def self.invoke_transfer(params, options = {})
68
+ params = {
69
+ mch_appid: options.delete(:appid) || WxPay.appid,
70
+ mchid: options.delete(:mch_id) || WxPay.mch_id,
71
+ nonce_str: SecureRandom.uuid.tr('-', '')
72
+ }.merge(params)
73
+
74
+ check_required_options(params, INVOKE_TRANSFER_REQUIRED_FIELDS)
55
75
 
56
- WxPay.extra_rest_client_options = {
57
- ssl_client_cert: WxPay.apiclient_cert.certificate,
58
- ssl_client_key: WxPay.apiclient_cert.key,
76
+ options = {
77
+ ssl_client_cert: options.delete(:apiclient_cert) || WxPay.apiclient_cert,
78
+ ssl_client_key: options.delete(:apiclient_key) || WxPay.apiclient_key,
59
79
  verify_ssl: OpenSSL::SSL::VERIFY_NONE
60
- }
80
+ }.merge(options)
61
81
 
62
- r = invoke_remote "#{GATEWAY_URL}/secapi/pay/refund", make_payload(params)
82
+ r = invoke_remote("#{GATEWAY_URL}/mmpaymkttransfers/promotion/transfers", make_payload(params), options)
63
83
 
64
- yield(r) if block_given?
84
+ yield r if block_given?
65
85
 
66
86
  r
67
87
  end
68
88
 
89
+ INVOKE_REVERSE_REQUIRED_FIELDS = %i(out_trade_no)
90
+ def self.invoke_reverse(params, options = {})
91
+ params = {
92
+ appid: options.delete(:appid) || WxPay.appid,
93
+ mch_id: options.delete(:mch_id) || WxPay.mch_id,
94
+ nonce_str: SecureRandom.uuid.tr('-', '')
95
+ }.merge(params)
69
96
 
70
- private
97
+ check_required_options(params, INVOKE_REVERSE_REQUIRED_FIELDS)
71
98
 
72
- def self.check_required_options(options, names)
73
- names.each do |name|
74
- warn("WxPay Warn: missing required option: #{name}") unless options.has_key?(name)
75
- end
99
+ options = {
100
+ ssl_client_cert: options.delete(:apiclient_cert) || WxPay.apiclient_cert,
101
+ ssl_client_key: options.delete(:apiclient_key) || WxPay.apiclient_key,
102
+ verify_ssl: OpenSSL::SSL::VERIFY_NONE
103
+ }.merge(options)
104
+
105
+ r = invoke_remote("#{GATEWAY_URL}/secapi/pay/reverse", make_payload(params), options)
106
+
107
+ yield r if block_given?
108
+
109
+ r
76
110
  end
77
111
 
78
- def self.make_payload(params)
79
- sign = WxPay::Sign.generate(params)
80
- params.delete(:key) if params[:key]
81
- "<xml>#{params.map { |k, v| "<#{k}>#{v}</#{k}>" }.join}<sign>#{sign}</sign></xml>"
112
+ INVOKE_MICROPAY_REQUIRED_FIELDS = %i(body out_trade_no total_fee spbill_create_ip auth_code)
113
+ def self.invoke_micropay(params, options = {})
114
+ params = {
115
+ appid: options.delete(:appid) || WxPay.appid,
116
+ mch_id: options.delete(:mch_id) || WxPay.mch_id,
117
+ nonce_str: SecureRandom.uuid.tr('-', '')
118
+ }.merge(params)
119
+
120
+ check_required_options(params, INVOKE_MICROPAY_REQUIRED_FIELDS)
121
+
122
+ options = {
123
+ ssl_client_cert: options.delete(:apiclient_cert) || WxPay.apiclient_cert,
124
+ ssl_client_key: options.delete(:apiclient_key) || WxPay.apiclient_key,
125
+ verify_ssl: OpenSSL::SSL::VERIFY_NONE
126
+ }.merge(options)
127
+
128
+ r = invoke_remote("#{GATEWAY_URL}/pay/micropay", make_payload(params), options)
129
+
130
+ yield r if block_given?
131
+
132
+ r
82
133
  end
83
134
 
84
- def self.invoke_remote(url, payload)
85
- r = RestClient::Request.execute(
86
- {
87
- method: :post,
88
- url: url,
89
- payload: payload,
90
- headers: { content_type: 'application/xml' }
91
- }.merge(WxPay.extra_rest_client_options)
92
- )
93
-
94
- if r
95
- WxPay::Result.new Hash.from_xml(r)
96
- else
97
- nil
135
+ ORDER_QUERY_REQUIRED_FIELDS = %i(out_trade_no)
136
+ def self.order_query(params, options = {})
137
+ params = {
138
+ appid: options.delete(:appid) || WxPay.appid,
139
+ mch_id: options.delete(:mch_id) || WxPay.mch_id,
140
+ nonce_str: SecureRandom.uuid.tr('-', '')
141
+ }.merge(params)
142
+
143
+ check_required_options(params, ORDER_QUERY_REQUIRED_FIELDS)
144
+
145
+ r = invoke_remote("#{GATEWAY_URL}/pay/orderquery", make_payload(params), options)
146
+
147
+ yield r if block_given?
148
+
149
+ r
150
+ end
151
+
152
+ class << self
153
+ private
154
+
155
+ def check_required_options(options, names)
156
+ names.each do |name|
157
+ warn("WxPay Warn: missing required option: #{name}") unless options.has_key?(name)
158
+ end
159
+ end
160
+
161
+ def make_payload(params)
162
+ sign = WxPay::Sign.generate(params)
163
+ params.delete(:key) if params[:key]
164
+ "<xml>#{params.map { |k, v| "<#{k}>#{v}</#{k}>" }.join}<sign>#{sign}</sign></xml>"
165
+ end
166
+
167
+ def invoke_remote(url, payload, options = {})
168
+ options = WxPay.extra_rest_client_options.merge(options)
169
+
170
+ r = RestClient::Request.execute(
171
+ {
172
+ method: :post,
173
+ url: url,
174
+ payload: payload,
175
+ headers: { content_type: 'application/xml' }
176
+ }.merge(options)
177
+ )
178
+
179
+ if r
180
+ WxPay::Result[Hash.from_xml(r)]
181
+ else
182
+ nil
183
+ end
98
184
  end
99
185
  end
100
186
  end
data/lib/wx_pay/sign.rb CHANGED
@@ -6,8 +6,8 @@ module WxPay
6
6
  key = params.delete(:key)
7
7
 
8
8
  query = params.sort.map do |key, value|
9
- "#{key}=#{value}"
10
- end.join('&')
9
+ "#{key}=#{value}" if value != "" && !value.nil?
10
+ end.compact.join('&')
11
11
 
12
12
  Digest::MD5.hexdigest("#{query}&key=#{key || WxPay.key}").upcase
13
13
  end
@@ -1,3 +1,3 @@
1
1
  module WxPay
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/wx_pay.rb CHANGED
@@ -1,21 +1,28 @@
1
1
  require 'wx_pay/result'
2
2
  require 'wx_pay/sign'
3
3
  require 'wx_pay/service'
4
+ require 'openssl'
4
5
 
5
6
  module WxPay
7
+ @extra_rest_client_options = {}
8
+
6
9
  class<< self
7
- attr_accessor :appid, :mch_id, :key, :apiclient_cert_path
10
+ attr_accessor :appid, :mch_id, :key, :apiclient_cert, :apiclient_key, :extra_rest_client_options
11
+
12
+ def set_apiclient_by_pkcs12(str, pass)
13
+ pkcs12 = OpenSSL::PKCS12.new(str, pass)
14
+ @apiclient_cert = pkcs12.certificate
15
+ @apiclient_key = pkcs12.key
8
16
 
9
- def extra_rest_client_options=(options)
10
- @rest_client_options = options
17
+ pkcs12
11
18
  end
12
19
 
13
- def extra_rest_client_options
14
- @rest_client_options || {}
20
+ def apiclient_cert=(cert)
21
+ @apiclient_cert = OpenSSL::X509::Certificate.new(cert)
15
22
  end
16
23
 
17
- def apiclient_cert
18
- @apiclient_cert ||= OpenSSL::PKCS12.new(WxPay.apiclient_cert_path, WxPay.mch_id)
24
+ def apiclient_key=(key)
25
+ @apiclient_key = OpenSSL::PKey::RSA.new(key)
19
26
  end
20
27
  end
21
28
  end
data/test/test_helper.rb CHANGED
@@ -6,4 +6,3 @@ require 'fakeweb'
6
6
  WxPay.appid = 'wxd930ea5d5a258f4f'
7
7
  WxPay.key = '8934e7d15453e97507ef794cf7b0519d'
8
8
  WxPay.mch_id = '1900000109'
9
- WxPay.apiclient_cert_path = '/path/to/your/cert/file.p12'
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class WxPay::ResultTest < MiniTest::Test
4
4
  def test_success_method_with_true
5
- r = WxPay::Result.new(
5
+ r = WxPay::Result[
6
6
  Hash.from_xml(
7
7
  <<-XML
8
8
  <xml>
@@ -10,19 +10,39 @@ class WxPay::ResultTest < MiniTest::Test
10
10
  <result_code>SUCCESS</result_code>
11
11
  </xml>
12
12
  XML
13
- ))
13
+ )
14
+ ]
14
15
 
15
16
  assert_equal r.success?, true
16
17
  end
17
18
 
19
+ def test_nonexistent_key
20
+ r = WxPay::Result[
21
+ Hash.from_xml(
22
+ <<-XML
23
+ <xml>
24
+ <return_code>SUCCESS</return_code>
25
+ <code_url>wx_code_url</code_url>
26
+ <result_code>SUCCESS</result_code>
27
+ </xml>
28
+ XML
29
+ )
30
+ ]
31
+
32
+ assert_equal r['return_code'].nil?, false
33
+ assert_equal r['prepay_id'].nil?, true
34
+ assert_equal r.keys, ['return_code', 'code_url', 'result_code']
35
+ end
36
+
18
37
  def test_success_method_with_false
19
- r = WxPay::Result.new(
38
+ r = WxPay::Result[
20
39
  Hash.from_xml(
21
40
  <<-XML
22
41
  <xml>
23
42
  </xml>
24
43
  XML
25
- ))
44
+ )
45
+ ]
26
46
 
27
47
  assert_equal r.success?, false
28
48
  end
@@ -1,7 +1,6 @@
1
1
 
2
2
  class ServiceTest < MiniTest::Test
3
3
 
4
- # TODO why put the params of refun in setup method
5
4
  def setup
6
5
  @params = {
7
6
  transaction_id: '1217752501201407033233368018',
@@ -11,10 +10,6 @@ class ServiceTest < MiniTest::Test
11
10
  refund_fee: 1,
12
11
  total_fee: 1
13
12
  }
14
-
15
- @apiclient_cert = Minitest::Mock.new
16
- @apiclient_cert.expect(:certificate, 'certificate')
17
- @apiclient_cert.expect(:key, 'key')
18
13
  end
19
14
 
20
15
  def test_invoke_refund
@@ -44,11 +39,6 @@ class ServiceTest < MiniTest::Test
44
39
  %r|https://api\.mch\.weixin\.qq\.com*|,
45
40
  body: response_body
46
41
  )
47
-
48
- WxPay.stub :apiclient_cert, @apiclient_cert do
49
- r = WxPay::Service.invoke_refund(@params)
50
- assert_equal r.success?, true
51
- end
52
42
  end
53
43
 
54
44
  def test_accept_multiple_app_id_when_invoke
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wx_pay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jasl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-06 00:00:00.000000000 Z
11
+ date: 2015-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -132,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
132
  version: '0'
133
133
  requirements: []
134
134
  rubyforge_project:
135
- rubygems_version: 2.4.5
135
+ rubygems_version: 2.4.8
136
136
  signing_key:
137
137
  specification_version: 4
138
138
  summary: An unofficial simple wechat pay gem