allpay_client 1.0.9 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -9
- data/examples/server.rb +3 -7
- data/examples/views/index.erb +3 -17
- data/lib/allpay.rb +2 -2
- data/lib/allpay/client.rb +50 -15
- data/lib/allpay/core_ext/hash.rb +9 -0
- data/lib/allpay/errors.rb +6 -0
- data/lib/allpay/version.rb +1 -1
- data/spec/allpay_spec.rb +2 -18
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 289f14a5eea78b627c25e2ba352b8db3fefc0085
|
4
|
+
data.tar.gz: 33a5f66099a93de19b3a2d0fded4d3642bf195d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
-
-
|
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(
|
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
|
data/examples/views/index.erb
CHANGED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
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
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
|
-
|
18
|
+
attr_reader :options
|
10
19
|
|
11
|
-
def initialize
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
36
|
-
|
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
|
data/lib/allpay/version.rb
CHANGED
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(
|
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:
|
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-
|
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
|