wxpay 0.1.0.alpha → 0.1.0.beta

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: d08ccd36a9d140b1db257fcae477f104f7e14a45
4
- data.tar.gz: 39d73461f4caf4ea8b912d6dc6f24660cca07351
3
+ metadata.gz: d7d722dfe9cd3843e79b5acdff3a68f092f7be27
4
+ data.tar.gz: 1a4937d2dc7642074bdb638bc9174658d4290618
5
5
  SHA512:
6
- metadata.gz: 75c3d8b58ecf4ec153d1ecc5c8265fe90442ec84314ea1224c608c73962015f540cce7e305c8d2b5a483bbd9c1cdd2829aedd7b9a59a58d9d3277a998286a8ef
7
- data.tar.gz: ac7e5c195ee0a657e88c7fa9b1417e381c6dbb2404da85290cf975f4f6c5644d7780ade9cc1667e99015a06157d12fa0dd4f559f4146fdaf19331dafc4769bed
6
+ metadata.gz: 24049c62991342c475eb2489e0819ec9d7fa74592228adad918ae1fa5f77ed655532e455b28ea04389ca7f70ab7fcfc662d4a1d0cbdae54ec6398eb6f4497905
7
+ data.tar.gz: 59e5f6e8cf1972b04a978d8236e199532e1fdb5c3a5f03c6b6247515447aff02936ce55933ce6a7ebba173439f9ac6663b152b9521fcf1f1e0a3a79ae467cda1
data/README.md CHANGED
@@ -16,10 +16,39 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install wxpay
18
18
 
19
+ ## Configuration
20
+
21
+ These 4 configurations are for NATIVE and JSAPI pay
22
+ ```ruby
23
+ Wxpay.app_id = 'YOUR_APP_ID',
24
+ Wxpay.app_secret = 'YOUR_APP_SECRET'
25
+ Wxpay.merchant_id = 'YOUR_MERCHANT_ID'
26
+ Wxpay.api_key = 'YOUR_API_KEY'
27
+ ```
28
+ These 4 configurations are for APP pay
29
+ ```ruby
30
+ Wxpay.app_app_id = 'YOUR_APP_APP_ID'
31
+ Wxpay.app_app_secret = 'YOUR_APP_APP_SECRET'
32
+ Wxpay.app_merchant_id = 'YOUR_APP_MERCHANT_ID'
33
+ Wxpay.app_api_key = 'YOUR_APP_API_KEY'
34
+ ```
35
+
36
+ If want use debug mode, set this to true
37
+ ```ruby
38
+ Wxpay.debug = true
39
+
40
+ # then you can print debug info to your stderr log
41
+
42
+ Wxpay.debug_info request.body.inspect
43
+ ```
44
+
19
45
  ## Usage
20
46
 
21
- Support there is a action named 'wxpay'
47
+ 1, NATIVE pay
48
+
49
+ Example code:
22
50
 
