Skip to content

Commit

Permalink
Add FeeFighters Samurai Gateway support
Browse files Browse the repository at this point in the history
  • Loading branch information
jkrall authored and Denis Odorcic committed Nov 11, 2011
1 parent 4f369d9 commit 66bd06e
Show file tree
Hide file tree
Showing 5 changed files with 376 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
source :rubygems

gemspec

group :test do
gem 'json-jruby', :platforms => :jruby
gem 'jruby-openssl', :platforms => :jruby

# gateway-specific dependencies, keeping these gems out of the gemspec
gem 'samurai', '>= 0.2.24'
end

group :remote_test do
gem 'mechanize'
gem 'launchy'
gem 'mongrel', '1.2.0.pre2', :platforms => :ruby

# gateway-specific dependencies, keeping these gems out of the gemspec
gem 'samurai', '>= 0.2.24'
end

119 changes: 119 additions & 0 deletions lib/active_merchant/billing/gateways/samurai.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class SamuraiGateway < Gateway

self.homepage_url = 'https://samurai.feefighters.com'
self.display_name = 'Samurai'
self.supported_countries = ['US']
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
self.default_currency = 'USD'
self.money_format = :cents

def initialize(options = {})
begin
require 'samurai'
rescue LoadError
raise "Could not load the samurai gem (>= 0.2.24). Use `gem install samurai` to install it."
end

requires!(options, :merchant_key, :merchant_password, :processor_token)
@sandbox = options[:sandbox] || false
Samurai.options = {
:merchant_key => options[:merchant_key],
:merchant_password => options[:merchant_password],
:processor_token => options[:processor_token]
}
end

def purchase(money, credit_card_or_vault_id, options = {})
if credit_card_or_vault_id.is_a?(ActiveMerchant::Billing::CreditCard)
store_result = store(credit_card_or_vault_id, options)
return store_result if !store_result.success?
credit_card_or_vault_id = store_result.params["payment_method_token"]
end
result = Samurai::Processor.purchase(credit_card_or_vault_id,
money,
{
:billing_reference => options[:billing_reference],
:customer_reference => options[:customer_reference],
:custom => options[:custom],
:descriptor => options[:descriptor],
})
handle_result(result)
end

def capture(money, authorization_id, options = {})
authorization = Samurai::Transaction.find(authorization_id) # get the authorization created previously
capture = money.nil? ? authorization.capture : authorization.capture(money)
handle_result(capture)
end

def credit(money, transaction_id, options = {})
transaction = Samurai::Transaction.find(transaction_id) # get the transaction
credit = money.nil? ? transaction.credit : transaction.credit(money)
handle_result(credit)
end

def authorize(money, credit_card_or_vault_id, options = {})
if credit_card_or_vault_id.is_a?(ActiveMerchant::Billing::CreditCard)
store_result = store(credit_card_or_vault_id, options)
return store_result if !store_result.success?
credit_card_or_vault_id = store_result.params["payment_method_token"]
end
authorize = Samurai::Processor.authorize(credit_card_or_vault_id, money, {:billing_reference => options[:billing_reference],:customer_reference => options[:customer_reference],:custom => options[:custom],:descriptor => options[:descriptor]})
handle_result(authorize)
end

def void(money, transaction_id, options = {})
void = Samurai::Processor.void(transaction_id, money, {:billing_reference => options[:billing_reference],:customer_reference => options[:customer_reference],:custom => options[:custom],:descriptor => options[:descriptor]})
handle_result(void)
end

def handle_result(result)
response_params, response_options, avs_result, cvv_result = {}, {}, {}, {}
if result.success?
response_options[:reference_id] = result.reference_id
response_options[:authorization] = result.reference_id
response_options[:transaction_token] = result.transaction_token
response_options[:payment_method_token] = result.payment_method.payment_method_token
end

# TODO: handle cvv here
response_options[:avs_result] = { :code => result.processor_response.avs_result_code }
message = message_from_result(result)
Response.new(result.success?, message, response_params, response_options)
end

def store(creditcard, options = {})
options[:billing_address] ||= {}

result = Samurai::PaymentMethod.create({
:card_number => creditcard.number,
:expiry_month => creditcard.month.to_s.rjust(2, "0"),
:expiry_year => creditcard.year.to_s,
:cvv => creditcard.verification_value,
:first_name => creditcard.first_name,
:last_name => creditcard.last_name,
:address_1 => options[:billing_address][:address1],
:address_2 => options[:billing_address][:address2],
:city => options[:billing_address][:city],
:zip => options[:billing_address][:zip],
:sandbox => @sandbox
})

Response.new(result.is_sensitive_data_valid,
message_from_result(result),
{ :payment_method_token => result.is_sensitive_data_valid && result.payment_method_token })
end

def message_from_result(result)
if result.success?
"OK"
else
result.errors.map {|_, messages| [messages].flatten.first }.first
end
end

end
end
end
6 changes: 6 additions & 0 deletions test/fixtures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ realex_mastercard_coms_error:
year: '2020'
verification_value: '123'

samurai:
merchant_key: 'a1ebafb6da5238fb8a3ac9f6'
merchant_password: 'ae1aa640f6b735c4730fbb56'
processor_token: '5a0e1ca1e5a11a2997bbf912'
sandbox: true

sage:
login: login
password: password
Expand Down
63 changes: 63 additions & 0 deletions test/remote/gateways/remote_samurai_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require 'test_helper'

class RemoteSamuraiTest < Test::Unit::TestCase


def setup
@gateway = SamuraiGateway.new(fixtures(:samurai))

@amount = 100
@declined_amount = 100.02
@invalid_card_amount = 100.07
@expired_card_amount = 100.08
@credit_card = credit_card('4111111111111111', :verification_value => '111')

@options = {
:address1 => "1000 1st Av",
:zip => "10101",
:billing_reference => "billing_reference",
:customer_reference => "customer_reference",
:custom => "custom",
:descriptor => "descriptor",
}
end

def test_successful_purchase
assert response = @gateway.purchase(@amount, @credit_card, @options)
assert_success response
assert_equal 'OK', response.message
end

def test_declined_purchase
assert response = @gateway.purchase(@declined_amount, @credit_card, @options)
assert_failure response
assert_equal 'The card was declined.', response.message
end

def test_invalid_purchase
assert response = @gateway.purchase(@invalid_card_amount, @credit_card, @options)
assert_failure response
assert_equal 'The card number was invalid.', response.message
end

def test_expired_purchase
assert response = @gateway.purchase(@expired_card_amount, @credit_card, @options)
assert_failure response
assert_equal 'The expiration date month was invalid, or prior to today.', response.message
end

def test_successful_auth_and_capture
assert authorize = @gateway.authorize(@amount, @credit_card, @options)
assert_success authorize
assert_equal 'OK', authorize.message
assert capture = @gateway.capture(@amount, authorize.authorization, @options)
assert_success capture
assert_equal 'OK', capture.message
end

def test_invalid_login
assert_raise(ArgumentError) do
SamuraiGateway.new( :login => '', :password => '' )
end
end
end
Loading

0 comments on commit 66bd06e

Please sign in to comment.