braintree 2.10.1 → 2.10.2
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.
- data/lib/braintree.rb +2 -0
- data/lib/braintree/error_codes.rb +2 -0
- data/lib/braintree/error_result.rb +6 -0
- data/lib/braintree/gateway.rb +4 -0
- data/lib/braintree/payer_authentication.rb +31 -0
- data/lib/braintree/payer_authentication_gateway.rb +25 -0
- data/lib/braintree/successful_result.rb +4 -1
- data/lib/braintree/test/credit_card_numbers.rb +12 -18
- data/lib/braintree/version.rb +1 -1
- data/spec/integration/braintree/credit_card_spec.rb +3 -3
- data/spec/integration/braintree/customer_search_spec.rb +1 -1
- data/spec/integration/braintree/transaction_search_spec.rb +3 -3
- data/spec/integration/braintree/transaction_spec.rb +102 -2
- data/spec/unit/braintree/error_result_spec.rb +13 -0
- data/spec/unit/braintree/payer_authentication_spec.rb +38 -0
- data/spec/unit/braintree/successful_result_spec.rb +6 -0
- metadata +8 -5
data/lib/braintree.rb
CHANGED
@@ -41,6 +41,8 @@ require File.dirname(__FILE__) + "/braintree/error_result"
|
|
41
41
|
require File.dirname(__FILE__) + "/braintree/errors"
|
42
42
|
require File.dirname(__FILE__) + "/braintree/gateway"
|
43
43
|
require File.dirname(__FILE__) + "/braintree/http"
|
44
|
+
require File.dirname(__FILE__) + "/braintree/payer_authentication"
|
45
|
+
require File.dirname(__FILE__) + "/braintree/payer_authentication_gateway"
|
44
46
|
require File.dirname(__FILE__) + "/braintree/resource_collection"
|
45
47
|
require File.dirname(__FILE__) + "/braintree/subscription"
|
46
48
|
require File.dirname(__FILE__) + "/braintree/subscription_gateway"
|
@@ -3,12 +3,14 @@ module Braintree
|
|
3
3
|
class ErrorResult
|
4
4
|
|
5
5
|
attr_reader :credit_card_verification, :transaction, :subscription, :errors, :params, :message
|
6
|
+
attr_reader :payer_authentication
|
6
7
|
|
7
8
|
def initialize(gateway, data) # :nodoc:
|
8
9
|
@gateway = gateway
|
9
10
|
@params = data[:params]
|
10
11
|
@credit_card_verification = CreditCardVerification._new(data[:verification]) if data[:verification]
|
11
12
|
@message = data[:message]
|
13
|
+
@payer_authentication = PayerAuthentication._new(gateway, data[:payer_authentication]) if data[:payer_authentication]
|
12
14
|
@transaction = Transaction._new(gateway, data[:transaction]) if data[:transaction]
|
13
15
|
@subscription = Subscription._new(gateway, data[:subscription]) if data[:subscription]
|
14
16
|
@errors = Errors.new(data[:errors])
|
@@ -24,6 +26,10 @@ module Braintree
|
|
24
26
|
"#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>#{verification_inspect}#{transaction_inspect}>"
|
25
27
|
end
|
26
28
|
|
29
|
+
def payer_authentication_required?
|
30
|
+
!!@payer_authentication
|
31
|
+
end
|
32
|
+
|
27
33
|
# Always returns false.
|
28
34
|
def success?
|
29
35
|
false
|
data/lib/braintree/gateway.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Braintree
|
2
|
+
class PayerAuthentication
|
3
|
+
include BaseModule # :nodoc:
|
4
|
+
|
5
|
+
attr_reader :id, :post_params, :post_url
|
6
|
+
|
7
|
+
def self.authenticate(payer_authentication_id, response_payload)
|
8
|
+
Configuration.gateway.payer_authentication.authenticate(
|
9
|
+
payer_authentication_id,
|
10
|
+
response_payload
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(gateway, attributes) # :nodoc:
|
15
|
+
@gateway = gateway
|
16
|
+
set_instance_variables_from_hash(attributes)
|
17
|
+
|
18
|
+
@post_params = (@post_params || []).map do |params|
|
19
|
+
OpenStruct.new(:name => params[:name], :value => params[:value])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
protected :new
|
25
|
+
end
|
26
|
+
|
27
|
+
def self._new(*args) # :nodoc:
|
28
|
+
self.new *args
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Braintree
|
2
|
+
class PayerAuthenticationGateway # :nodoc:
|
3
|
+
def initialize(gateway)
|
4
|
+
@gateway = gateway
|
5
|
+
@config = gateway.config
|
6
|
+
end
|
7
|
+
|
8
|
+
def authenticate(payer_authentication_id, response_payload)
|
9
|
+
response = @config.http.post(
|
10
|
+
"/payer_authentications/#{payer_authentication_id}/authenticate",
|
11
|
+
:payer_authentication => {
|
12
|
+
:response_payload => response_payload
|
13
|
+
}
|
14
|
+
)
|
15
|
+
|
16
|
+
if response[:transaction]
|
17
|
+
SuccessfulResult.new(:transaction => Transaction._new(@gateway, response[:transaction]))
|
18
|
+
elsif response[:api_error_response]
|
19
|
+
ErrorResult.new(@gateway, response[:api_error_response])
|
20
|
+
else
|
21
|
+
raise UnexpectedError, "expected :transaction or :api_error_response"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -6,20 +6,14 @@ module Braintree
|
|
6
6
|
#
|
7
7
|
# See http://www.braintreepayments.com/docs/ruby/reference/sandbox
|
8
8
|
module CreditCardNumbers
|
9
|
-
AmExes = %w[
|
10
|
-
378282246310005
|
11
|
-
371449635398431
|
12
|
-
378734493671000
|
13
|
-
]
|
9
|
+
AmExes = %w[378282246310005 371449635398431 378734493671000]
|
14
10
|
CarteBlanches = %w[30569309025904] # :nodoc:
|
15
11
|
DinersClubs = %w[38520000023237] # :nodoc:
|
16
12
|
|
17
|
-
Discovers = %w[
|
18
|
-
6011111111111117
|
19
|
-
6011000990139424
|
20
|
-
]
|
13
|
+
Discovers = %w[6011111111111117 6011000990139424]
|
21
14
|
JCBs = %w[3530111333300000 3566002020360505] # :nodoc:
|
22
15
|
|
16
|
+
Maestro = "6304000000000000" # :nodoc:
|
23
17
|
MasterCard = "5555555555554444"
|
24
18
|
MasterCardInternational = "5105105105105100" # :nodoc:
|
25
19
|
|
@@ -28,15 +22,15 @@ module Braintree
|
|
28
22
|
Visa = "4012888888881881"
|
29
23
|
VisaInternational = "4009348888881881" # :nodoc:
|
30
24
|
|
31
|
-
Visas = %w[
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
25
|
+
Visas = %w[4009348888881881 4012888888881881 4111111111111111 4000111111111115]
|
26
|
+
Unknowns = %w[1000000000000008]
|
27
|
+
|
28
|
+
module PayerAuthentication
|
29
|
+
ValidMaestro = "6304000000000000"
|
30
|
+
InvalidMaestro = "6773900000000000007"
|
31
|
+
AuthenticationSuccessfulPayload = "authentication_successful_payload"
|
32
|
+
AuthenticationFailedPayload = "authentication_failed_payload"
|
33
|
+
end
|
40
34
|
|
41
35
|
module FailsSandboxVerification
|
42
36
|
AmEx = "378734493671000"
|
data/lib/braintree/version.rb
CHANGED
@@ -40,7 +40,7 @@ describe Braintree::CreditCard do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "can specify the desired token" do
|
43
|
-
token = "token_#{rand(
|
43
|
+
token = "token_#{rand(10**10)}"
|
44
44
|
customer = Braintree::Customer.create!
|
45
45
|
result = Braintree::CreditCard.create(
|
46
46
|
:customer_id => customer.id,
|
@@ -673,8 +673,8 @@ describe Braintree::CreditCard do
|
|
673
673
|
|
674
674
|
describe "self.update_from_transparent_redirect" do
|
675
675
|
it "updates the credit card" do
|
676
|
-
old_token = "
|
677
|
-
new_token = "
|
676
|
+
old_token = "token_#{rand(10**10)}"
|
677
|
+
new_token = "token_#{rand(10**10)}"
|
678
678
|
customer = Braintree::Customer.create!(
|
679
679
|
:credit_card => {
|
680
680
|
:cardholder_name => "Old Cardholder Name",
|
@@ -11,7 +11,7 @@ describe Braintree::Transaction, "search" do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "can search on text fields" do
|
14
|
-
cctoken = "
|
14
|
+
cctoken = "cctoken_#{rand(10**10)}"
|
15
15
|
customer = Braintree::Customer.create!(
|
16
16
|
:first_name => "Timmy",
|
17
17
|
:last_name => "O'Toole",
|
@@ -11,9 +11,9 @@ describe Braintree::Transaction, "search" do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "can search on text fields" do
|
14
|
-
first_name = "
|
15
|
-
token = "
|
16
|
-
customer_id = "
|
14
|
+
first_name = "Tim_#{rand(10**10)}"
|
15
|
+
token = "creditcard_#{rand(10**10)}"
|
16
|
+
customer_id = "customer_#{rand(10**10)}"
|
17
17
|
|
18
18
|
transaction = Braintree::Transaction.sale!(
|
19
19
|
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
@@ -152,6 +152,106 @@ describe Braintree::Transaction do
|
|
152
152
|
codes.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted)
|
153
153
|
end
|
154
154
|
|
155
|
+
context "maestro authentication" do
|
156
|
+
it "returns an authentication response on successful lookup" do
|
157
|
+
result = Braintree::Transaction.create(
|
158
|
+
:type => "sale",
|
159
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
160
|
+
:merchant_account_id => "secure_code_ma",
|
161
|
+
:credit_card => {
|
162
|
+
:number => Braintree::Test::CreditCardNumbers::PayerAuthentication::ValidMaestro,
|
163
|
+
:expiration_date => "01/2012"
|
164
|
+
}
|
165
|
+
)
|
166
|
+
|
167
|
+
result.success?.should == false
|
168
|
+
result.payer_authentication_required?.should == true
|
169
|
+
|
170
|
+
payer_authentication = result.payer_authentication
|
171
|
+
payer_authentication.id.should match(/\A[a-z0-9]+\z/)
|
172
|
+
payer_authentication.post_url.should match(%r{\Ahttps?://})
|
173
|
+
payer_authentication.post_params.size.should == 1
|
174
|
+
payer_authentication.post_params.first.name.should == "PaReq"
|
175
|
+
payer_authentication.post_params.first.value.should_not be_empty
|
176
|
+
|
177
|
+
result = Braintree::PayerAuthentication.authenticate(
|
178
|
+
payer_authentication.id,
|
179
|
+
Braintree::Test::CreditCardNumbers::PayerAuthentication::AuthenticationSuccessfulPayload
|
180
|
+
)
|
181
|
+
|
182
|
+
result.success?.should == true
|
183
|
+
result.transaction.id.should =~ /^\w{6}$/
|
184
|
+
result.transaction.type.should == "sale"
|
185
|
+
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
|
186
|
+
result.transaction.processor_authorization_code.should_not be_nil
|
187
|
+
result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Maestro[0, 6]
|
188
|
+
result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Maestro[-4..-1]
|
189
|
+
result.transaction.credit_card_details.expiration_date.should == "01/2012"
|
190
|
+
result.transaction.credit_card_details.customer_location.should == "US"
|
191
|
+
end
|
192
|
+
|
193
|
+
it "attempts to create the transaction on an unsuccessful authentication" do
|
194
|
+
result = Braintree::Transaction.create(
|
195
|
+
:type => "sale",
|
196
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
197
|
+
:merchant_account_id => "secure_code_ma",
|
198
|
+
:credit_card => {
|
199
|
+
:number => Braintree::Test::CreditCardNumbers::PayerAuthentication::ValidMaestro,
|
200
|
+
:expiration_date => "01/2012"
|
201
|
+
}
|
202
|
+
)
|
203
|
+
|
204
|
+
result.success?.should == false
|
205
|
+
result.payer_authentication_required?.should == true
|
206
|
+
|
207
|
+
payer_authentication = result.payer_authentication
|
208
|
+
payer_authentication.id.should match(/\A[a-z0-9]+\z/)
|
209
|
+
payer_authentication.post_url.should match(%r{\Ahttps?://})
|
210
|
+
payer_authentication.post_params.size.should == 1
|
211
|
+
payer_authentication.post_params.first.name.should == "PaReq"
|
212
|
+
payer_authentication.post_params.first.value.should_not be_empty
|
213
|
+
|
214
|
+
result = Braintree::PayerAuthentication.authenticate(
|
215
|
+
payer_authentication.id,
|
216
|
+
Braintree::Test::CreditCardNumbers::PayerAuthentication::AuthenticationFailedPayload
|
217
|
+
)
|
218
|
+
|
219
|
+
result.success?.should == true
|
220
|
+
result.transaction.id.should =~ /^\w{6}$/
|
221
|
+
result.transaction.type.should == "sale"
|
222
|
+
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
|
223
|
+
result.transaction.processor_authorization_code.should_not be_nil
|
224
|
+
result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Maestro[0, 6]
|
225
|
+
result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Maestro[-4..-1]
|
226
|
+
result.transaction.credit_card_details.expiration_date.should == "01/2012"
|
227
|
+
result.transaction.credit_card_details.customer_location.should == "US"
|
228
|
+
end
|
229
|
+
|
230
|
+
it "runs a regular transaction on unsuccessful lookup" do
|
231
|
+
cc_number = Braintree::Test::CreditCardNumbers::PayerAuthentication::InvalidMaestro
|
232
|
+
result = Braintree::Transaction.create(
|
233
|
+
:type => "sale",
|
234
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
235
|
+
:merchant_account_id => "secure_code_ma",
|
236
|
+
:credit_card => {
|
237
|
+
:number => cc_number,
|
238
|
+
:expiration_date => "01/2012"
|
239
|
+
}
|
240
|
+
)
|
241
|
+
|
242
|
+
result.payer_authentication_required?.should == false
|
243
|
+
result.success?.should == true
|
244
|
+
result.transaction.id.should =~ /^\w{6}$/
|
245
|
+
result.transaction.type.should == "sale"
|
246
|
+
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
|
247
|
+
result.transaction.processor_authorization_code.should_not be_nil
|
248
|
+
result.transaction.credit_card_details.bin.should == cc_number[0, 6]
|
249
|
+
result.transaction.credit_card_details.last_4.should == cc_number[-4..-1]
|
250
|
+
result.transaction.credit_card_details.expiration_date.should == "01/2012"
|
251
|
+
result.transaction.credit_card_details.customer_location.should == "US"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
155
255
|
context "gateway rejection reason" do
|
156
256
|
it "exposes the cvv gateway rejection reason" do
|
157
257
|
old_merchant = Braintree::Configuration.merchant_id
|
@@ -1042,8 +1142,8 @@ describe Braintree::Transaction do
|
|
1042
1142
|
end
|
1043
1143
|
|
1044
1144
|
it "can specify the customer id and payment method token" do
|
1045
|
-
customer_id = "customer_#{rand(
|
1046
|
-
payment_mehtod_token = "credit_card_#{rand(
|
1145
|
+
customer_id = "customer_#{rand(10**10)}"
|
1146
|
+
payment_mehtod_token = "credit_card_#{rand(10**10)}"
|
1047
1147
|
result = Braintree::Transaction.sale(
|
1048
1148
|
:amount => "100",
|
1049
1149
|
:customer => {
|
@@ -74,4 +74,17 @@ describe Braintree::ErrorResult do
|
|
74
74
|
result.inspect.should_not include("transaction")
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
78
|
+
describe "payer_authentication_required?" do
|
79
|
+
it "is true if payer_authentication is in the response" do
|
80
|
+
result = Braintree::ErrorResult.new(
|
81
|
+
:gateway,
|
82
|
+
:payer_authentication => {:id => "public_id", :post_url => "post_url", :post_params => []},
|
83
|
+
:errors => {},
|
84
|
+
:verification => nil,
|
85
|
+
:transaction => nil
|
86
|
+
)
|
87
|
+
result.payer_authentication_required?.should be_true
|
88
|
+
end
|
89
|
+
end
|
77
90
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Braintree::PayerAuthentication do
|
4
|
+
describe "id" do
|
5
|
+
it "returns the given id" do
|
6
|
+
payer_authentication = Braintree::PayerAuthentication._new(
|
7
|
+
:gateway,
|
8
|
+
:id => :test_id
|
9
|
+
)
|
10
|
+
|
11
|
+
payer_authentication.id.should == :test_id
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "post_params" do
|
16
|
+
it "returns the given post params" do
|
17
|
+
payer_authentication = Braintree::PayerAuthentication._new(
|
18
|
+
:gateway,
|
19
|
+
:post_params => [{:name => 'imaname', :value => 'andimavalue'}]
|
20
|
+
)
|
21
|
+
|
22
|
+
post_param = payer_authentication.post_params.first
|
23
|
+
post_param.name.should == 'imaname'
|
24
|
+
post_param.value.should == 'andimavalue'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "post_url" do
|
29
|
+
it "returns the given post url" do
|
30
|
+
payer_authentication = Braintree::PayerAuthentication._new(
|
31
|
+
:gateway,
|
32
|
+
:post_url => "http://example.com"
|
33
|
+
)
|
34
|
+
|
35
|
+
payer_authentication.post_url.should == "http://example.com"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -24,4 +24,10 @@ describe Braintree::SuccessfulResult do
|
|
24
24
|
result.inspect.should == "#<Braintree::SuccessfulResult foo:\"foo_value\">"
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
describe "payer_authentication_required?" do
|
29
|
+
it "is always false" do
|
30
|
+
Braintree::SuccessfulResult.new.payer_authentication_required?.should be_false
|
31
|
+
end
|
32
|
+
end
|
27
33
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: braintree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 35
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 10
|
9
|
-
-
|
10
|
-
version: 2.10.
|
9
|
+
- 2
|
10
|
+
version: 2.10.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Braintree
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-02 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -68,6 +68,8 @@ files:
|
|
68
68
|
- lib/braintree/gateway.rb
|
69
69
|
- lib/braintree/http.rb
|
70
70
|
- lib/braintree/modification.rb
|
71
|
+
- lib/braintree/payer_authentication.rb
|
72
|
+
- lib/braintree/payer_authentication_gateway.rb
|
71
73
|
- lib/braintree/resource_collection.rb
|
72
74
|
- lib/braintree/subscription.rb
|
73
75
|
- lib/braintree/subscription_gateway.rb
|
@@ -121,6 +123,7 @@ files:
|
|
121
123
|
- spec/unit/braintree/error_result_spec.rb
|
122
124
|
- spec/unit/braintree/errors_spec.rb
|
123
125
|
- spec/unit/braintree/http_spec.rb
|
126
|
+
- spec/unit/braintree/payer_authentication_spec.rb
|
124
127
|
- spec/unit/braintree/resource_collection_spec.rb
|
125
128
|
- spec/unit/braintree/subscription_search_spec.rb
|
126
129
|
- spec/unit/braintree/subscription_spec.rb
|
@@ -172,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
175
|
requirements: []
|
173
176
|
|
174
177
|
rubyforge_project: braintree
|
175
|
-
rubygems_version: 1.
|
178
|
+
rubygems_version: 1.6.2
|
176
179
|
signing_key:
|
177
180
|
specification_version: 3
|
178
181
|
summary: Braintree Gateway Ruby Client Library
|