51
+ In your controller
23
52
  ```ruby
24
53
  def wxpay
25
54
  @order = Order.find params[:id]
@@ -28,19 +57,135 @@ Support there is a action named 'wxpay'
28
57
  spbill_create_ip: request_ip,
29
58
  notify_url: your_notify_url,
30
59
  out_trade_no: @order.wxpay_trade_no,
31
- trade_type: 'NATIVE', # Or 'APP', 'JSAPI'
32
- openid: user_wechat_openid
60
+ trade_type: 'NATIVE',
61
+ product_id: @order.product_id # 'product_id' is need for NATIVE pay
33
62
  resp = @wxorder.pay!
34
63
 
35
64
  if resp[:status] == "success"
36
65
  @code_url = resp[:code_url] # qrcode from wechat, you need to create qrcode image with this value
66
+ render json: {state: 'success', code_url: @code_url}
67
+ else
68
+ @error_message = resp[:err_msg]
69
+ render json: {state: 'failure', message: @error_message}
70
+ end
71
+ end
72
+ ```
73
+
74
+ 2, JSAPI pay
75
+
76
+ **Notice**
77
+
78
+ Compare to NATIVE pay, you need more settings to make jsapi works.
79
+ you need to set a url of the web page which the JSAPI pay launch,
80
+ and you need set permission to get base user info, e.g. **openid**, from wechat server.
81
+
82
+ Example code:
83
+ in your controller:
84
+ ```ruby
85
+ def wxpay_jsapi
86
+ @order = Order.find params[:id]
87
+
88
+ # if you do not get user's openid, JUST COMMENT THIS LINE
89
+ # wxpay_openid
90
+
91
+ @wxorder = Wxpay::Order.new body: @order.subject,
92
+ total_fee: @order.total_fee,
93
+ spbill_create_ip: request_ip,
94
+ notify_url: your_notify_url,
95
+ out_trade_no: @order.wxpay_trade_no,
96
+ trade_type: 'JSAPI',
97
+ openid: session[:wxpay_openid]
98
+
99
+ resp = @wxorder.pay!
100
+
101
+ if resp[:status] == "success"
102
+ @prepay_id = resp[:prepay_id]
103
+ signature_params
37
104
  else
38
105
  @error_message = resp[:err_msg]
39
106
  end
40
107
  end
41
108
  ```
42
- Notice: 'openid' is need for JSAPI pay, 'product_id' is need for NATIVE pay
109
+ **wxpay_openid** is convenient for you to get current_user's openid, you can call method directly within your action, or you can put it into before_action.
110
+ **signature_params** is another method to set params for wechat javascript api for payment
111
+ ```ruby
112
+ protected
113
+
114
+ def signature_params
115
+ @timestamp = Time.current.to_i
116
+ @nonce_str = SecureRandom.hex(16)
117
+ @package = "prepay_id=#{@prepay_id}"
118
+
119
+ param = {
120
+ 'appId' => Wxpay.app_id,
121
+ 'timeStamp' => @timestamp,
122
+ 'nonceStr' => @nonce_str,
123
+ 'package' => @package,
124
+ 'signType' => 'MD5'
125
+ }
126
+
127
+ @pay_sign = Wxpay::Sign.sign_package param
43
128
 
129
+ # success_url is a url the wechat will redirect when the payment succeed
130
+ @success_url = YOUR_SUCCESS_URL
131
+ end
132
+ ```
133
+
134
+
135
+ in your view:
136
+ ```ruby
137
+ = render_jsapi_script(timestamp: @timestamp, nonce_str: @nonce_str, package: @package, pay_sign: @pay_sign, success_url: @success_url)
138
+ ```
139
+ this helper method will generate some javascript into the view, and launch the wechat jsapi payment
140
+
141
+ 3, APP pay
142
+
143
+ Example code:
144
+ ```ruby
145
+ def wxpay_app
146
+ @order = Order.find params[:id]
147
+ Wxpay::Order.new body: @order.subject,
148
+ total_fee: @order.total_fee,
149
+ spbill_create_ip: request_ip,
150
+ notify_url: your_notify_url,
151
+ out_trade_no: @order.wxpay_trade_no,
152
+ trade_type: 'APP',
153
+ openid: session[:wxpay_openid]
154
+
155
+ resp = @wxorder.pay!
156
+
157
+ if resp[:status] == "success"
158
+ @prepay_id = resp[:prepay_id]
159
+ else
160
+ @error_message = resp[:err_msg]
161
+ end
162
+
163
+ @timestamp = Time.current.to_i
164
+ @nonce_str = SecureRandom.hex(16)
165
+ @package = "Sign=WXPay"
166
+
167
+ param = {
168
+ 'appid' => Wxpay.app_app_id,
169
+ 'partnerid' => Wxpay.app_merchant_id,
170
+ 'trade_type' => 'APP',
171
+ 'prepayid' => @prepay_id,
172
+ 'package' => @package,
173
+ 'noncestr' => @nonce_str,
174
+ 'timestamp' => @timestamp
175
+ }
176
+
177
+ @pay_sign = WxSign.sign_package param
178
+ # return the hash to your app
179
+ return json: { appid: APP_APP_ID,
180
+ partner_id: APP_MERCHANT_ID,
181
+ prepay_id: @prepay_id,
182
+ package_value: @package,
183
+ nonce_str: @nonce_str.to_s,
184
+ time_stamp: @timestamp,
185
+ sign: @pay_sign
186
+ }
187
+ end
188
+ ```
44
189
 
