ActiveMerchant-FatZebra 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "ActiveMerchant-FatZebra"
6
+ s.version = "1.0.0"
7
+ s.authors = ["Matthew Savage"]
8
+ s.email = ["matthew.savage@fatzebra.com.au"]
9
+ s.homepage = "https://www.fatzebra.com.au"
10
+ s.summary = %q{Fat Zebra support for Active Merchant, as a gem}
11
+ s.description = %q{Fat Zebra support for Active Merchant - temporary gem until support is combined into active_merchant core.}
12
+
13
+ s.rubyforge_project = "ActiveMerchant-FatZebra"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_runtime_dependency "activemerchant"
21
+ s.add_development_dependency "rake"
22
+ s.add_development_dependency('mocha', '~> 0.11.3')
23
+ s.add_development_dependency('rails', '>= 2.3.11')
24
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ActiveMerchant-FatZebra.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ FatZebra ActiveMerchant integration
2
+ ===================================
3
+
4
+ The quick 30-second rundown
5
+ ---------------------------
6
+
7
+ 1. Install the gem in your Gemfile
8
+
9
+ gem "active_merchant_fat_zebra"
10
+
11
+ Then `bundle install`
12
+
13
+ 2. Setup the gateway in your app:
14
+
15
+ ```ruby
16
+
17
+ options = {
18
+ :login => "test",
19
+ :token => "test_token"
20
+ }
21
+ gateway = ActiveMerchant::Billing::FatZebraGateway.new(options)
22
+
23
+ # If you are testing, uncomment the following line
24
+ # ActiveMerchant::Billing::Base.gateway_mode = :test
25
+ ```
26
+
27
+ 3. Setup the transaction data and then... transact!
28
+
29
+ ```ruby
30
+ cc = ActiveMerchant::Billing::CreditCard.new(:first_name => "Joe",
31
+ :last_name => "Smith",
32
+ :number => "4444333322221111",
33
+ :month => 12,
34
+ :year => 2013,
35
+ :verification_value => 123)
36
+
37
+ amount = 10000 # 100.00 in cents
38
+
39
+ result = gateway.purchase(amount, cc, { :order_id => "ORD18239", :ip => request.ip }) # If you are using rails you would use request.remote_ip
40
+ ```
41
+
42
+ 4. Handle the response - the data you get back is:
43
+
44
+ ```ruby
45
+ result.success? # True or False depending on if the txn was successful
46
+ result.message # e.g. "Approved" or "Declined"
47
+ result.id # The transaction ID
48
+ result.test? # Indicates if this was a test transaction
49
+ result.params # Parameters passed by the gateway (e.g. may be additional info like fraud review score.)
50
+ result.params["result"]["id"] # The transaction ID
51
+ result.params["result"]["token"] # The card token (when storing a card)
52
+ ```
53
+
54
+
55
+ Refunds
56
+ -------
57
+ ```ruby
58
+ # Refunding the amount of $100.00, for the original transaction ID of "AB12887Z"
59
+ response = gateway.refund(10000, "AB12887Z", "REFUND1")
60
+
61
+ response.success? # true or false
62
+ ```
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+
5
+ begin
6
+ require 'bundler'
7
+ Bundler.setup
8
+ rescue LoadError => e
9
+ puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
10
+ require 'rubygems'
11
+ end
12
+
13
+ require 'rake'
14
+ require 'rake/testtask'
15
+
16
+ desc "Run the unit test suite"
17
+ task :default => 'test:all'
18
+
19
+ namespace :test do
20
+
21
+ Rake::TestTask.new(:units) do |t|
22
+ t.pattern = 'test/unit/**/*_test.rb'
23
+ t.ruby_opts << '-rubygems'
24
+ t.libs << 'test'
25
+ t.verbose = true
26
+ end
27
+
28
+ Rake::TestTask.new(:remote) do |t|
29
+ t.pattern = 'test/remote/**/*_test.rb'
30
+ t.ruby_opts << '-rubygems'
31
+ t.libs << 'test'
32
+ t.verbose = true
33
+ end
34
+
35
+ desc "Test all"
36
+ task :all => [:units, :remote]
37
+ end
@@ -0,0 +1,2 @@
1
+ require 'active_merchant'
2
+ require "active_merchant/billing/gateways/fat_zebra"
@@ -0,0 +1,153 @@
1
+ require 'json'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class FatZebraGateway < Gateway
6
+ LIVE_URL = "https://gateway.fatzebra.com.au/v1.0"
7
+ SANDBOX_URL = "https://gateway.sandbox.fatzebra.com.au/v1.0"
8
+
9
+ self.supported_countries = ['AU']
10
+ self.default_currency = 'AUD'
11
+ self.money_format = :cents
12
+ self.supported_cardtypes = [:visa, :master, :american_express, :jcb]
13
+
14
+ self.homepage_url = 'https://www.fatzebra.com.au/'
15
+ self.display_name = 'Fat Zebra'
16
+
17
+ # Setup a new instance of the gateway.
18
+ #
19
+ # The options hash should include :username and :token
20
+ # You can find your username and token at https://dashboard.fatzebra.com.au
21
+ # Under the Your Account section
22
+ def initialize(options = {})
23
+ requires!(options, :username)
24
+ requires!(options, :token)
25
+ @username = options[:username]
26
+ @token = options[:token]
27
+ super
28
+ end
29
+
30
+ # To create a purchase on a credit card use:
31
+ #
32
+ # purchase(money, creditcard , { ... })
33
+ #
34
+ # To charge a tokenized card
35
+ #
36
+ # purchase(money, {:token => "abzy87u", :cvv => "123"}, { ... }})
37
+ def purchase(money, creditcard, options = {})
38
+ post = {}
39
+
40
+ add_amount(post, money, options)
41
+ add_creditcard(post, creditcard, options)
42
+ post[:reference] = options[:order_id]
43
+ post[:customer_ip] = options[:ip]
44
+
45
+ commit(:post, 'purchases', post)
46
+ end
47
+
48
+ # Refund a transaction
49
+ #
50
+ # amount - Integer - the amount to refund
51
+ # txn_id - String - the original transaction to be refunded
52
+ # reference - String - your transaction reference
53
+ def refund(money, txn_id, reference)
54
+ post = {}
55
+
56
+ post[:amount] = money
57
+ post[:transaction_id] = txn_id
58
+ post[:reference] = reference
59
+
60
+ commit(:post, "refunds", post)
61
+ end
62
+
63
+ # Tokenize a credit card
64
+ def store(creditcard)
65
+ post = {}
66
+ add_creditcard(post, creditcard)
67
+
68
+ commit(:post, "credit_cards", post)
69
+ end
70
+
71
+ private
72
+ # Add the money details to the request
73
+ def add_amount(post, money, options)
74
+ post[:amount] = money
75
+ end
76
+
77
+ # Add the credit card details to the request
78
+ def add_creditcard(post, creditcard, options = {})
79
+ if creditcard.respond_to?(:number)
80
+ post[:card_number] = creditcard.number
81
+ post[:card_expiry] = "#{creditcard.month}/#{creditcard.year}"
82
+ post[:cvv] = creditcard.verification_value if creditcard.verification_value?
83
+ post[:card_holder] = creditcard.name if creditcard.name
84
+ else
85
+ post[:card_token] = creditcard[:token]
86
+ post[:cvv] = creditcard[:cvv]
87
+ end
88
+ end
89
+
90
+ # Post the data to the gateway
91
+ def commit(method, uri, parameters=nil)
92
+ raw_response = response = nil
93
+ success = false
94
+ begin
95
+ raw_response = ssl_request(method, get_url(uri), parameters.to_json, headers)
96
+ response = parse(raw_response)
97
+ success = response["successful"] && (response["response"]["successful"] || response["response"]["token"])
98
+ rescue ResponseError => e
99
+ if e.response.code == "401"
100
+ return Response.new(false, "Invalid Login")
101
+ end
102
+
103
+ raw_response = e.response.body
104
+ response = parse(raw_response)
105
+ rescue JSON::ParserError
106
+ response = json_error(raw_response)
107
+ end
108
+
109
+ message = response["response"]["message"]
110
+ unless response["successful"]
111
+ # There is an error, so we will show that instead
112
+ message = response["errors"].empty? ? "Unknown Error" : response["errors"].join(", ")
113
+ end
114
+
115
+ Response.new(success,
116
+ message,
117
+ response,
118
+ :test => response.has_key?("test") ? response["test"] : false,
119
+ :authorization => response["response"]["authorization"],
120
+ :id => response["response"]["id"])
121
+ end
122
+
123
+ # Parse the returned JSON, if parse errors are raised then return a detailed error.
124
+ def parse(response)
125
+ begin
126
+ JSON.parse(response)
127
+ rescue JSON::ParserError
128
+ msg = 'Invalid JSON response received from Fat Zebra. Please contact support@fatzebra.com.au if you continue to receive this message.'
129
+ msg += " (The raw response returned by the API was #{response.inspect})"
130
+ {
131
+ "successful" => false,
132
+ "response" => {},
133
+ "errors" => [msg]
134
+ }
135
+ end
136
+ end
137
+
138
+ # Build the URL based on the AM mode and the URI
139
+ def get_url(uri)
140
+ base = test? ? SANDBOX_URL : LIVE_URL
141
+ base + "/" + uri
142
+ end
143
+
144
+ # Builds the auth and U-A headers for the request
145
+ def headers
146
+ {
147
+ "Authorization" => "Basic " + Base64.encode64(@username.to_s + ":" + @token.to_s).strip,
148
+ "User-Agent" => "Fat Zebra v1.0/ActiveMerchant #{ActiveMerchant::VERSION}"
149
+ }
150
+ end
151
+ end
152
+ end
153
+ end
data/test/comm_stub.rb ADDED
@@ -0,0 +1,39 @@
1
+ module CommStub
2
+ class Stub
3
+ def initialize(gateway, action)
4
+ @gateway = gateway
5
+ @action = action
6
+ @complete = false
7
+ end
8
+
9
+ def check_request(&block)
10
+ @check = block
11
+ self
12
+ end
13
+
14
+ def respond_with(*responses)
15
+ @complete = true
16
+ check = @check
17
+ (class << @gateway; self; end).send(:define_method, :ssl_post) do |*args|
18
+ check.call(*args) if check
19
+ (responses.size == 1 ? responses.last : responses.shift)
20
+ end
21
+ @action.call
22
+ end
23
+
24
+ def complete?
25
+ @complete
26
+ end
27
+ end
28
+
29
+ def stub_comms(gateway=@gateway, &action)
30
+ if @last_comm_stub
31
+ assert @last_comm_stub.complete?, "Tried to stub communications when there's a stub already in progress."
32
+ end
33
+ @last_comm_stub = Stub.new(gateway, action)
34
+ end
35
+
36
+ def teardown
37
+ assert(@last_comm_stub.complete?) if @last_comm_stub
38
+ end
39
+ end
data/test/fixtures.yml ADDED
@@ -0,0 +1,3 @@
1
+ fat_zebra:
2
+ username: TEST
3
+ token: TEST
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+
3
+ class RemoteFatZebraTest < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ @gateway = FatZebraGateway.new(fixtures(:fat_zebra))
8
+
9
+ @amount = 100
10
+ @credit_card = credit_card('5123456789012346')
11
+ @declined_card = credit_card('4557012345678902')
12
+
13
+ @options = {
14
+ :order_id => rand(100000).to_s,
15
+ :ip => "123.1.2.3"
16
+ }
17
+ end
18
+
19
+ def test_successful_purchase
20
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
21
+ assert_success response
22
+ assert_equal 'Approved', response.message
23
+ end
24
+
25
+ def test_unsuccessful_purchase
26
+ assert response = @gateway.purchase(@amount, @declined_card, @options)
27
+ assert_failure response
28
+ assert_equal 'Declined', response.message
29
+ end
30
+
31
+ def test_invalid_data
32
+ @options.delete(:ip)
33
+ assert response = @gateway.purchase(@amount, @declined_card, @options)
34
+ assert_failure response
35
+ assert_equal "Customer ip can't be blank", response.message
36
+ end
37
+
38
+ def test_refund
39
+ purchase = @gateway.purchase(@amount, @credit_card, @options)
40
+
41
+ assert response = @gateway.refund(@amount, purchase.params["response"]["id"], rand(1000000).to_s)
42
+ assert_success response
43
+ assert_match /Approved/, response.message
44
+ end
45
+
46
+ def test_invalid_refund
47
+ purchase = @gateway.purchase(@amount, @credit_card, @options)
48
+
49
+ assert response = @gateway.refund(@amount, nil, rand(1000000).to_s)
50
+ assert_failure response
51
+ assert_match /Original transaction is required/, response.message
52
+ end
53
+
54
+ def test_store
55
+ assert card = @gateway.store(@credit_card)
56
+
57
+ assert_success card
58
+ assert_false card.params["response"]["token"].nil?
59
+ end
60
+
61
+ def test_purchase_with_token
62
+ assert card = @gateway.store(@credit_card)
63
+ assert purchase = @gateway.purchase(@amount, {:cvv => 123, :token => card.params["response"]["token"]}, @options)
64
+ assert_success purchase
65
+ end
66
+
67
+ def test_invalid_login
68
+ gateway = FatZebraGateway.new(
69
+ :username => 'invalid',
70
+ :token => 'wrongtoken'
71
+ )
72
+ assert response = gateway.purchase(@amount, @credit_card, @options)
73
+ assert_failure response
74
+ assert_equal 'Invalid Login', response.message
75
+ end
76
+ end
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ begin
5
+ require 'rubygems'
6
+ require 'bundler'
7
+ Bundler.setup
8
+ rescue LoadError => e
9
+ puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
10
+ end
11
+
12
+ require 'test/unit'
13
+ require 'money'
14
+ require 'mocha'
15
+ require 'yaml'
16
+ require 'active_merchant'
17
+ require 'active_merchant/billing/gateways/fat_zebra'
18
+ require 'comm_stub'
19
+
20
+ require 'active_support/core_ext/integer/time'
21
+ require 'active_support/core_ext/numeric/time'
22
+
23
+
24
+
25
+ begin
26
+ require 'active_support/core_ext/time/acts_like'
27
+ rescue LoadError
28
+ end
29
+
30
+ begin
31
+ gem 'actionpack'
32
+ rescue LoadError
33
+ raise StandardError, "The view tests need ActionPack installed as gem to run"
34
+ end
35
+
36
+ require 'action_controller'
37
+ require "action_view/template"
38
+ begin
39
+ require 'active_support/core_ext/module/deprecation'
40
+ require 'action_dispatch/testing/test_process'
41
+ rescue LoadError
42
+ require 'action_controller/test_process'
43
+ end
44
+ require 'active_merchant/billing/integrations/action_view_helper'
45
+
46
+ ActiveMerchant::Billing::Base.mode = :test
47
+
48
+ if ENV['DEBUG_ACTIVE_MERCHANT'] == 'true'
49
+ require 'logger'
50
+ ActiveMerchant::Billing::Gateway.logger = Logger.new(STDOUT)
51
+ ActiveMerchant::Billing::Gateway.wiredump_device = STDOUT
52
+ end
53
+
54
+ # Test gateways
55
+ class SimpleTestGateway < ActiveMerchant::Billing::Gateway
56
+ end
57
+
58
+ class SubclassGateway < SimpleTestGateway
59
+ end
60
+
61
+
62
+ module ActiveMerchant
63
+ module Assertions
64
+ AssertionClass = RUBY_VERSION > '1.9' ? MiniTest::Assertion : Test::Unit::AssertionFailedError
65
+
66
+ def assert_field(field, value)
67
+ clean_backtrace do
68
+ assert_equal value, @helper.fields[field]
69
+ end
70
+ end
71
+
72
+ # Allows the testing of you to check for negative assertions:
73
+ #
74
+ # # Instead of
75
+ # assert !something_that_is_false
76
+ #
77
+ # # Do this
78
+ # assert_false something_that_should_be_false
79
+ #
80
+ # An optional +msg+ parameter is available to help you debug.
81
+ def assert_false(boolean, message = nil)
82
+ message = build_message message, '<?> is not false or nil.', boolean
83
+
84
+ clean_backtrace do
85
+ assert_block message do
86
+ not boolean
87
+ end
88
+ end
89
+ end
90
+
91
+ # A handy little assertion to check for a successful response:
92
+ #
93
+ # # Instead of
94
+ # assert_success response
95
+ #
96
+ # # DRY that up with
97
+ # assert_success response
98
+ #
99
+ # A message will automatically show the inspection of the response
100
+ # object if things go afoul.
101
+ def assert_success(response)
102
+ clean_backtrace do
103
+ assert response.success?, "Response failed: #{response.inspect}"
104
+ end
105
+ end
106
+
107
+ # The negative of +assert_success+
108
+ def assert_failure(response)
109
+ clean_backtrace do
110
+ assert_false response.success?, "Response expected to fail: #{response.inspect}"
111
+ end
112
+ end
113
+
114
+ def assert_valid(validateable)
115
+ clean_backtrace do
116
+ assert validateable.valid?, "Expected to be valid"
117
+ end
118
+ end
119
+
120
+ def assert_not_valid(validateable)
121
+ clean_backtrace do
122
+ assert_false validateable.valid?, "Expected to not be valid"
123
+ end
124
+ end
125
+
126
+ def assert_deprecation_warning(message, target)
127
+ target.expects(:deprecated).with(message)
128
+ yield
129
+ end
130
+
131
+ private
132
+ def clean_backtrace(&block)
133
+ yield
134
+ rescue AssertionClass => e
135
+ path = File.expand_path(__FILE__)
136
+ raise AssertionClass, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
137
+ end
138
+ end
139
+
140
+ module Fixtures
141
+ HOME_DIR = RUBY_PLATFORM =~ /mswin32/ ? ENV['HOMEPATH'] : ENV['HOME'] unless defined?(HOME_DIR)
142
+ LOCAL_CREDENTIALS = File.join(HOME_DIR.to_s, '.active_merchant/fixtures.yml') unless defined?(LOCAL_CREDENTIALS)
143
+ DEFAULT_CREDENTIALS = File.join(File.dirname(__FILE__), 'fixtures.yml') unless defined?(DEFAULT_CREDENTIALS)
144
+
145
+ private
146
+ def credit_card(number = '4242424242424242', options = {})
147
+ defaults = {
148
+ :number => number,
149
+ :month => 9,
150
+ :year => Time.now.year + 1,
151
+ :first_name => 'Longbob',
152
+ :last_name => 'Longsen',
153
+ :verification_value => '123',
154
+ :brand => 'visa'
155
+ }.update(options)
156
+
157
+ Billing::CreditCard.new(defaults)
158
+ end
159
+
160
+ def check(options = {})
161
+ defaults = {
162
+ :name => 'Jim Smith',
163
+ :routing_number => '244183602',
164
+ :account_number => '15378535',
165
+ :account_holder_type => 'personal',
166
+ :account_type => 'checking',
167
+ :number => '1'
168
+ }.update(options)
169
+
170
+ Billing::Check.new(defaults)
171
+ end
172
+
173
+ def address(options = {})
174
+ {
175
+ :name => 'Jim Smith',
176
+ :address1 => '1234 My Street',
177
+ :address2 => 'Apt 1',
178
+ :company => 'Widgets Inc',
179
+ :city => 'Ottawa',
180
+ :state => 'ON',
181
+ :zip => 'K1C2N6',
182
+ :country => 'CA',
183
+ :phone => '(555)555-5555',
184
+ :fax => '(555)555-6666'
185
+ }.update(options)
186
+ end
187
+
188
+ def all_fixtures
189
+ @@fixtures ||= load_fixtures
190
+ end
191
+
192
+ def fixtures(key)
193
+ data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
194
+
195
+ data.dup
196
+ end
197
+
198
+ def load_fixtures
199
+ [DEFAULT_CREDENTIALS, LOCAL_CREDENTIALS].inject({}) do |credentials, file_name|
200
+ if File.exists?(file_name)
201
+ yaml_data = YAML.load(File.read(file_name))
202
+ credentials.merge!(symbolize_keys(yaml_data))
203
+ end
204
+ credentials
205
+ end
206
+ end
207
+
208
+ def symbolize_keys(hash)
209
+ return unless hash.is_a?(Hash)
210
+
211
+ hash.symbolize_keys!
212
+ hash.each{|k,v| symbolize_keys(v)}
213
+ end
214
+ end
215
+ end
216
+
217
+ Test::Unit::TestCase.class_eval do
218
+ include ActiveMerchant::Billing
219
+ include ActiveMerchant::Assertions
220
+ include ActiveMerchant::Utils
221
+ include ActiveMerchant::Fixtures
222
+ end
223
+
224
+ module ActionViewHelperTestHelper
225
+
226
+ def self.included(base)
227
+ base.send(:include, ActiveMerchant::Billing::Integrations::ActionViewHelper)
228
+ base.send(:include, ActionView::Helpers::FormHelper)
229
+ base.send(:include, ActionView::Helpers::FormTagHelper)
230
+ base.send(:include, ActionView::Helpers::UrlHelper)
231
+ base.send(:include, ActionView::Helpers::TagHelper)
232
+ base.send(:include, ActionView::Helpers::CaptureHelper)
233
+ base.send(:include, ActionView::Helpers::TextHelper)
234
+ base.send(:attr_accessor, :output_buffer)
235
+ end
236
+
237
+ def setup
238
+ @controller = Class.new do
239
+ attr_reader :url_for_options
240
+ def url_for(options, *parameters_for_method_reference)
241
+ @url_for_options = options
242
+ end
243
+ end
244
+ @controller = @controller.new
245
+ @output_buffer = ''
246
+ end
247
+
248
+ protected
249
+ def protect_against_forgery?
250
+ false
251
+ end
252
+ end
@@ -0,0 +1,172 @@
1
+ require 'test_helper'
2
+
3
+ class FatZebraTest < Test::Unit::TestCase
4
+ def setup
5
+ @gateway = FatZebraGateway.new(
6
+ :username => 'TEST',
7
+ :token => 'TEST'
8
+ )
9
+
10
+ @credit_card = credit_card
11
+ @amount = 100
12
+
13
+ @options = {
14
+ :order_id => rand(10000),
15
+ :billing_address => address,
16
+ :description => 'Store Purchase'
17
+ }
18
+ end
19
+
20
+ def test_successful_purchase
21
+ @gateway.expects(:ssl_request).returns(successful_purchase_response)
22
+
23
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
24
+ assert_success response
25
+
26
+ # Replace with authorization number from the successful response
27
+ assert_equal '55355', response.authorization
28
+ assert response.test?
29
+ end
30
+
31
+ def test_unsuccessful_request
32
+ @gateway.expects(:ssl_request).returns(failed_purchase_response)
33
+
34
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
35
+ assert_failure response
36
+ assert response.test?
37
+ assert_match /Invalid Card Number/, response.message
38
+ end
39
+
40
+ def test_declined_purchase
41
+ @gateway.expects(:ssl_request).returns(declined_purchase_response)
42
+
43
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
44
+ assert_failure response
45
+ assert response.test?
46
+ assert_match /Card Declined/, response.message
47
+ end
48
+
49
+ def test_parse_error
50
+ @gateway.expects(:ssl_request).returns("{") # Some invalid JSON
51
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
52
+ assert_failure response
53
+ assert_match /Invalid JSON response/, response.message
54
+ end
55
+
56
+ def test_request_error
57
+ @gateway.expects(:ssl_request).returns(missing_data_response)
58
+
59
+ assert response = @gateway.purchase(@amount, @credit_card, @options)
60
+ assert_failure response
61
+ assert_match /Card Number is required/, response.message
62
+ end
63
+
64
+ def test_successful_tokenization
65
+ @gateway.expects(:ssl_request).returns(successful_tokenize_response)
66
+
67
+ assert response = @gateway.store(@credit_card)
68
+ assert_success response
69
+ end
70
+
71
+ def test_unsuccessful_tokenization
72
+ @gateway.expects(:ssl_request).returns(failed_tokenize_response)
73
+
74
+ assert response = @gateway.store(@credit_card)
75
+ assert_failure response
76
+ end
77
+
78
+ private
79
+
80
+ # Place raw successful response from gateway here
81
+ def successful_purchase_response
82
+ {
83
+ :successful => true,
84
+ :response => {
85
+ :authorization => "55355",
86
+ :id => "001-P-12345AA",
87
+ :card_number => "XXXXXXXXXXXX1111",
88
+ :card_holder => "John Smith",
89
+ :card_expiry => "10/2011",
90
+ :card_token => "a1bhj98j",
91
+ :amount => 349,
92
+ :successful => true,
93
+ :reference => "ABC123",
94
+ :message => "Approved",
95
+ },
96
+ :test => true,
97
+ :errors => []
98
+ }.to_json
99
+ end
100
+
101
+ def declined_purchase_response
102
+ {
103
+ :successful => true,
104
+ :response => {
105
+ :authorization_id => nil,
106
+ :id => nil,
107
+ :card_number => "XXXXXXXXXXXX1111",
108
+ :card_holder => "John Smith",
109
+ :card_expiry => "10/2011",
110
+ :amount => 100,
111
+ :authorized => false,
112
+ :reference => "ABC123",
113
+ :message => "Card Declined - check with issuer",
114
+ },
115
+ :test => true,
116
+ :errors => []
117
+ }.to_json
118
+ end
119
+
120
+ def successful_tokenize_response
121
+ {
122
+ :successful => true,
123
+ :response => {
124
+ :token => "e1q7dbj2",
125
+ :card_holder => "Bob Smith",
126
+ :card_number => "XXXXXXXXXXXX2346",
127
+ :card_expiry => "2013-05-31T23:59:59+10:00",
128
+ :authorized => true,
129
+ :transaction_count => 0
130
+ },
131
+ :errors => [],
132
+ :test => true
133
+ }.to_json
134
+ end
135
+
136
+ def failed_tokenize_response
137
+ {
138
+ :successful => false,
139
+ :response => {
140
+ :token => nil,
141
+ :card_holder => "Bob ",
142
+ :card_number => "512345XXXXXX2346",
143
+ :card_expiry => nil,
144
+ :authorized => false,
145
+ :transaction_count => 10
146
+ },
147
+ :errors => [
148
+ "Expiry date can't be blank"
149
+ ],
150
+ :test => false
151
+ }.to_json
152
+ end
153
+
154
+ # Place raw failed response from gateway here
155
+ def failed_purchase_response
156
+ {
157
+ :successful => false,
158
+ :response => {},
159
+ :test => true,
160
+ :errors => ["Invalid Card Number"]
161
+ }.to_json
162
+ end
163
+
164
+ def missing_data_response
165
+ {
166
+ :successful => false,
167
+ :response => {},
168
+ :test => true,
169
+ :errors => ["Card Number is required"]
170
+ }.to_json
171
+ end
172
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ActiveMerchant-FatZebra
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matthew Savage
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemerchant
16
+ requirement: &70121469611100 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70121469611100
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70121469610340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70121469610340
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ requirement: &70121469608900 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.11.3
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70121469608900
47
+ - !ruby/object:Gem::Dependency
48
+ name: rails
49
+ requirement: &70121469645180 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.11
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70121469645180
58
+ description: Fat Zebra support for Active Merchant - temporary gem until support is
59
+ combined into active_merchant core.
60
+ email:
61
+ - matthew.savage@fatzebra.com.au
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - ActiveMerchant-FatZebra.gemspec
68
+ - Gemfile
69
+ - README.md
70
+ - Rakefile
71
+ - lib/ActiveMerchant-FatZebra.rb
72
+ - lib/active_merchant/billing/gateways/fat_zebra.rb
73
+ - test/comm_stub.rb
74
+ - test/fixtures.yml
75
+ - test/remote/gateways/remote_fat_zebra_test.rb
76
+ - test/test_helper.rb
77
+ - test/unit/gateways/fat_zebra_test.rb
78
+ homepage: https://www.fatzebra.com.au
79
+ licenses: []
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 3400427441090863407
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ segments:
100
+ - 0
101
+ hash: 3400427441090863407
102
+ requirements: []
103
+ rubyforge_project: ActiveMerchant-FatZebra
104
+ rubygems_version: 1.8.10
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Fat Zebra support for Active Merchant, as a gem
108
+ test_files:
109
+ - test/comm_stub.rb
110
+ - test/fixtures.yml
111
+ - test/remote/gateways/remote_fat_zebra_test.rb
112
+ - test/test_helper.rb
113
+ - test/unit/gateways/fat_zebra_test.rb