Skip to content

Commit

Permalink
2.10.2
Browse files Browse the repository at this point in the history
  • Loading branch information
braintreeps committed Aug 2, 2011
1 parent e2f9950 commit 86dad78
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 29 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rdoc
@@ -1,3 +1,7 @@
== 2.10.2

* Added support for international Maestro cards with payer authentication

== 2.10.1 == 2.10.1


* Support builder >= 2.0 * Support builder >= 2.0
Expand Down
2 changes: 2 additions & 0 deletions lib/braintree.rb
Expand Up @@ -41,6 +41,8 @@ module Braintree
require File.dirname(__FILE__) + "/braintree/errors" require File.dirname(__FILE__) + "/braintree/errors"
require File.dirname(__FILE__) + "/braintree/gateway" require File.dirname(__FILE__) + "/braintree/gateway"
require File.dirname(__FILE__) + "/braintree/http" require File.dirname(__FILE__) + "/braintree/http"
require File.dirname(__FILE__) + "/braintree/payer_authentication"
require File.dirname(__FILE__) + "/braintree/payer_authentication_gateway"
require File.dirname(__FILE__) + "/braintree/resource_collection" require File.dirname(__FILE__) + "/braintree/resource_collection"
require File.dirname(__FILE__) + "/braintree/subscription" require File.dirname(__FILE__) + "/braintree/subscription"
require File.dirname(__FILE__) + "/braintree/subscription_gateway" require File.dirname(__FILE__) + "/braintree/subscription_gateway"
Expand Down
2 changes: 2 additions & 0 deletions lib/braintree/error_codes.rb
Expand Up @@ -184,6 +184,8 @@ module Transaction
TaxAmountIsTooLarge = "81536" TaxAmountIsTooLarge = "81536"
TypeIsInvalid = "91523" TypeIsInvalid = "91523"
TypeIsRequired = "91524" TypeIsRequired = "91524"
UnsupportedVoiceAuthorization = "91539"

module Options module Options
VaultIsDisabled = "91525" VaultIsDisabled = "91525"
end end
Expand Down
6 changes: 6 additions & 0 deletions lib/braintree/error_result.rb
Expand Up @@ -3,12 +3,14 @@ module Braintree
class ErrorResult class ErrorResult


attr_reader :credit_card_verification, :transaction, :subscription, :errors, :params, :message attr_reader :credit_card_verification, :transaction, :subscription, :errors, :params, :message
attr_reader :payer_authentication


def initialize(gateway, data) # :nodoc: def initialize(gateway, data) # :nodoc:
@gateway = gateway @gateway = gateway
@params = data[:params] @params = data[:params]
@credit_card_verification = CreditCardVerification._new(data[:verification]) if data[:verification] @credit_card_verification = CreditCardVerification._new(data[:verification]) if data[:verification]
@message = data[:message] @message = data[:message]
@payer_authentication = PayerAuthentication._new(gateway, data[:payer_authentication]) if data[:payer_authentication]
@transaction = Transaction._new(gateway, data[:transaction]) if data[:transaction] @transaction = Transaction._new(gateway, data[:transaction]) if data[:transaction]
@subscription = Subscription._new(gateway, data[:subscription]) if data[:subscription] @subscription = Subscription._new(gateway, data[:subscription]) if data[:subscription]
@errors = Errors.new(data[:errors]) @errors = Errors.new(data[:errors])
Expand All @@ -24,6 +26,10 @@ def inspect # :nodoc:
"#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>#{verification_inspect}#{transaction_inspect}>" "#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>#{verification_inspect}#{transaction_inspect}>"
end end


def payer_authentication_required?
!!@payer_authentication
end

# Always returns false. # Always returns false.
def success? def success?
false false
Expand Down
4 changes: 4 additions & 0 deletions lib/braintree/gateway.rb
Expand Up @@ -24,6 +24,10 @@ def customer
CustomerGateway.new(self) CustomerGateway.new(self)
end end


def payer_authentication
PayerAuthenticationGateway.new(self)
end

