allpay_client 1.0.9 → 2.0.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: 45e8efe0cfd77657844f1579f7ba92f0353163ec
4
- data.tar.gz: 9359e09cf6c1a665dc6a1ababe6e749a5ff3726f
3
+ metadata.gz: 289f14a5eea78b627c25e2ba352b8db3fefc0085
4
+ data.tar.gz: 33a5f66099a93de19b3a2d0fded4d3642bf195d5
5
5
  SHA512:
6
- metadata.gz: 7a8b488d46e9c5f8eaa892ebfa177cd8f5be1c35425b91f467dec7c356839ca8baaad0098397bf7c5772f2a2b63cef7fd12c220ed7e810f25afdda3c774afe4c
7
- data.tar.gz: 67779336cc5698abd9a47b413bec97f8fd1031219d281b578d694f3a06c4505ff7250d2ac1c54bfeb625875503a1547e0f95a77e6060bf2ca19d926907d81843
6
+ metadata.gz: 53a307012b9805ee5bd2c2f284d7eeaa6455b71d0b877d5ce00d1dc2bdf8e75910771e3dcc3a7c5d616c5fd3f7acab547d340c5a9061a02296b4f46f449fa952
7
+ data.tar.gz: c1e186805948c1339029b4bab674f2aa506687d7be994a41d07f69157de9f8c3a880eb71cf878dc05a77db55f14cc88af15c155a0315853e33007f3a4c530613
data/README.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  這是歐付寶 API 的 Ruby 包裝,更多資訊參考他們的[官方文件](https://www.allpay.com.tw/Content/files/%E5%85%A8%E6%96%B9%E4%BD%8D%E9%87%91%E6%B5%81%E4%BB%8B%E6%8E%A5%E6%8A%80%E8%A1%93%E6%96%87%E4%BB%B6.pdf)。
6
6
 
7
+ - 這不是 Rails 插件,只是個 API 包裝。
8
+ - 使用時只需要傳送需要的參數即可,不用產生檢查碼,`allpay_client` 會自己產生。
9
+ - 錯誤代碼太多且會不斷增加,筆者不另行撰寫,官方也建議查網站上的代碼清單。
10
+
7
11
  ## 安裝
8
12
 
9
13
  ```bash
@@ -13,13 +17,14 @@ gem install allpay_client
13
17
  ## 使用
14
18
 
15
19
  ```ruby
16
- client = Allpay::Client.new({
17
- merchant_id: '2000132',
18
- hash_key: '5294y06JbISpM5x9',
19
- hash_iv: 'v77hoKGq4kWxNNIS',
20
- mode: :test
20
+ test_client = Allpay::Client.new(mode: :test)
21
+ production_client = Allpay::Client.new({
22
+ merchant_id: 'MERCHANT_ID',
23
+ hash_key: 'HASH_KEY',
24
+ hash_iv: 'HASH_IV'
21
25
  })
22
- client.request '/Cashier/QueryTradeInfo',
26
+
27
+ test_client.request '/Cashier/QueryTradeInfo',
23
28
  MerchantTradeNo: '0457ce27',
24
29
  TimeStamp: Time.now.to_i
25
30
  ```
@@ -32,10 +37,10 @@ client.request '/Cashier/QueryTradeInfo',
32
37
  - /CreditDetail/DoAction
33
38
  - /Cashier/AioChargeback
34
39
 
35
- 每個 API 有哪些參數建議直接參考歐付寶文件,不過要注意幾點:
40
+ 每個 API 有哪些參數建議直接參考歐付寶文件,注意幾點:
36
41
 
37
- - 原本 API 都需要 `MerchantID` 與 `CheckMacValue`,不過 `Client#request` 已經都處理好了,使用時可忽略這兩個參數,正如上述範例一樣。
38
- - `/Cashier/AioCheckOut` 回傳的內容是 HTML,這個請求應該是交給瀏覽器發送的,所以不應該寫出 `client.request '/Cashier/AioCheckOut'`這樣的內容。
42
+ - 使用時不用煩惱 `MerchantID` 與 `CheckMacValue`,正如上述範例一樣。
43
+ - `/Cashier/AioCheckOut` 回傳的內容是 HTML,這個請求應該是交給瀏覽器發送的,所以不應該寫出 `client.request '/Cashier/AioCheckOut'` 這樣的內容。
39
44
 
40
45
  ## Allpay::Client
41
46
 
@@ -43,8 +48,10 @@ client.request '/Cashier/QueryTradeInfo',
43
48
  --- | --- | ---
44
49
  `request(path, **params)` | `Net::HTTPResponse` | 發送 API 請求
45
50
  `make_mac(**params)` | `String` | 用於產生 `CheckMacValue`,單純做加密,`params` 需要完整包含到 `MerchantID`
51
+ `verify_mac(**params)` | `Boolean` | 會於檢查收到的參數,其檢查碼是否正確,這用在歐付寶物的 `ReturnURL` 與 `PeriodReturnURL` 參數上。
46
52
  `query_trade_info(merchant_trade_number, platform = nil)` | `Hash` | `/Cashier/QueryTradeInfo` 的捷徑方法,將 `TimeStamp` 設定為當前時間
47
53
  `query_period_credit_card_trade_info(merchant_trade_number)` | `Hash` | `/Cashier/QueryPeriodCreditCardTradeInfo` 的捷徑方法,將 `TimeStamp` 設定為當前時間
54
+ `generate_checkout_params` | `Hash` | 用於產生 `/Cashier/AioCheckOut` 表單需要的參數,`MerchantTradeDate`、`MerchantTradeNo`、`PaymentType`,可省略。
48
55
 
49
56
  ## 使用範例
50
57
 
data/examples/server.rb CHANGED
@@ -4,12 +4,9 @@ require 'sinatra'
4
4
  require 'allpay'
5
5
 
6
6
  get '/' do
7
- client = Allpay::Client.new(merchant_id: '2000132', hash_key: '5294y06JbISpM5x9', hash_iv: 'v77hoKGq4kWxNNIS', mode: :test)
8
- @params = {
9
- MerchantID: client.merchant_id,
7
+ client = Allpay::Client.new(mode: :test)
8
+ @params = client.generate_checkout_params({
10
9
  MerchantTradeNo: SecureRandom.hex(4),
11
- MerchantTradeDate: Time.now.strftime('%Y/%m/%d %H:%M:%S'),
12
- PaymentType: 'aio',
13
10
  TotalAmount: 1000,
14
11
  TradeDesc: '腦袋有動工作室',
15
12
  ItemName: '物品一#物品二',
@@ -21,7 +18,6 @@ get '/' do
21
18
  Frequency: 1,
22
19
  ExecTimes: 12,
23
20
  PeriodReturnURL: 'http://requestb.in/158bu8e1'
24
- }
25
- @mac = client.make_mac(@params)
21
+ })
26
22
  erb :index
27
23
  end
@@ -6,23 +6,9 @@
6
6
  </head>
7
7
  <body>
8
8
  <form action="http://payment-stage.allpay.com.tw/Cashier/AioCheckOut" method="post">
9
- <input type="text" name="MerchantID" value="<%= @params[:MerchantID] %>">
10
- <input type="text" name="MerchantTradeNo" value="<%= @params[:MerchantTradeNo] %>">
11
- <input type="text" name="MerchantTradeDate" value="<%= @params[:MerchantTradeDate] %>">
12
- <input type="text" name="PaymentType" value="<%= @params[:PaymentType] %>">
13
- <input type="text" name="TotalAmount" value="<%= @params[:TotalAmount] %>">
14
- <input type="text" name="TradeDesc" value="<%= @params[:TradeDesc] %>">
15
- <input type="text" name="ItemName" value="<%= @params[:ItemName] %>">
16
- <input type="text" name="ReturnURL" value="<%= @params[:ReturnURL] %>">
17
- <input type="text" name="ClientBackURL" value="<%= @params[:ClientBackURL] %>">
18
- <input type="text" name="ChoosePayment" value="<%= @params[:ChoosePayment] %>">
19
- <input type="text" name="PeriodAmount" value="<%= @params[:PeriodAmount] %>">
20
- <input type="text" name="PeriodType" value="<%= @params[:PeriodType] %>">
21
- <input type="text" name="Frequency" value="<%= @params[:Frequency] %>">
22
- <input type="text" name="ExecTimes" value="<%= @params[:ExecTimes] %>">
23
- <input type="text" name="PeriodReturnURL" value="<%= @params[:PeriodReturnURL] %>">
24
-
25
- <input type="text" name="CheckMacValue" value="<%= @mac %>">
9
+ <% @params.each do |k, v| %>
10
+ <input type="text" name="<%= k %>" value="<%= v %>">
11
+ <% end %>
26
12
  <input type="submit">
27
13
  </form>
28
14
  </body>
data/lib/allpay.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "allpay/version"
2
- require "allpay/client"
1
+ require 'allpay/version'
2
+ require 'allpay/client'
3
3
 
4
4
  module Allpay
5
5
  end
data/lib/allpay/client.rb CHANGED
@@ -1,46 +1,73 @@
1
1
  require 'net/http'
2
2
  require 'json'
3
+ require 'cgi'
4
+ require 'digest'
5
+ require 'allpay/errors'
6
+ require 'allpay/core_ext/hash'
3
7
 
4
8
  module Allpay
5
9
  class Client
6
10
  PRODUCTION_API_HOST = 'https://payment.allpay.com.tw'.freeze
7
11
  TEST_API_HOST = 'http://payment-stage.allpay.com.tw'.freeze
12
+ TEST_OPTIONS = {
13
+ merchant_id: '2000132',
14
+ hash_key: '5294y06JbISpM5x9',
15
+ hash_iv: 'v77hoKGq4kWxNNIS'
16
+ }.freeze
8
17
 
9
- attr_accessor :merchant_id, :hash_key, :hash_iv, :mode
18
+ attr_reader :options
10
19
 
11
- def initialize params = {}
12
- merchant_id = params[:merchant_id]
13
- hash_key = params[:hash_key]
14
- hash_iv = params[:hash_iv]
15
- mode = params[:mode]
16
- @merchant_id, @hash_key, @hash_iv, @mode = merchant_id, hash_key, hash_iv, mode
20
+ def initialize options = {}
21
+ @options = {mode: :production}.merge!(options)
22
+ case @options[:mode]
23
+ when :production
24
+ option_required! :merchant_id, :hash_key, :hash_iv
25
+ when :test
26
+ @options = TEST_OPTIONS.merge(options)
27
+ else
28
+ raise InvalidMode, %Q{option :mode is either :test or :production}
29
+ end
30
+ @options.freeze
17
31
  end
18
32
 
19
33
  def api_host
20
- case mode
34
+ case @options[:mode]
21
35
  when :production then PRODUCTION_API_HOST
22
36
  when :test then TEST_API_HOST
23
- else raise '`mode` is either :test or :production (default)'
24
37
  end
25
38
  end
26
39
 
27
40
  def make_mac params = {}
28
41
  raw = params.sort.map!{|k,v| "#{k}=#{v}"}.join('&')
29
- padded = "HashKey=#{@hash_key}&#{raw}&HashIV=#{@hash_iv}"
42
+ padded = "HashKey=#{@options[:hash_key]}&#{raw}&HashIV=#{@options[:hash_iv]}"
30
43
  url_encoded = CGI.escape(padded).downcase!
31
44
  Digest::MD5.hexdigest(url_encoded).upcase!
32
45
  end
33
46
 
34
47
  def verify_mac params = {}
35
- check_mac_value = params[:CheckMacValue] || params['CheckMacValue']
36
- make_mac(params.reject{ |k,v| [:CheckMacValue, 'CheckMacValue'].include? k }) == check_mac_value
48
+ stringified_keys = params.stringify_keys
49
+ check_mac_value = stringified_keys.delete('CheckMacValue')
50
+ make_mac(stringified_keys) == check_mac_value
51
+ end
52
+
53
+ def generate_params overwrite_params = {}
54
+ result = overwrite_params.clone
55
+ result[:MerchantID] = @options[:merchant_id]
56
+ result[:CheckMacValue] = make_mac(result)
57
+ result
58
+ end
59
+
60
+ def generate_checkout_params overwrite_params = {}
61
+ generate_params({
62
+ MerchantTradeDate: Time.now.strftime('%Y/%m/%d %H:%M:%S'),
63
+ MerchantTradeNo: SecureRandom.hex(4),
64
+ PaymentType: 'aio'
65
+ }.merge!(overwrite_params))
37
66
  end
38
67
 
39
68
  def request path, params = {}
40
- params[:MerchantID] = @merchant_id
41
- params[:CheckMacValue] = make_mac(params)
42
69
  api_url = URI.join(api_host, path)
43
- Net::HTTP.post_form api_url, params
70
+ Net::HTTP.post_form api_url, generate_params(params)
44
71
  end
45
72
 
46
73
  def query_trade_info merchant_trade_number, platform = nil
@@ -60,5 +87,13 @@ module Allpay
60
87
  TimeStamp: Time.now.to_i
61
88
  JSON.parse(res.body)
62
89
  end
90
+
91
+ private
92
+
93
+ def option_required! *option_names
94
+ option_names.each do |option_name|
95
+ raise MissingOption, %Q{option "#{option_name}" is required.} if @options[:option_name].nil?
96
+ end
97
+ end
63
98
  end
64
99
  end
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def stringify_keys
3
+ result = self.class.new
4
+ each_key do |key|
5
+ result[key.to_s] = self[key]
6
+ end
7
+ result
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Allpay
2
+ # Generic Allpay exception class.
3
+ class AllpayError < StandardError; end
4
+ class MissingOption < AllpayError; end
5
+ class InvalidMode < AllpayError; end
6
+ end
@@ -1,3 +1,3 @@
1
1
  module Allpay
2
- VERSION = "1.0.9"
2
+ VERSION = "2.0.0"
3
3
  end
data/spec/allpay_spec.rb CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  require 'securerandom'
4
4
  describe Allpay::Client do
5
5
  before :all do
6
- @client = Allpay::Client.new(merchant_id: '2000132', hash_key: '5294y06JbISpM5x9', hash_iv: 'v77hoKGq4kWxNNIS', mode: :test)
6
+ @client = Allpay::Client.new(mode: :test)
7
7
  end
8
8
 
9
9
  it '#api /Cashier/AioCheckOut' do
@@ -41,7 +41,7 @@ describe Allpay::Client do
41
41
  end
42
42
 
43
43
  it '#make_mac' do
44
- client = Allpay::Client.new(merchant_id: '12345678', hash_key: 'xdfaefasdfasdfa32d', hash_iv: 'sdfxfafaeafwexfe')
44
+ client = Allpay::Client.new(merchant_id: '12345678', hash_key: 'xdfaefasdfasdfa32d', hash_iv: 'sdfxfafaeafwexfe', mode: :test)
45
45
  mac = client.make_mac({
46
46
  ItemName: 'sdfasdfa',
47
47
  MerchantID: '12345678',
@@ -70,20 +70,4 @@ describe Allpay::Client do
70
70
  MerchantTradeNo: '355313'
71
71
  expect(result).to eq true
72
72
  end
73
-
74
- it '#verify_mac with string hash' do
75
- result = @client.verify_mac 'RtnCode' => '1',
76
- 'PaymentType' => 'Credit_CreditCard',
77
- 'TradeAmt' => '700',
78
- 'PaymentTypeChargeFee' => '14',
79
- 'PaymentDate' => '2015/02/07 14:21:00',
80
- 'SimulatePaid' => '0',
81
- 'CheckMacValue' => '3AF270CCCFA58CA0349F4FD462E21643',
82
- 'TradeDate' => '2015/02/07 14:20:47',
83
- 'MerchantID' => '2000132',
84
- 'TradeNo' => '1502071420478656',
85
- 'RtnMsg' => '交易成功',
86
- 'MerchantTradeNo' => '355313'
87
- expect(result).to eq true
88
- end
89
73
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: allpay_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jian Weihang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-08 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -85,6 +85,8 @@ files:
85
85
  - examples/views/index.erb
86
86
  - lib/allpay.rb
87
87
  - lib/allpay/client.rb
88
+ - lib/allpay/core_ext/hash.rb
89
+ - lib/allpay/errors.rb
88
90
  - lib/allpay/version.rb
89
91
  - lib/allpay_client.rb
90
92
  - spec/allpay_spec.rb