pay2go_client 1.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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +161 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/public/style.css +15 -0
- data/examples/server.rb +46 -0
- data/examples/views/mpg.erb +30 -0
- data/examples/views/period.erb +30 -0
- data/lib/pay2go.rb +5 -0
- data/lib/pay2go/client.rb +245 -0
- data/lib/pay2go/core_ext/hash.rb +9 -0
- data/lib/pay2go/errors.rb +8 -0
- data/lib/pay2go/version.rb +3 -0
- data/lib/pay2go_client.rb +1 -0
- data/pay2go.gemspec +27 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 94c744431068dcfe778555adc0b846e716c240ec
|
4
|
+
data.tar.gz: 69ef98e01e9a55a5f49d993fff121bc4b667567f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5799cd9ec1151aa49c81d73b34a81b20d2c2119ddcf25065518d6b6ca8c2a19d7b46fb296f4ac68e019f9a7394fb6050b6ac940c4e4b4999958aa7cd751c241c
|
7
|
+
data.tar.gz: 11e7bcfbfb562ff6cd08b9f80213345ceef349cfd485dc806975459834696ed7aedaca441680b0c21ff3c75c689a282bdbd86a19bf746c07de9333d3ae01f836
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Calvert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
[](https://travis-ci.org/CalvertYang/pay2go)
|
2
|
+
|
3
|
+
# 智付寶 Pay2go
|
4
|
+
|
5
|
+
這是智付寶 API 的 Ruby 包裝,更多資訊請參閱 [API 文件專區](https://www.pay2go.com/info/site_description/api_description)。
|
6
|
+
|
7
|
+
- 這不是 Rails 插件,只是個 API 包裝。
|
8
|
+
- 使用時只需要傳送需要的參數即可,不用產生檢查碼,`pay2go_client` 會自己產生。
|
9
|
+
- 感謝[大兜](https://github.com/tonytonyjan)撰寫的 [allpay](https://github.com/tonytonyjan/allpay)
|
10
|
+
|
11
|
+
## 安裝
|
12
|
+
|
13
|
+
```bash
|
14
|
+
gem install pay2go_client
|
15
|
+
```
|
16
|
+
|
17
|
+
## 使用
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
test_client = Pay2go::Client.new({
|
21
|
+
merchant_id: 'MERCHANT_ID',
|
22
|
+
hash_key: 'HASH_KEY',
|
23
|
+
hash_iv: 'HASH_IV',
|
24
|
+
mode: :test
|
25
|
+
})
|
26
|
+
|
27
|
+
production_client = Pay2go::Client.new({
|
28
|
+
merchant_id: 'MERCHANT_ID',
|
29
|
+
hash_key: 'HASH_KEY',
|
30
|
+
hash_iv: 'HASH_IV'
|
31
|
+
})
|
32
|
+
|
33
|
+
test_client.query_trade_info({
|
34
|
+
MerchantOrderNo: '4e19cab1',
|
35
|
+
Amt: 100
|
36
|
+
})
|
37
|
+
```
|
38
|
+
|
39
|
+
本文件撰寫時,智付寶共有 5 個 API:
|
40
|
+
|
41
|
+
API 名稱 | 說明
|
42
|
+
--- | ---
|
43
|
+
MPG API | MPG(Multi Payment Gateway),單一串接多種支付方式。<br>透過 MPG API 可串接平台提供的所有支付方式。
|
44
|
+
交易狀態查詢 API | 透過交易查詢 API 可自動化查核所有交易是否同步更新付款資訊。
|
45
|
+
信用卡-取消授權模組 API | 透過取消授權 API,可進行信用卡交易授權取消,以返還持卡人及商店信用卡額度。
|
46
|
+
信用卡-請退款模組 API | 透過請退款 API,可進行信用卡交易的請退款。
|
47
|
+
信用卡-定期定額 API | 透過信用卡定期定額 API,可進行信用卡定期定額交易。
|
48
|
+
|
49
|
+
詳細 API 參數請參閱智付寶技術串接手冊,注意幾點:
|
50
|
+
|
51
|
+
- 使用時不用煩惱 `MerchantID`、`RespondType`、`CheckValue`、`TimeStamp` 及 `Version`,正如上述範例一樣。
|
52
|
+
- MPG/信用卡-定期定額 API 回傳的內容是 HTML,這個請求應該是交給瀏覽器發送的。
|
53
|
+
|
54
|
+
## Pay2go::Client
|
55
|
+
|
56
|
+
實體方法 | 回傳 | 說明
|
57
|
+
--- | --- | ---
|
58
|
+
`verify_check_code(params)` | `Boolean` | 會於檢查收到的參數,其檢查碼是否正確,用於智付寶的 `NotifyURL` 參數及檢核資料回傳的合法性。
|
59
|
+
`generate_mpg_params(params)` | `Hash` | 用於產生 MPG API 表單需要的參數。
|
60
|
+
`query_trade_info(params)` | `Hash` | 用於查詢交易狀態。
|
61
|
+
`credit_card_deauthorize(params)` | `Hash` | 用於進行信用卡交易授權取消作業。
|
62
|
+
`credit_card_deauthorize_by_merchant_order_no(params)` | `Hash` | `credit_card_deauthorize` 的捷徑方法,將 `IndexType` 設為 1
|
63
|
+
`credit_card_deauthorize_by_trade_no(params)` | `Hash` | `credit_card_deauthorize` 的捷徑方法,將 `IndexType` 設為 2
|
64
|
+
`credit_card_collect_refund(params)` | `Hash` | 用於進行信用卡交易的請退款作業。
|
65
|
+
`credit_card_collect_refund_by_merchant_order_no(params)` | `Hash` | `credit_card_collect_refund` 的捷徑方法,將 `IndexType` 設為 1
|
66
|
+
`credit_card_collect_refund_by_trade_no(params)` | `Hash` | `credit_card_collect_refund` 的捷徑方法,將 `IndexType` 設為 2
|
67
|
+
`generate_credit_card_period_params(params)` | `Hash` | 用於產生信用卡-定期定額 API 表單需要的參數。
|
68
|
+
|
69
|
+
## 使用範例
|
70
|
+
|
71
|
+
##### MPG、信用卡-定期定額
|
72
|
+
```bash
|
73
|
+
git clone git@github.com:CalvertYang/pay2go.git
|
74
|
+
cd pay2go
|
75
|
+
bundle install
|
76
|
+
ruby examples/server.rb
|
77
|
+
```
|
78
|
+
|
79
|
+
- MPG(GET):http://localhost:4567/mpg
|
80
|
+
- 信用卡-定期定額(GET):http://localhost:4567/period
|
81
|
+
- 驗證資料合法性(POST):http://localhost:4567/validate
|
82
|
+
|
83
|
+
##### 交易狀態查詢
|
84
|
+
```ruby
|
85
|
+
result = test_client.query_trade_info({
|
86
|
+
MerchantOrderNo: '4e19cab1',
|
87
|
+
Amt: 100
|
88
|
+
})
|
89
|
+
|
90
|
+
puts "Result: #{result}"
|
91
|
+
puts "Valid?: #{@client.verify_check_code(result)}"
|
92
|
+
```
|
93
|
+
|
94
|
+
##### 信用卡-取消授權模組
|
95
|
+
```ruby
|
96
|
+
result = test_client.credit_card_deauthorize({
|
97
|
+
TradeNo: '16010112345678901',
|
98
|
+
Amt: 100,
|
99
|
+
IndexType: 1
|
100
|
+
})
|
101
|
+
|
102
|
+
puts "Result: #{result}"
|
103
|
+
puts "Valid?: #{@client.verify_check_code(result)}"
|
104
|
+
```
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
result = test_client.credit_card_deauthorize_by_merchant_order_no({
|
108
|
+
MerchantOrderNo: '4e19cab1',
|
109
|
+
Amt: 100
|
110
|
+
})
|
111
|
+
|
112
|
+
puts "Result: #{result}"
|
113
|
+
puts "Valid?: #{@client.verify_check_code(result)}"
|
114
|
+
```
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
result = test_client.credit_card_deauthorize_by_trade_no({
|
118
|
+
TradeNo: '16010112345678901',
|
119
|
+
Amt: 100
|
120
|
+
})
|
121
|
+
|
122
|
+
puts "Result: #{result}"
|
123
|
+
puts "Valid?: #{@client.verify_check_code(result)}"
|
124
|
+
```
|
125
|
+
|
126
|
+
##### 信用卡-請退款模組
|
127
|
+
```ruby
|
128
|
+
result = test_client.credit_card_collect_refund({
|
129
|
+
MerchantOrderNo: '4e19cab1',
|
130
|
+
Amt: 100,
|
131
|
+
CloseType: 2,
|
132
|
+
IndexType: 1
|
133
|
+
})
|
134
|
+
|
135
|
+
puts "Result: #{result}"
|
136
|
+
```
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
result = test_client.credit_card_collect_refund_by_merchant_order_no({
|
140
|
+
MerchantOrderNo: '4e19cab1',
|
141
|
+
Amt: 100,
|
142
|
+
CloseType: 2
|
143
|
+
})
|
144
|
+
|
145
|
+
puts "Result: #{result}"
|
146
|
+
```
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
result = test_client.credit_card_collect_refund_by_trade_no({
|
150
|
+
TradeNo: '16010112345678901',
|
151
|
+
Amt: 100,
|
152
|
+
CloseType: 2
|
153
|
+
})
|
154
|
+
|
155
|
+
puts "Result: #{result}"
|
156
|
+
```
|
157
|
+
|
158
|
+
## License
|
159
|
+
MIT
|
160
|
+
|
161
|
+

|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pay2go_client"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/examples/server.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
$: << File.expand_path('../lib')
|
3
|
+
require 'sinatra'
|
4
|
+
require 'pay2go'
|
5
|
+
|
6
|
+
client = Pay2go::Client.new({
|
7
|
+
merchant_id: '123456',
|
8
|
+
hash_key: '12345678901234567890123456789012',
|
9
|
+
hash_iv: '1234567890123456',
|
10
|
+
mode: :test
|
11
|
+
})
|
12
|
+
|
13
|
+
get '/mpg' do
|
14
|
+
@client_options = client.options
|
15
|
+
@params = client.generate_mpg_params({
|
16
|
+
MerchantOrderNo: SecureRandom.hex(4),
|
17
|
+
Amt: 200,
|
18
|
+
ItemDesc: '一般交易測試',
|
19
|
+
Email: 'hello@localhost.com',
|
20
|
+
EmailModify: 0,
|
21
|
+
LoginType: 0,
|
22
|
+
CREDIT: 1
|
23
|
+
})
|
24
|
+
|
25
|
+
erb :mpg
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/period' do
|
29
|
+
@client_options = client.options
|
30
|
+
@params = client.generate_credit_card_period_params({
|
31
|
+
MerchantOrderNo: SecureRandom.hex(4),
|
32
|
+
ProdDesc: '定期定額交易測試',
|
33
|
+
PeriodAmt: 100,
|
34
|
+
PeriodAmtMode: 'Total',
|
35
|
+
PeriodType: 'M',
|
36
|
+
PeriodPoint: '01',
|
37
|
+
PeriodStartType: 1,
|
38
|
+
PeriodTimes: '5',
|
39
|
+
})
|
40
|
+
|
41
|
+
erb :period
|
42
|
+
end
|
43
|
+
|
44
|
+
post '/validate' do
|
45
|
+
client.verify_check_code(request.POST).to_s
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>MPG API</title>
|
6
|
+
<link rel="stylesheet" type="text/css" href="<%= url("/style.css")%>">
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<form action="https://capi.pay2go.com/MPG/mpg_gateway" method="post">
|
10
|
+
<table>
|
11
|
+
<caption>MPG API</caption>
|
12
|
+
<% @client_options.each do |k, v| %>
|
13
|
+
<tr>
|
14
|
+
<th class="title"><%= k %></th>
|
15
|
+
<td><%= v %></td>
|
16
|
+
</tr>
|
17
|
+
<% end %>
|
18
|
+
<% @params.each do |k, v| %>
|
19
|
+
<tr>
|
20
|
+
<th class="title"><%= k %></th>
|
21
|
+
<td><input type="text" name="<%= k %>" value="<%= v %>"></td>
|
22
|
+
</tr>
|
23
|
+
<% end %>
|
24
|
+
<tr>
|
25
|
+
<td colspan="2"><input type="submit"></td>
|
26
|
+
</tr>
|
27
|
+
</table>
|
28
|
+
</form>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>信用卡-定期定額 API</title>
|
6
|
+
<link rel="stylesheet" type="text/css" href="<%= url("/style.css")%>">
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<form action="https://capi.pay2go.com/API/PeriodAPI" method="post">
|
10
|
+
<table>
|
11
|
+
<caption>信用卡-定期定額 API</caption>
|
12
|
+
<% @client_options.each do |k, v| %>
|
13
|
+
<tr>
|
14
|
+
<th class="title"><%= k %></th>
|
15
|
+
<td><%= v %></td>
|
16
|
+
</tr>
|
17
|
+
<% end %>
|
18
|
+
<% @params.each do |k, v| %>
|
19
|
+
<tr>
|
20
|
+
<th class="title"><%= k %></th>
|
21
|
+
<td><input type="text" name="<%= k %>" value="<%= v %>"></td>
|
22
|
+
</tr>
|
23
|
+
<% end %>
|
24
|
+
<tr>
|
25
|
+
<td colspan="2"><input type="submit"></td>
|
26
|
+
</tr>
|
27
|
+
</table>
|
28
|
+
</form>
|
29
|
+
</body>
|
30
|
+
</html>
|
data/lib/pay2go.rb
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'cgi'
|
3
|
+
require 'digest'
|
4
|
+
require 'pay2go/errors'
|
5
|
+
require 'pay2go/core_ext/hash'
|
6
|
+
|
7
|
+
module Pay2go
|
8
|
+
class Client
|
9
|
+
TRANSACTION_API_ENDPOINTS = {
|
10
|
+
test: 'https://capi.pay2go.com/API/QueryTradeInfo',
|
11
|
+
production: 'https://api.pay2go.com/API/QueryTradeInfo'
|
12
|
+
}.freeze
|
13
|
+
CREDITCARD_COLLECT_REFUND_API_ENDPOINTS = {
|
14
|
+
test: 'https://cweb.pay2go.com/API/CreditCard/Close',
|
15
|
+
production: 'https://web.pay2go.com/API/CreditCard/Close'
|
16
|
+
}.freeze
|
17
|
+
CREDITCARD_DEAUTHORIZE_API_ENDPOINTS = {
|
18
|
+
test: 'https://cweb.pay2go.com/API/CreditCard/Cancel',
|
19
|
+
production: 'https://web.pay2go.com/API/CreditCard/Cancel'
|
20
|
+
}.freeze
|
21
|
+
NEED_CHECK_VALUE_APIS = [
|
22
|
+
:query_trade_info # Transaction API
|
23
|
+
]
|
24
|
+
|
25
|
+
attr_reader :options
|
26
|
+
|
27
|
+
def initialize options = {}
|
28
|
+
@options = { mode: :production }.merge!(options)
|
29
|
+
|
30
|
+
case @options[:mode]
|
31
|
+
when :test, :production
|
32
|
+
option_required! :merchant_id, :hash_key, :hash_iv
|
33
|
+
else
|
34
|
+
raise InvalidMode, %Q{option :mode is either :test or :production}
|
35
|
+
end
|
36
|
+
|
37
|
+
@options.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def verify_check_code params = {}
|
41
|
+
stringified_keys = params.stringify_keys
|
42
|
+
check_code = stringified_keys.delete('CheckCode')
|
43
|
+
make_check_code(stringified_keys) == check_code
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_mpg_params params = {}
|
47
|
+
param_required! params, [:MerchantOrderNo, :Amt, :ItemDesc, :Email, :LoginType]
|
48
|
+
|
49
|
+
post_params = {
|
50
|
+
RespondType: 'String',
|
51
|
+
TimeStamp: Time.now.to_i,
|
52
|
+
Version: '1.2'
|
53
|
+
}.merge!(params)
|
54
|
+
|
55
|
+
generate_params(:mpg, post_params)
|
56
|
+
end
|
57
|
+
|
58
|
+
def query_trade_info params = {}
|
59
|
+
param_required! params, [:MerchantOrderNo, :Amt]
|
60
|
+
|
61
|
+
post_params = {
|
62
|
+
Version: '1.1',
|
63
|
+
RespondType: 'String',
|
64
|
+
TimeStamp: Time.now.to_i
|
65
|
+
}.merge!(params)
|
66
|
+
|
67
|
+
res = request :query_trade_info, post_params
|
68
|
+
Hash[res.body.split('&').map!{|i| URI::decode(i).split('=')}]
|
69
|
+
end
|
70
|
+
|
71
|
+
def credit_card_deauthorize params = {}
|
72
|
+
param_required! params, [:Amt, :IndexType]
|
73
|
+
|
74
|
+
raise MissingOption, %Q{One of the following param is required: MerchantOrderNo, TradeNo} if params[:MerchantOrderNo].nil? and params[:TradeNo].nil?
|
75
|
+
|
76
|
+
post_params = {
|
77
|
+
RespondType: 'String',
|
78
|
+
Version: '1.0',
|
79
|
+
TimeStamp: Time.now.to_i
|
80
|
+
}.merge!(params)
|
81
|
+
|
82
|
+
post_params.delete_if { |key, value| value.nil? }
|
83
|
+
|
84
|
+
res = request :credit_card_deauthorize, post_params
|
85
|
+
Hash[res.body.split('&').map!{|i| URI::decode(i.force_encoding('ASCII-8BIT').force_encoding('UTF-8')).split('=')}]
|
86
|
+
end
|
87
|
+
|
88
|
+
def credit_card_deauthorize_by_merchant_order_no params = {}
|
89
|
+
param_required! params, [:Amt, :MerchantOrderNo]
|
90
|
+
|
91
|
+
post_params = {
|
92
|
+
IndexType: 1
|
93
|
+
}.merge!(params)
|
94
|
+
|
95
|
+
credit_card_deauthorize post_params
|
96
|
+
end
|
97
|
+
|
98
|
+
def credit_card_deauthorize_by_trade_no params = {}
|
99
|
+
param_required! params, [:Amt, :TradeNo]
|
100
|
+
|
101
|
+
post_params = {
|
102
|
+
IndexType: 2
|
103
|
+
}.merge!(params)
|
104
|
+
|
105
|
+
credit_card_deauthorize post_params
|
106
|
+
end
|
107
|
+
|
108
|
+
def credit_card_collect_refund params = {}
|
109
|
+
param_required! params, [:Amt, :IndexType, :CloseType]
|
110
|
+
|
111
|
+
raise MissingOption, %Q{One of the following param is required: MerchantOrderNo, TradeNo} if params[:MerchantOrderNo].nil? and params[:TradeNo].nil?
|
112
|
+
|
113
|
+
post_params = {
|
114
|
+
RespondType: 'String',
|
115
|
+
Version: '1.0',
|
116
|
+
TimeStamp: Time.now.to_i
|
117
|
+
}.merge!(params)
|
118
|
+
|
119
|
+
res = request :credit_card_collect_refund, post_params
|
120
|
+
Hash[res.body.split('&').map!{|i| URI::decode(i.force_encoding('ASCII-8BIT').force_encoding('UTF-8')).split('=')}]
|
121
|
+
end
|
122
|
+
|
123
|
+
def credit_card_collect_refund_by_merchant_order_no params = {}
|
124
|
+
param_required! params, [:Amt, :MerchantOrderNo, :CloseType]
|
125
|
+
|
126
|
+
post_params = {
|
127
|
+
IndexType: 1
|
128
|
+
}.merge!(params)
|
129
|
+
|
130
|
+
credit_card_collect_refund post_params
|
131
|
+
end
|
132
|
+
|
133
|
+
def credit_card_collect_refund_by_trade_no params = {}
|
134
|
+
param_required! params, [:Amt, :TradeNo, :CloseType]
|
135
|
+
|
136
|
+
post_params = {
|
137
|
+
IndexType: 1
|
138
|
+
}.merge!(params)
|
139
|
+
|
140
|
+
credit_card_collect_refund post_params
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_credit_card_period_params params = {}
|
144
|
+
param_required! params, [:MerchantOrderNo, :ProdDesc, :PeriodAmt, :PeriodAmtMode, :PeriodType, :PeriodPoint, :PeriodStartType, :PeriodTimes]
|
145
|
+
|
146
|
+
generate_params(:credit_card_period, {
|
147
|
+
RespondType: 'String',
|
148
|
+
TimeStamp: Time.now.to_i,
|
149
|
+
Version: '1.0'
|
150
|
+
}.merge!(params))
|
151
|
+
end
|
152
|
+
|
153
|
+
def make_check_value type, params = {}
|
154
|
+
case type
|
155
|
+
when :mpg
|
156
|
+
check_value_fields = [:Amt, :MerchantID, :MerchantOrderNo, :TimeStamp, :Version]
|
157
|
+
padded = "HashKey=#{@options[:hash_key]}&%s&HashIV=#{@options[:hash_iv]}"
|
158
|
+
when :query_trade_info
|
159
|
+
check_value_fields = [:Amt, :MerchantID, :MerchantOrderNo]
|
160
|
+
padded = "IV=#{@options[:hash_iv]}&%s&Key=#{@options[:hash_key]}"
|
161
|
+
when :credit_card_period
|
162
|
+
check_value_fields = [:MerchantID, :MerchantOrderNo, :PeriodAmt, :PeriodType, :TimeStamp]
|
163
|
+
padded = "HashKey=#{@options[:hash_key]}&%s&HashIV=#{@options[:hash_iv]}"
|
164
|
+
else
|
165
|
+
raise UnsupportedType, "Unsupported API type."
|
166
|
+
end
|
167
|
+
|
168
|
+
param_required! params, check_value_fields
|
169
|
+
|
170
|
+
raw = params.select { |key, value| key.to_s.match(/^(#{check_value_fields.join('|')})$/) }
|
171
|
+
.sort_by{ |k, v| k.downcase }.map!{ |k, v| "#{k}=#{v}" }.join('&')
|
172
|
+
|
173
|
+
padded = padded % raw
|
174
|
+
|
175
|
+
Digest::SHA256.hexdigest(padded).upcase!
|
176
|
+
end
|
177
|
+
|
178
|
+
def encode_post_data data
|
179
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
180
|
+
cipher.encrypt
|
181
|
+
cipher.padding = 0
|
182
|
+
cipher.key = @options[:hash_key]
|
183
|
+
cipher.iv = @options[:hash_iv]
|
184
|
+
data = add_padding(data)
|
185
|
+
encrypted = cipher.update(data) + cipher.final
|
186
|
+
encrypted.unpack('H*').first
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def option_required! *option_names
|
192
|
+
option_names.each do |option_name|
|
193
|
+
raise MissingOption, %Q{option "#{option_name}" is required.} if @options[option_name].nil?
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def param_required! params, param_names
|
198
|
+
param_names.each do |param_name|
|
199
|
+
raise MissingParameter, %Q{param "#{param_name}" is required.} if params[param_name].nil?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def make_check_code params = {}
|
204
|
+
raw = params.select { |key, value| key.to_s.match(/^(Amt|MerchantID|MerchantOrderNo|TradeNo)$/) }
|
205
|
+
.sort_by{ |k, v| k.downcase }.map!{ |k, v| "#{k}=#{v}" }.join('&')
|
206
|
+
padded = "HashIV=#{@options[:hash_iv]}&#{raw}&HashKey=#{@options[:hash_key]}"
|
207
|
+
Digest::SHA256.hexdigest(padded).upcase!
|
208
|
+
end
|
209
|
+
|
210
|
+
def generate_params type, overwrite_params = {}
|
211
|
+
result = overwrite_params.clone
|
212
|
+
result[:MerchantID] = @options[:merchant_id]
|
213
|
+
result[:CheckValue] = make_check_value(type, result)
|
214
|
+
result
|
215
|
+
end
|
216
|
+
|
217
|
+
def request type, params = {}
|
218
|
+
case type
|
219
|
+
when :query_trade_info
|
220
|
+
api_url = TRANSACTION_API_ENDPOINTS[@options[:mode]]
|
221
|
+
when :credit_card_deauthorize
|
222
|
+
api_url = CREDITCARD_DEAUTHORIZE_API_ENDPOINTS[@options[:mode]]
|
223
|
+
when :credit_card_collect_refund
|
224
|
+
api_url = CREDITCARD_COLLECT_REFUND_API_ENDPOINTS[@options[:mode]]
|
225
|
+
end
|
226
|
+
|
227
|
+
if NEED_CHECK_VALUE_APIS.include?(type)
|
228
|
+
post_params = generate_params(type, params)
|
229
|
+
else
|
230
|
+
post_params = {
|
231
|
+
MerchantID_: @options[:merchant_id],
|
232
|
+
PostData_: encode_post_data(URI.encode(params.map{ |key, value| "#{key}=#{value}" }.join("&")))
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
Net::HTTP.post_form URI(api_url), post_params
|
237
|
+
end
|
238
|
+
|
239
|
+
def add_padding text, size = 32
|
240
|
+
len = text.length
|
241
|
+
pad = size - (len % size)
|
242
|
+
text = text + (pad.chr * pad)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'pay2go'
|
data/pay2go.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pay2go/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pay2go_client"
|
8
|
+
spec.version = Pay2go::VERSION
|
9
|
+
spec.authors = ["Calvert"]
|
10
|
+
spec.email = [""]
|
11
|
+
|
12
|
+
spec.summary = %q{API client for pay2go}
|
13
|
+
spec.description = %q{API client for pay2go}
|
14
|
+
spec.homepage = "https://github.com/CalvertYang/pay2go"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "bin"
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.8"
|
25
|
+
spec.add_development_dependency "minitest-reporters", "~> 1.1"
|
26
|
+
spec.add_development_dependency "sinatra"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pay2go_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Calvert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.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: '5.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-reporters
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sinatra
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: API client for pay2go
|
84
|
+
email:
|
85
|
+
- ''
|
86
|
+
executables:
|
87
|
+
- console
|
88
|
+
- setup
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bin/console
|
99
|
+
- bin/setup
|
100
|
+
- examples/public/style.css
|
101
|
+
- examples/server.rb
|
102
|
+
- examples/views/mpg.erb
|
103
|
+
- examples/views/period.erb
|
104
|
+
- lib/pay2go.rb
|
105
|
+
- lib/pay2go/client.rb
|
106
|
+
- lib/pay2go/core_ext/hash.rb
|
107
|
+
- lib/pay2go/errors.rb
|
108
|
+
- lib/pay2go/version.rb
|
109
|
+
- lib/pay2go_client.rb
|
110
|
+
- pay2go.gemspec
|
111
|
+
homepage: https://github.com/CalvertYang/pay2go
|
112
|
+
licenses:
|
113
|
+
- MIT
|
114
|
+
metadata: {}
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 2.5.1
|
132
|
+
signing_key:
|
133
|
+
specification_version: 4
|
134
|
+
summary: API client for pay2go
|
135
|
+
test_files: []
|