def subscription def subscription
SubscriptionGateway.new(self) SubscriptionGateway.new(self)
end end
Expand Down
31 changes: 31 additions & 0 deletions lib/braintree/payer_authentication.rb
@@ -0,0 +1,31 @@
module Braintree
class PayerAuthentication
include BaseModule # :nodoc:

attr_reader :id, :post_params, :post_url

def self.authenticate(payer_authentication_id, response_payload)
Configuration.gateway.payer_authentication.authenticate(
payer_authentication_id,
response_payload
)
end

def initialize(gateway, attributes) # :nodoc:
@gateway = gateway
set_instance_variables_from_hash(attributes)

@post_params = (@post_params || []).map do |params|
OpenStruct.new(:name => params[:name], :value => params[:value])
end
end

class << self
protected :new
end

def self._new(*args) # :nodoc:
self.new *args
end
end
end
25 changes: 25 additions & 0 deletions lib/braintree/payer_authentication_gateway.rb
@@ -0,0 +1,25 @@
module Braintree
class PayerAuthenticationGateway # :nodoc:
def initialize(gateway)
@gateway = gateway
@config = gateway.config
end

def authenticate(payer_authentication_id, response_payload)
response = @config.http.post(
"/payer_authentications/#{payer_authentication_id}/authenticate",
:payer_authentication => {
:response_payload => response_payload
}
)

if response[:transaction]
SuccessfulResult.new(:transaction => Transaction._new(@gateway, response[:transaction]))
elsif response[:api_error_response]
ErrorResult.new(@gateway, response[:api_error_response])
else
raise UnexpectedError, "expected :transaction or :api_error_response"
end
end
end
end
5 changes: 4 additions & 1 deletion lib/braintree/successful_result.rb
Expand Up @@ -19,7 +19,10 @@ def inspect # :nodoc:
"#<#{self.class} #{inspected_attributes.join(" ")}>" "#<#{self.class} #{inspected_attributes.join(" ")}>"
end end


# Always returns true. def payer_authentication_required?
false
end

def success? def success?
true true
end end
Expand Down
30 changes: 12 additions & 18 deletions lib/braintree/test/credit_card_numbers.rb
Expand Up @@ -6,20 +6,14 @@ module Test # :nodoc:
# #
# See http://www.braintreepayments.com/docs/ruby/reference/sandbox # See http://www.braintreepayments.com/docs/ruby/reference/sandbox
module CreditCardNumbers module CreditCardNumbers
AmExes = %w[ AmExes = %w[378282246310005 371449635398431 378734493671000]
378282246310005
371449635398431
378734493671000
]
CarteBlanches = %w[30569309025904] # :nodoc: CarteBlanches = %w[30569309025904] # :nodoc:
DinersClubs = %w[38520000023237] # :nodoc: DinersClubs = %w[38520000023237] # :nodoc:


Discovers = %w[ Discovers = %w[6011111111111117 6011000990139424]
6011111111111117
6011000990139424
]
JCBs = %w[3530111333300000 3566002020360505] # :nodoc: JCBs = %w[3530111333300000 3566002020360505] # :nodoc:


Maestro = "6304000000000000" # :nodoc:
MasterCard = "5555555555554444" MasterCard = "5555555555554444"
MasterCardInternational = "5105105105105100" # :nodoc: MasterCardInternational = "5105105105105100" # :nodoc:


Expand All @@ -28,15 +22,15 @@ module CreditCardNumbers
Visa = "4012888888881881" Visa = "4012888888881881"
VisaInternational = "4009348888881881" # :nodoc: VisaInternational = "4009348888881881" # :nodoc:


Visas = %w[ Visas = %w[4009348888881881 4012888888881881 4111111111111111 4000111111111115]
4009348888881881 Unknowns = %w[1000000000000008]
4012888888881881
4111111111111111 module PayerAuthentication
4000111111111115 ValidMaestro = "6304000000000000"
] InvalidMaestro = "6773900000000000007"
Unknowns = %w[ AuthenticationSuccessfulPayload = "authentication_successful_payload"
1000000000000008 AuthenticationFailedPayload = "authentication_failed_payload"
] end


