forked from spree/spree
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
5 changed files
with
292 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
vendor/extensions/payment_gateway/app/models/gateway/braintree.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
class Gateway::Braintree < Gateway | ||
preference :merchant_id, :string | ||
preference :public_key, :string | ||
preference :private_key, :string | ||
|
||
def provider_class | ||
ActiveMerchant::Billing::BraintreeGateway | ||
end | ||
|
||
def authorize(money, creditcard, options = {}) | ||
adjust_options_for_braintree(creditcard, options) | ||
payment_method = creditcard.gateway_customer_profile_id || creditcard | ||
provider.authorize(money, payment_method, options) | ||
end | ||
|
||
def capture(authorization, ignored_creditcard, ignored_options) | ||
amount = (authorization.amount * 100).to_i | ||
provider.capture(amount, authorization.response_code) | ||
end | ||
|
||
def create_profile(payment) | ||
if payment.source.gateway_customer_profile_id.nil? | ||
response = provider.store(payment.source) | ||
if response.success? | ||
payment.source.update_attributes!(:gateway_customer_profile_id => response.params["customer_vault_id"]) | ||
else | ||
payment.source.gateway_error response.message | ||
end | ||
end | ||
end | ||
|
||
def credit(*args) | ||
if args.size == 4 | ||
credit_with_payment_profiles(*args) | ||
elsif args.size == 3 | ||
credit_without_payment_profiles(*args) | ||
else | ||
raise ArgumentError, "Expected 3 or 4 arguments, received #{args.size}" | ||
end | ||
end | ||
|
||
def credit_with_payment_profiles(amount, payment, response_code, option) | ||
provider.credit(amount, payment) | ||
end | ||
|
||
def credit_without_payment_profiles(amount, response_code, options) | ||
transaction = ::Braintree::Transaction.find(response_code) | ||
if BigDecimal.new(amount.to_s) == (transaction.amount * 100) | ||
provider.refund(response_code) | ||
else | ||
raise NotImplementedError | ||
end | ||
end | ||
|
||
def payment_profiles_supported? | ||
true | ||
end | ||
|
||
def purchase(money, creditcard, options = {}) | ||
authorize(money, creditcard, options.merge(:submit_for_settlement => true)) | ||
end | ||
|
||
def void(response_code, ignored_creditcard, ignored_options) | ||
provider.void(response_code) | ||
end | ||
|
||
protected | ||
|
||
def adjust_country_name(options) | ||
[:billing_address, :shipping_address].each do |address| | ||
if options[address] && options[address][:country] == "US" | ||
options[address][:country] = "United States of America" | ||
end | ||
end | ||
end | ||
|
||
def adjust_billing_address(creditcard, options) | ||
if creditcard.gateway_customer_profile_id | ||
options.delete(:billing_address) | ||
end | ||
end | ||
|
||
def adjust_options_for_braintree(creditcard, options) | ||
adjust_country_name(options) | ||
adjust_billing_address(creditcard, options) | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
vendor/extensions/payment_gateway/test/unit/braintree_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
require File.dirname(__FILE__) + '/../test_helper' | ||
require "braintree" | ||
|
||
class BraintreeTest < Test::Unit::TestCase | ||
|
||
def setup | ||
Gateway.update_all(:active => false) | ||
@gateway = Gateway::Braintree.create!(:name => "Braintree Gateway", :environment => "test", :active => true) | ||
|
||
# TODO: really need to figure out how preferences work in Spree | ||
# doing configuration this way for now | ||
::Braintree::Configuration.environment = :sandbox | ||
::Braintree::Configuration.merchant_id = "zbn5yzq9t7wmwx42" | ||
::Braintree::Configuration.public_key = "ym9djwqpkxbv3xzt" | ||
::Braintree::Configuration.private_key = "4ghghkyp2yy6yqc8" | ||
::Braintree::Configuration.class_eval do | ||
def self.merchant_id=(value); end | ||
def self.public_key=(value); end | ||
def self.private_key=(value); end | ||
end | ||
|
||
with_payment_profiles_off do | ||
@country = Factory(:country, :name => "United States", :iso_name => "UNITED STATES", :iso3 => "USA", :iso => "US", :numcode => 840) | ||
@address = Factory(:address, | ||
:firstname => 'John', | ||
:lastname => 'Doe', | ||
:address1 => '1234 My Street', | ||
:address2 => 'Apt 1', | ||
:city => 'Washington DC', | ||
:zipcode => '20123', | ||
:phone => '(555)555-5555', | ||
:state_name => 'MD', | ||
:country => @country | ||
) | ||
@checkout = Factory(:checkout, :bill_address => @address, :ship_address => @address) | ||
@creditcard = Factory(:creditcard, :verification_value => '123', :number => '5105105105105100', :month => 9, :year => Time.now.year + 1, :first_name => 'John', :last_name => 'Doe') | ||
@payment = Factory(:payment, :source => @creditcard, :payable => @checkout, :amount => @checkout.order.total) | ||
end | ||
end | ||
|
||
context "provider_class" do | ||
should "be braintree gateway" do | ||
@gateway.provider_class.should == ::ActiveMerchant::Billing::BraintreeGateway | ||
end | ||
end | ||
|
||
context "authorize" do | ||
should "return a success response with an authorization code" do | ||
result = @gateway.authorize(500, @creditcard) | ||
assert_equal true, result.success? | ||
assert_match /\A\w{6}\z/, result.authorization | ||
assert_equal Braintree::Transaction::Status::Authorized, Braintree::Transaction.find(result.authorization).status | ||
end | ||
|
||
should "work through the spree payment interface" do | ||
Spree::Config.set :auto_capture => false | ||
assert_equal 0, @payment.txns.size | ||
@payment.process! | ||
assert_equal 1, @payment.txns.size | ||
assert_match /\A\w{6}\z/, @payment.txns[0].response_code | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::Authorized, transaction.status | ||
assert_equal "510510******5100", transaction.credit_card_details.masked_number | ||
assert_equal "09/#{Time.now.year + 1}", transaction.credit_card_details.expiration_date | ||
assert_equal "John", transaction.customer_details.first_name | ||
assert_equal "Doe", transaction.customer_details.last_name | ||
end | ||
end | ||
|
||
context "capture" do | ||
should "capture a previous authorization" do | ||
@payment.process! | ||
assert_equal 1, @payment.txns.size | ||
assert_match /\A\w{6}\z/, @payment.txns[0].response_code | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::Authorized, transaction.status | ||
capture_result = @gateway.capture(@payment.txns.first, :ignored_arg_creditcard, :ignored_arg_options) | ||
assert_equal true, capture_result.success? | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
end | ||
|
||
should "raise an error if capture fails using spree interface" do | ||
Spree::Config.set :auto_capture => false | ||
assert_equal 0, @payment.txns.size | ||
@payment.process! | ||
assert_equal 1, @payment.txns.size | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::Authorized, transaction.status | ||
@payment.source.capture(@payment) # as done in PaymentsController#fire | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
assert_raises(Spree::GatewayError, "Cannot submit for settlement unless status is authorized. (91507)") do | ||
@payment.source.capture(@payment) # as done in PaymentsController#fire | ||
end | ||
end | ||
|
||
should "work using the spree interface" do | ||
Spree::Config.set :auto_capture => false | ||
assert_equal 0, @payment.txns.size | ||
@payment.process! | ||
assert_equal 1, @payment.txns.size | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::Authorized, transaction.status | ||
@payment.source.capture(@payment) # as done in PaymentsController#fire | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
end | ||
end | ||
|
||
context "purchase" do | ||
should "return a success response with an authorization code" do | ||
result = @gateway.purchase(500, @creditcard) | ||
assert_equal true, result.success? | ||
assert_match /\A\w{6}\z/, result.authorization | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, Braintree::Transaction.find(result.authorization).status | ||
end | ||
|
||
should "work through the spree payment interface with payment profiles" do | ||
purchase_using_spree_interface | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_match /\A\w{4}\z/, transaction.credit_card_details.token | ||
end | ||
|
||
should "work through the spree payment interface without payment profiles" do | ||
with_payment_profiles_off do | ||
purchase_using_spree_interface | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal nil, transaction.credit_card_details.token | ||
end | ||
end | ||
end | ||
|
||
context "credit" do | ||
should "work through the spree interface" do | ||
purchase_using_spree_interface | ||
credit_using_spree_interface | ||
end | ||
end | ||
|
||
context "void" do | ||
should "work through the spree creditcard / payment interface" do | ||
assert_equal 0, @payment.txns.size | ||
@payment.process! | ||
assert_equal 1, @payment.txns.size | ||
assert_match /\A\w{6}\z/, @payment.txns[0].response_code | ||
transaction = Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
@creditcard.void(@payment) | ||
transaction = Braintree::Transaction.find(transaction.id) | ||
assert_equal Braintree::Transaction::Status::Voided, transaction.status | ||
end | ||
end | ||
|
||
def credit_using_spree_interface | ||
@payment.order.payments << @payment | ||
assert_equal 1, @payment.txns.size | ||
@payment.source.credit(@payment) # as done in PaymentsController#fire | ||
assert_equal 2, @payment.txns.size | ||
assert_match /\A\w{6}\z/, @payment.txns[1].response_code | ||
transaction = ::Braintree::Transaction.find(@payment.txns[1].response_code) | ||
assert_equal Braintree::Transaction::Type::Credit, transaction.type | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
assert_equal "510510******5100", transaction.credit_card_details.masked_number | ||
assert_equal "09/#{Time.now.year + 1}", transaction.credit_card_details.expiration_date | ||
assert_equal "John", transaction.customer_details.first_name | ||
assert_equal "Doe", transaction.customer_details.last_name | ||
end | ||
|
||
def purchase_using_spree_interface | ||
Spree::Config.set :auto_capture => true | ||
@payment.send(:create_payment_profile) | ||
assert_equal 0, @payment.txns.size | ||
@payment.process! # as done in PaymentsController#create | ||
assert_equal 1, @payment.txns.size | ||
assert_match /\A\w{6}\z/, @payment.txns[0].response_code | ||
transaction = ::Braintree::Transaction.find(@payment.txns[0].response_code) | ||
assert_equal Braintree::Transaction::Status::SubmittedForSettlement, transaction.status | ||
assert_equal "510510******5100", transaction.credit_card_details.masked_number | ||
assert_equal "09/#{Time.now.year + 1}", transaction.credit_card_details.expiration_date | ||
assert_equal "John", transaction.customer_details.first_name | ||
assert_equal "Doe", transaction.customer_details.last_name | ||
end | ||
|
||
def with_payment_profiles_off(&block) | ||
Gateway::Braintree.class_eval do | ||
def payment_profiles_supported? | ||
false | ||
end | ||
end | ||
yield | ||
ensure | ||
Gateway::Braintree.class_eval do | ||
def payment_profiles_supported? | ||
true | ||
end | ||
end | ||
end | ||
end | ||
|