Commit 1fa6ade437289662de34647f24a1910df7dcff3b
1 parent
48419b64
Exists in
master
first functional version
Showing
12 changed files
with
115 additions
and
62 deletions
Show diff stats
README.md
@@ -30,14 +30,47 @@ $ bundle | @@ -30,14 +30,47 @@ $ bundle | ||
30 | ### Config | 30 | ### Config |
31 | 31 | ||
32 | ```ruby | 32 | ```ruby |
33 | +# required | ||
33 | WxPay.appid = 'YOUR_APPID' | 34 | WxPay.appid = 'YOUR_APPID' |
34 | WxPay.key = 'YOUR_KEY' | 35 | WxPay.key = 'YOUR_KEY' |
35 | WxPay.mch_id = 'YOUR_MCH_ID' | 36 | WxPay.mch_id = 'YOUR_MCH_ID' |
37 | + | ||
38 | +# optional | ||
39 | +WxPay.extra_rest_client_options = {timeout: 2, open_timeout: 3} | ||
36 | ``` | 40 | ``` |
37 | 41 | ||
38 | ### APIs | 42 | ### APIs |
39 | 43 | ||
40 | -**PLACEHOLDER** | 44 | +**Check official document for detailed request params and return fields** |
45 | + | ||
46 | +#### unifiedorder | ||
47 | + | ||
48 | +```ruby | ||
49 | +# required fields | ||
50 | +params = { | ||
51 | +body: '测试商品', | ||
52 | +out_trade_no: 'test003', | ||
53 | +total_fee: 1, | ||
54 | +spbill_create_ip: '127.0.0.1', | ||
55 | +notify_url: 'http://making.dev', | ||
56 | +trade_type: 'JSAPI' | ||
57 | +} | ||
58 | + | ||
59 | +# Return a WxPay::Result instance(subclass of Hash) contains parsed result | ||
60 | +r = WxPay::Service.invoke_unifiedorder params | ||
61 | +# => {"return_code"=>"SUCCESS", | ||
62 | +# "return_msg"=>"OK", | ||
63 | +# "appid"=>"YOUR APPID", | ||
64 | +# "mch_id"=>"YOUR MCH_ID", | ||
65 | +# "nonce_str"=>"8RN7YfTZ3OUgWX5e", | ||
66 | +# "sign"=>"623AE90C9679729DDD7407DC7A1151B2", | ||
67 | +# "result_code"=>"SUCCESS", | ||
68 | +# "prepay_id"=>"wx2014111104255143b7605afb0314593866", | ||
69 | +# "trade_type"=>"JSAPI"} | ||
70 | + | ||
71 | +# Return true if both return_code and result_code equal SUCCESS | ||
72 | +r.success? # => true | ||
73 | +``` | ||
41 | 74 | ||
42 | ## Contributing | 75 | ## Contributing |
43 | 76 |
lib/wx_pay.rb
lib/wx_pay/notify.rb
@@ -1,18 +0,0 @@ | @@ -1,18 +0,0 @@ | ||
1 | -module WxPay | ||
2 | - module Notify | ||
3 | - GATEWAY = 'https://gw.tenpay.com/gateway/simpleverifynotifyid.xml' | ||
4 | - SUCCESS_STR = '<retcode>0</retcode>' | ||
5 | - | ||
6 | - def self.verify?(params) | ||
7 | - return false unless Sign.verify?(params) | ||
8 | - | ||
9 | - params = { | ||
10 | - 'input_charset' => 'UTF-8', | ||
11 | - 'partner' => WxPay.appid, | ||
12 | - 'notify_id' => CGI.escape(params[:notify_id].to_s) | ||
13 | - } | ||
14 | - | ||
15 | - open("#{GATEWAY}?#{Utils.make_query_string(params)}").read.include?(SUCCESS_STR) | ||
16 | - end | ||
17 | - end | ||
18 | -end |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +module WxPay | ||
2 | + class Result < ::Hash | ||
3 | + SUCCESS_FLAG = 'SUCCESS'.freeze | ||
4 | + | ||
5 | + def initialize(result) | ||
6 | + super | ||
7 | + | ||
8 | + if result['xml'].class == Hash | ||
9 | + result['xml'].each_pair do |k, v| | ||
10 | + self[k] = v | ||
11 | + end | ||
12 | + end | ||
13 | + end | ||
14 | + | ||
15 | + def success? | ||
16 | + self['return_code'] == SUCCESS_FLAG && self['result_code'] == SUCCESS_FLAG | ||
17 | + end | ||
18 | + end | ||
19 | +end |
lib/wx_pay/service.rb
@@ -8,14 +8,18 @@ module WxPay | @@ -8,14 +8,18 @@ module WxPay | ||
8 | INVOKE_UNIFIEDORDER_REQUIRED_FIELDS = %i(body out_trade_no total_fee spbill_create_ip notify_url trade_type) | 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) |
10 | params = { | 10 | params = { |
11 | - app_id: WxPay.appid, | 11 | + appid: WxPay.appid, |
12 | mch_id: WxPay.mch_id, | 12 | mch_id: WxPay.mch_id, |
13 | nonce_str: SecureRandom.uuid.tr('-', ''), | 13 | nonce_str: SecureRandom.uuid.tr('-', ''), |
14 | }.merge(params) | 14 | }.merge(params) |
15 | 15 | ||
16 | check_required_options(params, INVOKE_UNIFIEDORDER_REQUIRED_FIELDS) | 16 | check_required_options(params, INVOKE_UNIFIEDORDER_REQUIRED_FIELDS) |
17 | 17 | ||
18 | - WxPay::Utils.invoke_remote("#{GATEWAY_URL}/unifiedorder", WxPay::Utils.make_payload(params)) | 18 | + r = invoke_remote("#{GATEWAY_URL}/unifiedorder", make_payload(params)) |
19 | + | ||
20 | + yield r if block_given? | ||
21 | + | ||
22 | + r | ||
19 | end | 23 | end |
20 | 24 | ||
21 | private | 25 | private |
@@ -25,5 +29,26 @@ module WxPay | @@ -25,5 +29,26 @@ module WxPay | ||
25 | warn("WxPay Warn: missing required option: #{name}") unless options.has_key?(name) | 29 | warn("WxPay Warn: missing required option: #{name}") unless options.has_key?(name) |
26 | end | 30 | end |
27 | end | 31 | end |
32 | + | ||
33 | + def self.make_payload(params) | ||
34 | + "<xml>#{params.map { |k, v| "<#{k}>#{v}</#{k}>" }.join}<sign>#{WxPay::Sign.generate(params)}</sign></xml>" | ||
35 | + end | ||
36 | + | ||
37 | + def self.invoke_remote(url, payload) | ||
38 | + r = RestClient::Request.execute( | ||
39 | + { | ||
40 | + method: :post, | ||
41 | + url: url, | ||
42 | + payload: payload, | ||
43 | + headers: { content_type: 'application/xml' } | ||
44 | + }.merge(WxPay.extra_rest_client_options) | ||
45 | + ) | ||
46 | + | ||
47 | + if r | ||
48 | + WxPay::Result.new Hash.from_xml(r) | ||
49 | + else | ||
50 | + nil | ||
51 | + end | ||
52 | + end | ||
28 | end | 53 | end |
29 | end | 54 | end |
lib/wx_pay/sign.rb
@@ -11,8 +11,8 @@ module WxPay | @@ -11,8 +11,8 @@ module WxPay | ||
11 | end | 11 | end |
12 | 12 | ||
13 | def self.verify?(params) | 13 | def self.verify?(params) |
14 | - params = Utils.stringify_keys(params) | ||
15 | - sign = params.delete('sign') | 14 | + params = params.dup |
15 | + sign = params.delete('sign') || params.delete(:sign) | ||
16 | 16 | ||
17 | generate(params) == sign | 17 | generate(params) == sign |
18 | end | 18 | end |
lib/wx_pay/utils.rb
@@ -1,27 +0,0 @@ | @@ -1,27 +0,0 @@ | ||
1 | -module WxPay | ||
2 | - module Utils | ||
3 | - def self.stringify_keys(hash) | ||
4 | - new_hash = {} | ||
5 | - hash.each do |key, value| | ||
6 | - new_hash[(key.to_s rescue key) || key] = value | ||
7 | - end | ||
8 | - new_hash | ||
9 | - end | ||
10 | - | ||
11 | - def self.make_payload(params) | ||
12 | - "<xml>#{params.map {|k, v| "<#{k}>#{v}</#{k}>"}.join}<sign>#{WxPay::Sign.generate(params)}</sign></xml>" | ||
13 | - end | ||
14 | - | ||
15 | - def self.invoke_remote(url, payload) | ||
16 | - Hash.from_xml( | ||
17 | - RestClient::Request.execute( | ||
18 | - { | ||
19 | - method: :post, | ||
20 | - url: url, | ||
21 | - payload: payload, | ||
22 | - headers: {content_type: 'application/xml'} | ||
23 | - }.merge(WxPay.extra_rest_client_options)) | ||
24 | - ) | ||
25 | - end | ||
26 | - end | ||
27 | -end |
lib/wx_pay/version.rb
test/test_helper.rb
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class WxPay::ResultTest < MiniTest::Test | ||
4 | + def test_success_method_with_true | ||
5 | + r = WxPay::Result.new( | ||
6 | + Hash.from_xml( | ||
7 | + <<-XML | ||
8 | + <xml> | ||
9 | + <return_code>SUCCESS</return_code> | ||
10 | + <result_code>SUCCESS</result_code> | ||
11 | + </xml> | ||
12 | + XML | ||
13 | + )) | ||
14 | + | ||
15 | + assert_equal r.success?, true | ||
16 | + end | ||
17 | + | ||
18 | + def test_success_method_with_false | ||
19 | + r = WxPay::Result.new( | ||
20 | + Hash.from_xml( | ||
21 | + <<-XML | ||
22 | + <xml> | ||
23 | + </xml> | ||
24 | + XML | ||
25 | + )) | ||
26 | + | ||
27 | + assert_equal r.success?, false | ||
28 | + end | ||
29 | +end |
test/wx_pay/sign_test.rb
test/wx_pay/utils_test.rb