module FailsSandboxVerification module FailsSandboxVerification
AmEx = "378734493671000" AmEx = "378734493671000"
Expand Down
2 changes: 1 addition & 1 deletion lib/braintree/version.rb
Expand Up @@ -2,7 +2,7 @@ module Braintree
module Version module Version
Major = 2 Major = 2
Minor = 10 Minor = 10
Tiny = 1 Tiny = 2


String = "#{Major}.#{Minor}.#{Tiny}" String = "#{Major}.#{Minor}.#{Tiny}"
end end
Expand Down
6 changes: 3 additions & 3 deletions spec/integration/braintree/credit_card_spec.rb
Expand Up @@ -40,7 +40,7 @@
end end


it "can specify the desired token" do it "can specify the desired token" do
token = "token_#{rand(1_000_000)}" token = "token_#{rand(10**10)}"
customer = Braintree::Customer.create! customer = Braintree::Customer.create!
result = Braintree::CreditCard.create( result = Braintree::CreditCard.create(
:customer_id => customer.id, :customer_id => customer.id,
Expand Down Expand Up @@ -673,8 +673,8 @@


describe "self.update_from_transparent_redirect" do describe "self.update_from_transparent_redirect" do
it "updates the credit card" do it "updates the credit card" do
old_token = "token#{rand(1_000_000)}" old_token = "token_#{rand(10**10)}"
new_token = "token#{rand(1_000_000)}" new_token = "token_#{rand(10**10)}"
customer = Braintree::Customer.create!( customer = Braintree::Customer.create!(
:credit_card => { :credit_card => {
:cardholder_name => "Old Cardholder Name", :cardholder_name => "Old Cardholder Name",
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/braintree/customer_search_spec.rb
Expand Up @@ -11,7 +11,7 @@
end end


it "can search on text fields" do it "can search on text fields" do
cctoken = "cctoken#{rand(1_000_000)}" cctoken = "cctoken_#{rand(10**10)}"
customer = Braintree::Customer.create!( customer = Braintree::Customer.create!(
:first_name => "Timmy", :first_name => "Timmy",
:last_name => "O'Toole", :last_name => "O'Toole",
Expand Down
6 changes: 3 additions & 3 deletions spec/integration/braintree/transaction_search_spec.rb
Expand Up @@ -11,9 +11,9 @@
end end


it "can search on text fields" do it "can search on text fields" do
first_name = "Tim#{rand(10000)}" first_name = "Tim_#{rand(10**10)}"
token = "creditcard#{rand(10000)}" token = "creditcard_#{rand(10**10)}"
customer_id = "customer#{rand(10000)}" customer_id = "customer_#{rand(10**10)}"


transaction = Braintree::Transaction.sale!( transaction = Braintree::Transaction.sale!(
:amount => Braintree::Test::TransactionAmounts::Authorize, :amount => Braintree::Test::TransactionAmounts::Authorize,
Expand Down
104 changes: 102 additions & 2 deletions spec/integration/braintree/transaction_spec.rb
Expand Up @@ -152,6 +152,106 @@
codes.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted) codes.should include(Braintree::ErrorCodes::Address::CountryCodeNumericIsNotAccepted)
end end


context "maestro authentication" do
it "returns an authentication response on successful lookup" do
result = Braintree::Transaction.create(
:type => "sale",
:amount => Braintree::Test::TransactionAmounts::Authorize,
:merchant_account_id => "secure_code_ma",
:credit_card => {
:number => Braintree::Test::CreditCardNumbers::PayerAuthentication::ValidMaestro,
:expiration_date => "01/2012"
}
)

result.success?.should == false
result.payer_authentication_required?.should == true

payer_authentication = result.payer_authentication
payer_authentication.id.should match(/\A[a-z0-9]+\z/)
payer_authentication.post_url.should match(%r{\Ahttps?://})
payer_authentication.post_params.size.should == 1
payer_authentication.post_params.first.name.should == "PaReq"
payer_authentication.post_params.first.value.should_not be_empty

result = Braintree::PayerAuthentication.authenticate(
payer_authentication.id,
Braintree::Test::CreditCardNumbers::PayerAuthentication::AuthenticationSuccessfulPayload
)

result.success?.should == true
result.transaction.id.should =~ /^\w{6}$/
result.transaction.type.should == "sale"
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
result.transaction.processor_authorization_code.should_not be_nil
result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Maestro[0, 6]
result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Maestro[-4..-1]
result.transaction.credit_card_details.expiration_date.should == "01/2012"
result.transaction.credit_card_details.customer_location.should == "US"
end

it "attempts to create the transaction on an unsuccessful authentication" do
result = Braintree::Transaction.create(
:type => "sale",
:amount => Braintree::Test::TransactionAmounts::Authorize,
:merchant_account_id => "secure_code_ma",
:credit_card => {
:number => Braintree::Test::CreditCardNumbers::PayerAuthentication::ValidMaestro,
:expiration_date => "01/2012"
}
)

result.success?.should == false
result.payer_authentication_required?.should == true

payer_authentication = result.payer_authentication
payer_authentication.id.should match(/\A[a-z0-9]+\z/)
payer_authentication.post_url.should match(%r{\Ahttps?://})
payer_authentication.post_params.size.should == 1
payer_authentication.post_params.first.name.should == "PaReq"
payer_authentication.post_params.first.value.should_not be_empty

result = Braintree::PayerAuthentication.authenticate(
payer_authentication.id,
Braintree::Test::CreditCardNumbers::PayerAuthentication::AuthenticationFailedPayload
)

result.success?.should == true
result.transaction.id.should =~ /^\w{6}$/
result.transaction.type.should == "sale"
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
result.transaction.processor_authorization_code.should_not be_nil
result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Maestro[0, 6]
result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Maestro[-4..-1]
result.transaction.credit_card_details.expiration_date.should == "01/2012"
result.transaction.credit_card_details.customer_location.should == "US"
end

it "runs a regular transaction on unsuccessful lookup" do
cc_number = Braintree::Test::CreditCardNumbers::PayerAuthentication::InvalidMaestro
result = Braintree::Transaction.create(
:type => "sale",
:amount => Braintree::Test::TransactionAmounts::Authorize,
:merchant_account_id => "secure_code_ma",
:credit_card => {
:number => cc_number,
:expiration_date => "01/2012"
}
)

result.payer_authentication_required?.should == false
result.success?.should == true
result.transaction.id.should =~ /^\w{6}$/
result.transaction.type.should == "sale"
result.transaction.amount.should == BigDecimal.new(Braintree::Test::TransactionAmounts::Authorize)
result.transaction.processor_authorization_code.should_not be_nil
result.transaction.credit_card_details.bin.should == cc_number[0, 6]
result.transaction.credit_card_details.last_4.should == cc_number[-4..-1]
result.transaction.credit_card_details.expiration_date.should == "01/2012"
result.transaction.credit_card_details.customer_location.should == "US"
end
end

context "gateway rejection reason" do context "gateway rejection reason" do
it "exposes the cvv gateway rejection reason" do it "exposes the cvv gateway rejection reason" do
old_merchant = Braintree::Configuration.merchant_id old_merchant = Braintree::Configuration.merchant_id
Expand Down Expand Up @@ -1042,8 +1142,8 @@
end end


it "can specify the customer id and payment method token" do it "can specify the customer id and payment method token" do
customer_id = "customer_#{rand(1000000)}" customer_id = "customer_#{rand(10**10)}"
payment_mehtod_token = "credit_card_#{rand(1000000)}" payment_mehtod_token = "credit_card_#{rand(10**10)}"
result = Braintree::Transaction.sale( result = Braintree::Transaction.sale(
:amount => "100", :amount => "100",
:customer => { :customer => {
Expand Down
13 changes: 13 additions & 0 deletions spec/unit/braintree/error_result_spec.rb
Expand Up @@ -74,4 +74,17 @@
result.inspect.should_not include("transaction") result.inspect.should_not include("transaction")
end end
end end

describe "payer_authentication_required?" do
it "is true if payer_authentication is in the response" do
result = Braintree::ErrorResult.new(
:gateway,
:payer_authentication => {:id => "public_id", :post_url => "post_url", :post_params => []},
:errors => {},
:verification => nil,
:transaction => nil
)
result.payer_authentication_required?.should be_true
end
end
end end

0 comments on commit 86dad78

Please sign in to comment.