45
190
  ## Contributing
46
191
 
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ end
8
+
9
+ task :default => :test
@@ -3,6 +3,8 @@ require "wxpay/version"
3
3
  require "wxpay/sign"
4
4
  require "wxpay/api"
5
5
  require "wxpay/order"
6
+ require "wxpay/helpers"
7
+ require "wxpay/controllers"
6
8
 
7
9
  module Wxpay
8
10
  class << self
@@ -23,3 +25,5 @@ module Wxpay
23
25
  end
24
26
  end
25
27
  end
28
+
29
+ ActionView::Base.send :include, Wxpay::Helpers if defined? ActionView::Base
@@ -1,3 +1,4 @@
1
+ require 'builder'
1
2
  require 'faraday'
2
3
 
3
4
  module Wxpay
@@ -11,8 +12,8 @@ module Wxpay
11
12
  nonce_str: random_str,
12
13
  out_trade_no: order.wxpay_trade_no
13
14
  }
14
- sort_str = Wxpay::Sign.create_sign_str param
15
- sign = Wxpay::Sign.sign_package sort_str
15
+
16
+ sign = Wxpay::Sign.sign_package param
16
17
 
17
18
  _xm = Builder::XmlMarkup.new
18
19
  request_str = _xm.xml {
@@ -1,3 +1,4 @@
1
+ require 'builder'
1
2
  require 'faraday'
2
3
 
3
4
  module Wxpay
@@ -7,15 +8,14 @@ module Wxpay
7
8
  random_str = SecureRandom.hex(10)
8
9
 
9
10
  defaults = {
10
- appid: Wxpay.app_id,
11
- mch_id: Wxpay.merchant_id,
11
+ appid: order.app_id,
12
+ mch_id: order.merchant_id,
12
13
  nonce_str: random_str
13
14
  }
14
15
 
15
16
  param = defaults.merge(order.attributes).merge(options)
16
17
 
17
- sort_str = Wxpay::Sign.create_sign_str param
18
- sign = Wxpay::Sign.sign_package sort_str
18
+ sign = Wxpay::Sign.sign_package param
19
19
 
20
20
  _xm = Builder::XmlMarkup.new
21
21
  request_str = _xm.xml {
@@ -0,0 +1,29 @@
1
+ module Wxpay
2
+ module Controllers
3
+
4
+ AUTHORIZE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize'
5
+ ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token'
6
+
7
+ def wxpay_openid
8
+ return if session[:wxpay_openid]
9
+ code = request.parameters[:code]
10
+ # 如果code参数为空,则为认证第一步,重定向到微信认证
11
+ if code.nil?
12
+ url = URI.encode(request.url, /\W/)
13
+ redirect_to "#{AUTHORIZE_URL}?appid=#{Wxpay.app_id}&redirect_uri=#{url}&response_type=code&scope=snsapi_base&state=WXPAY#wechat_redirect"
14
+ return
15
+ end
16
+
17
+ #如果code参数不为空,则认证到第二步,通过code获取openid,并保存到session中
18
+ begin
19
+ url = "#{ACCESS_TOKEN_URL}?appid=#{Wxpay.app_id}&secret=#{Wxpay.app_secret}&code=#{code}&grant_type=authorization_code"
20
+ openid = JSON.parse(URI.parse(url).read)["openid"]
21
+ session[:wxpay_openid] = openid
22
+ return openid
23
+ rescue Exception => e
24
+ warn "Wechat openid Exception::::::"
25
+ warn e.message
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module Wxpay
2
+ module Helpers
3
+ def render_jsapi_script options={}
4
+ javascript_tag <<-SCRIPT
5
+ function onBridgeReady(){
6
+ WeixinJSBridge.invoke(
7
+ 'getBrandWCPayRequest', {
8
+ "appId" : "#{Wxpay.app_id}",
9
+ "timeStamp": "#{options[:timestamp]}",
10
+ "nonceStr" : "#{options[:nonce_str]}",
11
+ "package" : "#{options[:package]}",
12
+ "signType" : "MD5",
13
+ "paySign" : "#{options[:pay_sign]}"
14
+ },
15
+ function(res){
16
+ if(res.err_msg == "get_brand_wcpay_request:ok" ) {
17
+ window.location = "#{options[:success_url]}";
18
+ }
19
+ }
20
+ );
21
+ }
22
+ if (typeof WeixinJSBridge == "undefined"){
23
+ if( document.addEventListener ){
24
+ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
25
+ }else if (document.attachEvent){
26
+ document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
27
+ document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
28
+ }
29
+ }else{
30
+ onBridgeReady();
31
+ }
32
+ SCRIPT
33
+ end
34
+ end
35
+ end
@@ -52,10 +52,6 @@ module Wxpay
52
52
  raise OrderIllegal, "trade_type must be one of ['NATIVE', 'APP', 'JSAPI']"
53
53
  end
54
54
 
55
- if @trade_type == 'JSAPI' && @openid.blank?
56
- raise OrderIllegal, "openid is needed"
57
- end
58
-
59
55
  if @trade_type == 'NATIVE' && @product_id.blank?
60
56
  raise OrderIllegal, "product_id is needed"
61
57
  end
@@ -23,11 +23,12 @@ module Wxpay
23
23
 
24
24
  Wxpay.debug_info resp.body
25
25
 
26
- if xml.at('code_url').present?
27
- code_url = xml.at('code_url').text
28
- return {status: 'success', code_url: code_url}
29
- else
26
+ if xml.at('return_code').text == 'SUCCESS' && xml.at('result_code').text == 'SUCCESS'
27
+ return {status: 'success', prepay_id: xml.at('prepay_id').text}
28
+ elsif xml.at('return_code').text == 'SUCCESS'
30
29
  return {status: 'failure', err_msg: xml.at('err_code_des').text}
30
+ else
31
+ return {status: 'failure', err_msg: xml.at('return_msg').text}
31
32
  end
32
33
  end
33
34
 
@@ -54,11 +55,12 @@ module Wxpay
54
55
 
55
56
  Wxpay.debug_info resp.body
56
57
 
57
- if xml.at('code_url').present?
58
- code_url = xml.at('code_url').text
59
- return {status: 'success', code_url: code_url}
58
+ if xml.at('return_code').text == 'SUCCESS' && xml.at('result_code').text == 'SUCCESS'
59
+ return {status: 'success', prepay_id: xml.at('prepay_id').text}
60
+ elsif xml.at('return_code').text == 'SUCCESS'
61
+ return {status: 'failure', err_msg: xml.at('err_code_des').text}
60
62
  else
61
- return {status: 'error', err_msg: xml.at('return_msg').text}
63
+ return {status: 'failure', err_msg: xml.at('return_msg').text}
62
64
  end
63
65
  end
64
66
  end
@@ -2,21 +2,32 @@ module Wxpay
2
2
  module Sign
3
3
  extend self
4
4
 
5
- def sign_package params_str, options={}
6
- if params_str =~ /trade_type=APP/ || options[:trade_type] == 'APP'
5
+ # used in wechat pay api
6
+ def sign_package params
7
+ params_str = create_sign_str params
8
+
9
+ if params_str =~ /trade_type=APP/
7
10
  key = Wxpay.app_api_key
8
11
  else
9
12
  key = Wxpay.api_key
10
13
  end
11
- Rails.logger.info "sign_package:::::: #{params_str}"
12
14
  Digest::MD5.hexdigest(params_str+"&key=#{key}").upcase
13
15
  end
14
16
 
15
- def sign_pay params_str
16
- Rails.logger.info "sign_pay:::::: #{params_str}"
17
+ # used in wechat jssdk ,
18
+ def sign_jssdk params
19
+ params_str = create_sign_str params
20
+
17
21
  Digest::SHA1.hexdigest params_str
18
22
  end
19
23
 
24
+ # used in wechat pay notify
25
+ def verify params
26
+ params['sign'] == sign_package(params.except('sign'))
27
+ end
28
+
29
+ private
30
+
20
31
  def create_sign_str options={}, sort=true
21
32
  unsigned_str = ''
22
33
  if sort
@@ -28,9 +39,5 @@ module Wxpay
28
39
  unsigned_str = unsigned_str[0, unsigned_str.length - 1]
29
40
  end
30
41
 
31
- def verify params
32
- sign_str = create_sign_str(params.except('sign'))
33
- params['sign'] == sign_package(sign_str)
34
- end
35
42
  end
36
43
  end
@@ -1,3 +1,3 @@
1
1
  module Wxpay
2
- VERSION = "0.1.0.alpha"
2
+ VERSION = "0.1.0.beta"
3
3
  end
@@ -16,10 +16,14 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
20
  spec.require_paths = ["lib"]
20
21
 
21
22
  spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "minitest"
25
+ spec.add_development_dependency "fakeweb"
26
+ spec.add_dependency "builder", "~> 3.2"
23
27
  spec.add_dependency "nokogiri", "~> 1.6"
24
28
  spec.add_dependency "faraday", "~> 0.9.1"
25
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wxpay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha
4
+ version: 0.1.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - lifeixiong
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-21 00:00:00.000000000 Z
11
+ date: 2016-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,58 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fakeweb
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: builder
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :runtime
77
+ prerelease: false
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
80
  - - "~>"
39
81
  - !ruby/object:Gem::Version
40
- version: '10.0'
82
+ version: '3.2'
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: nokogiri
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -85,7 +127,8 @@ files:
85
127
  - lib/wxpay/api.rb
86
128
  - lib/wxpay/api/orderquery.rb
87
129
  - lib/wxpay/api/unifiedorder.rb
88
- - lib/wxpay/openid.rb
130
+ - lib/wxpay/controllers.rb
131
+ - lib/wxpay/helpers.rb
89
132
  - lib/wxpay/order.rb
90
133
  - lib/wxpay/order/pay.rb
91
134
  - lib/wxpay/sign.rb
@@ -1,24 +0,0 @@
1
- module Wxpay
2
- module Openid
3
- AUTHORIZE_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize'
4
- ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token'
5
- def get_openid
6
- code = params[:code]
7
- Rails.logger.info "code: #{code}"
8
- # 如果code参数为空,则为认证第一步,重定向到微信认证
9
- if code.nil?
10
- url = URI.encode(request.url.gsub('www.tangpin.me', 'tangpin.me'), /\W/)
11
- redirect_to "#{AUTHORIZE_URL}?appid=#{WEIXIN_ID}&redirect_uri=#{url}&response_type=code&scope=snsapi_base&state=tangpin#wechat_redirect"
12
- return
13
- end
14
-
15
- #如果code参数不为空,则认证到第二步,通过code获取openid,并保存到session中
16
- begin
17
- url = "#{ACCESS_TOKEN_URL}?appid=#{WEIXIN_ID}&secret=#{WEIXIN_SECRET}&code=#{code}&grant_type=authorization_code"
18
- session[:weixin_openid] = JSON.parse(URI.parse(url).read)["openid"]
19
- rescue Exception => e
20
- # ...
21
- end
22
- end
23
- end
24
- end