Commit 1fa6ade437289662de34647f24a1910df7dcff3b

Authored by jasl
1 parent 48419b64
Exists in master

first functional version

@@ -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
1 -require 'wx_pay/utils' 1 +require 'wx_pay/result'
2 require 'wx_pay/sign' 2 require 'wx_pay/sign'
3 require 'wx_pay/service' 3 require 'wx_pay/service'
4 -require 'wx_pay/notify'  
5 4
6 module WxPay 5 module WxPay
7 class<< self 6 class<< self
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  
lib/wx_pay/result.rb 0 → 100644
@@ -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
1 module WxPay 1 module WxPay
2 - VERSION = "0.0.1" 2 + VERSION = "0.0.2"
3 end 3 end
test/test_helper.rb
  1 +require 'active_support/core_ext/hash/conversions'
1 require 'minitest/autorun' 2 require 'minitest/autorun'
2 require 'wx_pay' 3 require 'wx_pay'
3 require 'fakeweb' 4 require 'fakeweb'
test/wx_pay/result_test.rb 0 → 100644
@@ -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
1 require 'test_helper' 1 require 'test_helper'
2 2
3 -class WxPay::SignTest < MiniTest::Unit::TestCase 3 +class WxPay::SignTest < MiniTest::Test
4 def setup 4 def setup
5 @params = { 5 @params = {
6 appid: 'wxd930ea5d5a258f4f', 6 appid: 'wxd930ea5d5a258f4f',
test/wx_pay/utils_test.rb
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -require 'test_helper'  
2 -  
3 -class WxPay::UtilsTest < MiniTest::Unit::TestCase  
4 - def test_stringify_keys  
5 - hash = { 'a' => 1, :b => 2 }  
6 - assert_equal({ 'a' => 1, 'b' => 2 }.sort, WxPay::Utils.stringify_keys(hash).sort)  
7 - end  
8 -end