tns_payments 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +6 -0
- data/lib/tns_payments/connection.rb +19 -32
- data/lib/tns_payments/request.rb +33 -0
- data/lib/tns_payments/response.rb +15 -11
- data/lib/tns_payments/version.rb +1 -1
- data/lib/tns_payments.rb +3 -1
- data/test/unit/conntection_test.rb +38 -21
- data/test/unit/response_test.rb +25 -0
- metadata +5 -5
- data/lib/tns_payments/credit_card.rb +0 -8
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 0.0.5 / 2012-03-29
|
4
|
+
|
5
|
+
* Tokenize credit card.
|
6
|
+
* Request gets it's own class.
|
7
|
+
* Raise SessionTokenException when `session_token` request is invalid.
|
8
|
+
|
3
9
|
## 0.0.4 / 2012-03-08
|
4
10
|
|
5
11
|
* Check credit card token length as well as starting digit.
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require 'json'
|
3
|
-
require 'rest-client'
|
4
2
|
|
5
3
|
module TNSPayments
|
6
4
|
class Connection
|
7
5
|
CREDIT_CARD_TOKEN_FORMAT = /^9\d{15}/
|
8
6
|
|
9
7
|
attr_accessor :host
|
8
|
+
attr_reader :api_key, :merchant_id
|
10
9
|
attr_writer :session_token
|
11
10
|
|
12
11
|
def available?
|
@@ -28,12 +27,12 @@ module TNSPayments
|
|
28
27
|
transaction_id = transaction.transaction_id
|
29
28
|
params = {
|
30
29
|
'apiOperation' => 'PAY',
|
31
|
-
'
|
32
|
-
'
|
33
|
-
'transaction' => {'amount'
|
30
|
+
'cardDetails' => card_details(token),
|
31
|
+
'order' => {'reference' => transaction.reference},
|
32
|
+
'transaction' => {'amount' => transaction.amount.to_s, 'currency' => transaction.currency, 'reference' => transaction_id.to_s}
|
34
33
|
}
|
35
34
|
|
36
|
-
request :put, "/merchant/#{
|
35
|
+
request :put, "/merchant/#{merchant_id}/order/#{order_id}/transaction/#{transaction_id}", params
|
37
36
|
end
|
38
37
|
|
39
38
|
def refund transaction
|
@@ -44,52 +43,40 @@ module TNSPayments
|
|
44
43
|
'transaction' => {'amount' => transaction.amount.to_s, 'currency' => transaction.currency, 'reference' => transaction_id.to_s}
|
45
44
|
}
|
46
45
|
|
47
|
-
request :put, "/merchant/#{
|
46
|
+
request :put, "/merchant/#{merchant_id}/order/#{order_id}/transaction/#{transaction_id}", params
|
48
47
|
end
|
49
48
|
|
50
|
-
def create_credit_card_token
|
51
|
-
|
49
|
+
def create_credit_card_token token
|
50
|
+
params = {
|
51
|
+
'cardDetails' => card_details(token)
|
52
|
+
}
|
53
|
+
|
54
|
+
request :post, "/merchant/#{merchant_id}/token", params
|
52
55
|
end
|
53
56
|
|
54
57
|
def delete_credit_card_token token
|
55
|
-
request :delete, "/merchant/#{
|
58
|
+
request :delete, "/merchant/#{merchant_id}/token/#{token}"
|
56
59
|
end
|
57
60
|
|
58
61
|
def session_token
|
59
62
|
@session_token ||= begin
|
60
|
-
response = request :post, "/merchant/#{
|
61
|
-
response.
|
63
|
+
response = request :post, "/merchant/#{merchant_id}/session"
|
64
|
+
response.response.fetch('session') { raise(SessionTokenException.new, response.message) }
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
65
68
|
private
|
66
69
|
|
67
|
-
def
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def encode_credentials
|
72
|
-
credentials = ['', @api_key].join(':')
|
73
|
-
'Basic ' << Base64.encode64(credentials)
|
70
|
+
def card_details token
|
71
|
+
{token_key(token) => token}
|
74
72
|
end
|
75
73
|
|
76
|
-
def
|
74
|
+
def token_key token
|
77
75
|
token =~ CREDIT_CARD_TOKEN_FORMAT ? 'cardToken' : 'session'
|
78
76
|
end
|
79
77
|
|
80
78
|
def request method, path, options = {}
|
81
|
-
|
82
|
-
url = api_url << path
|
83
|
-
auth_headers = {:Authorization => encode_credentials}
|
84
|
-
headers = {:content_type => 'Application/json;charset=UTF-8', :accept => '*/*'}
|
85
|
-
headers.merge! auth_headers if authorization
|
86
|
-
|
87
|
-
args = [headers]
|
88
|
-
args.unshift(options.to_json) unless [:delete, :get, :head].include? method
|
89
|
-
|
90
|
-
Response.new JSON.parse(RestClient.send(method, url, *args))
|
91
|
-
rescue RestClient::Exception => e
|
92
|
-
Response.new 'result' => e.message.upcase, 'response' => e.response
|
79
|
+
Request.new(self, method, path, options).perform
|
93
80
|
end
|
94
81
|
end
|
95
82
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest-client'
|
3
|
+
|
4
|
+
module TNSPayments
|
5
|
+
class Request
|
6
|
+
attr_accessor :connection, :method, :path, :options
|
7
|
+
|
8
|
+
def initialize connection, method, path, options = {}
|
9
|
+
self.connection, self.method, self.path, self.options = connection, method, path, options
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform
|
13
|
+
authorization = options.fetch(:authorization) { true }
|
14
|
+
url = "#{connection.host}/api/rest/version/4#{path}"
|
15
|
+
auth_headers = {:Authorization => encode_credentials}
|
16
|
+
headers = {:content_type => 'Application/json;charset=UTF-8', :accept => '*/*'}
|
17
|
+
headers.merge! auth_headers if authorization
|
18
|
+
|
19
|
+
args = [headers]
|
20
|
+
args.unshift(options.to_json) unless [:delete, :get, :head].include? method
|
21
|
+
|
22
|
+
Response.new RestClient.send(method, url, *args)
|
23
|
+
rescue RestClient::Exception => e
|
24
|
+
Response.new({:result => e.message.upcase, :response => JSON.parse(e.response || '{}')}.to_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def encode_credentials
|
30
|
+
'Basic ' + Base64.encode64(":#{connection.api_key}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,22 +1,26 @@
|
|
1
1
|
module TNSPayments
|
2
2
|
class Response
|
3
|
-
|
3
|
+
attr_reader :raw_response
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
def_delegators :credit_card, :card_type
|
8
|
-
|
9
|
-
def initialize body
|
10
|
-
@response = body
|
11
|
-
@result = @response['result'] || @response['status']
|
5
|
+
def initialize response
|
6
|
+
@raw_response = response
|
12
7
|
end
|
13
8
|
|
14
|
-
def
|
15
|
-
@
|
9
|
+
def response
|
10
|
+
@response ||= JSON.parse(raw_response)
|
16
11
|
end
|
17
12
|
|
18
13
|
def success?
|
19
|
-
%w[SUCCESS OPERATING].include?
|
14
|
+
%w[SUCCESS OPERATING].include? response['result'] || response['status']
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
result = response['response'].fetch('result') { 'SUCCESS' }
|
19
|
+
if result == 'ERROR'
|
20
|
+
response['response']['error']['explanation']
|
21
|
+
else
|
22
|
+
'Successful request'
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
data/lib/tns_payments/version.rb
CHANGED
data/lib/tns_payments.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'tns_payments/connection'
|
2
|
-
require 'tns_payments/
|
2
|
+
require 'tns_payments/request'
|
3
3
|
require 'tns_payments/response'
|
4
4
|
require 'tns_payments/version'
|
5
5
|
|
6
6
|
module TNSPayments
|
7
|
+
class SessionTokenException < Exception; end
|
8
|
+
|
7
9
|
def self.new options = {}
|
8
10
|
Connection.new options
|
9
11
|
end
|
@@ -64,29 +64,29 @@ class TNSPayments::ConnectionTest < MiniTest::Unit::TestCase
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_create_credit_card_token_successfully_stores_creditcard
|
67
|
-
stub_successful_create_credit_card_token_request
|
68
|
-
assert @gateway.create_credit_card_token.success?
|
67
|
+
stub_successful_create_credit_card_token_request 'SESSIONTOKEN'
|
68
|
+
assert @gateway.create_credit_card_token('SESSIONTOKEN').success?
|
69
69
|
end
|
70
70
|
|
71
71
|
def test_create_credit_card_token_returns_valid_card_token_when_successful
|
72
|
-
stub_successful_create_credit_card_token_request
|
73
|
-
token = @gateway.create_credit_card_token.response['cardToken']
|
72
|
+
stub_successful_create_credit_card_token_request 'SESSIONTOKEN'
|
73
|
+
token = @gateway.create_credit_card_token('SESSIONTOKEN').response['cardToken']
|
74
74
|
assert_equal 16, token.size
|
75
75
|
assert_match Connection::CREDIT_CARD_TOKEN_FORMAT, token
|
76
76
|
end
|
77
77
|
|
78
78
|
def test_create_credit_card_token_unsuccessfully_attempts_to_store_credit_card
|
79
|
-
stub_unsuccessful_create_credit_card_token_request
|
80
|
-
refute @gateway.create_credit_card_token.success?
|
79
|
+
stub_unsuccessful_create_credit_card_token_request 'SESSIONTOKEN'
|
80
|
+
refute @gateway.create_credit_card_token('SESSIONTOKEN').success?
|
81
81
|
end
|
82
82
|
|
83
83
|
def test_delete_credit_card_token_successfully_deletes_a_stored_credit_card_token
|
84
|
-
stub_successful_delete_credit_card_token_request
|
84
|
+
stub_successful_delete_credit_card_token_request '9123456781234567'
|
85
85
|
assert @gateway.delete_credit_card_token('9123456781234567').success?
|
86
86
|
end
|
87
87
|
|
88
88
|
def test_delete_credit_card_token_unsuccessfully_attempts_to_delete_a_stored_credit_card
|
89
|
-
stub_unsuccessful_delete_credit_card_token_request
|
89
|
+
stub_unsuccessful_delete_credit_card_token_request '9123456781234567'
|
90
90
|
refute @gateway.delete_credit_card_token('9123456781234567').success?
|
91
91
|
end
|
92
92
|
|
@@ -95,6 +95,13 @@ class TNSPayments::ConnectionTest < MiniTest::Unit::TestCase
|
|
95
95
|
assert_equal 'SESSIONTOKEN', @gateway.session_token
|
96
96
|
end
|
97
97
|
|
98
|
+
def test_unsuccessful_session_token_request_raises_an_exception
|
99
|
+
stub_session_token_request.to_return(:status => 400, :body => '{}')
|
100
|
+
assert_raises SessionTokenException do
|
101
|
+
@gateway.session_token
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
98
105
|
private
|
99
106
|
|
100
107
|
def stub_availability_request
|
@@ -137,23 +144,23 @@ private
|
|
137
144
|
to_return(:status => 200, :body => '{"result":"FAILURE"}', :headers => {})
|
138
145
|
end
|
139
146
|
|
140
|
-
def stub_successful_create_credit_card_token_request
|
141
|
-
stub_create_credit_card_token_request.
|
147
|
+
def stub_successful_create_credit_card_token_request token
|
148
|
+
stub_create_credit_card_token_request(token).
|
142
149
|
to_return(:status => 200, :body => %{{"result":"SUCCESS", "response":{"gatewayCode":"BASIC_VERIFICATION_SUCCESSFUL"}, "card":{"number":"xxxxxxxxxxxxxxxx", "scheme":"MASTERCARD", "expiry":{"month":"5", "year":"13"}}, "cardToken":"9102370788509763"}}, :headers => {})
|
143
150
|
end
|
144
151
|
|
145
|
-
def stub_unsuccessful_create_credit_card_token_request
|
146
|
-
stub_create_credit_card_token_request.
|
152
|
+
def stub_unsuccessful_create_credit_card_token_request token
|
153
|
+
stub_create_credit_card_token_request(token).
|
147
154
|
to_return(:status => 200, :body => '{"result":"FAILURE"}', :headers => {})
|
148
155
|
end
|
149
156
|
|
150
|
-
def stub_successful_delete_credit_card_token_request
|
151
|
-
stub_delete_credit_card_token_request.
|
157
|
+
def stub_successful_delete_credit_card_token_request token
|
158
|
+
stub_delete_credit_card_token_request(token).
|
152
159
|
to_return(:status => 200, :body => '{"result":"SUCCESS"}', :headers => {})
|
153
160
|
end
|
154
161
|
|
155
|
-
def stub_unsuccessful_delete_credit_card_token_request
|
156
|
-
stub_delete_credit_card_token_request.
|
162
|
+
def stub_unsuccessful_delete_credit_card_token_request token
|
163
|
+
stub_delete_credit_card_token_request(token).
|
157
164
|
to_return(:status => 200, :body => '{"result":"FAILURE"}', :headers => {})
|
158
165
|
end
|
159
166
|
|
@@ -218,14 +225,24 @@ private
|
|
218
225
|
}
|
219
226
|
end
|
220
227
|
|
221
|
-
def stub_create_credit_card_token_request
|
228
|
+
def stub_create_credit_card_token_request token
|
222
229
|
stub_request(:post, /https:\/\/:#{@api_key}@secure\.ap\.tnspayments\.com\/api\/rest\/version\/4\/merchant\/#{@merchant_id}\/token/).
|
223
|
-
with
|
230
|
+
with :body => JSON.generate({
|
231
|
+
'cardDetails' => {'session' => token}
|
232
|
+
}),
|
233
|
+
:headers => {
|
234
|
+
'Accept' => '*/*',
|
235
|
+
'Content-Type' => 'Application/json;charset=UTF-8'
|
236
|
+
}
|
224
237
|
end
|
225
238
|
|
226
|
-
def stub_delete_credit_card_token_request
|
227
|
-
stub_request(:delete, /https:\/\/:#{@api_key}@secure\.ap\.tnspayments\.com\/api\/rest\/version\/4\/merchant\/#{@merchant_id}\/token
|
228
|
-
with
|
239
|
+
def stub_delete_credit_card_token_request token
|
240
|
+
stub_request(:delete, /https:\/\/:#{@api_key}@secure\.ap\.tnspayments\.com\/api\/rest\/version\/4\/merchant\/#{@merchant_id}\/token\/#{token}/).
|
241
|
+
with :body => {},
|
242
|
+
:headers => {
|
243
|
+
'Accept' => '*/*',
|
244
|
+
'Content-Type' => 'Application/json;charset=UTF-8'
|
245
|
+
}
|
229
246
|
end
|
230
247
|
|
231
248
|
def mock_transaction
|
data/test/unit/response_test.rb
CHANGED
@@ -1,4 +1,29 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TNSPayments::ResponseTest < MiniTest::Unit::TestCase
|
4
|
+
def test_success_when_operating
|
5
|
+
assert Response.new({:result => 'OPERATING'}.to_json).success?
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_success_when_success
|
9
|
+
assert Response.new({:result => 'SUCCESS'}.to_json).success?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_success_when_not_successful
|
13
|
+
refute Response.new({:result => '404 RESOURCE NOT FOUND'}.to_json).success?
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_message_when_error_request
|
17
|
+
response = "{\"result\":\"401 UNAUTHORIZED\",\"response\":{\"error\":{\"cause\":\"INVALID_REQUEST\",\"explanation\":\"Invalid credentials.\"},\"result\":\"ERROR\"}}"
|
18
|
+
assert_equal 'Invalid credentials.', Response.new(response).message
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_message_when_success_request
|
22
|
+
assert_equal 'Successful request', Response.new({:result => 'SUCCESS', :response => {}}.to_json).message
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_raw_response_is_the_json
|
26
|
+
response = "{\"result\":\"401 UNAUTHORIZED\",\"response\":{\"error\":{\"cause\":\"INVALID_REQUEST\",\"explanation\":\"Invalid credentials.\"},\"result\":\"ERROR\"}}"
|
27
|
+
assert_equal response, Response.new(response).raw_response
|
28
|
+
end
|
4
29
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tns_payments
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tim Cooper
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-03-
|
18
|
+
date: 2012-03-29 00:00:00 +10:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -104,7 +104,7 @@ files:
|
|
104
104
|
- Rakefile
|
105
105
|
- lib/tns_payments.rb
|
106
106
|
- lib/tns_payments/connection.rb
|
107
|
-
- lib/tns_payments/
|
107
|
+
- lib/tns_payments/request.rb
|
108
108
|
- lib/tns_payments/response.rb
|
109
109
|
- lib/tns_payments/version.rb
|
110
110
|
- test/helper.rb
|
@@ -1,8 +0,0 @@
|
|
1
|
-
module TNSPayments
|
2
|
-
class CreditCard
|
3
|
-
FORM_RESPONSE_MAPPING = {:gatewayCardExpiryDateYear => :year, :gatewayCardExpiryDateMonth => :month, :gatewayCardNumber => :number, :gatewayCardSecurityCode => :verification_value}.freeze
|
4
|
-
|
5
|
-
def initialize args = {}
|
6
|
-
end
|
7
|
-
end
|
8
|
-
end
|