activemerchant 1.24.0 → 1.25.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,6 +10,46 @@ raise "Need braintree gem 2.x.y. Run `gem install braintree --version '~>2.0'` t
10
10
 
11
11
  module ActiveMerchant #:nodoc:
12
12
  module Billing #:nodoc:
13
+ # For more information on the Braintree Gateway please visit their
14
+ # {Developer Portal}[https://www.braintreepayments.com/developers]
15
+ #
16
+ # ==== About this implementation
17
+ #
18
+ # This implementation leverages the Braintree-authored ruby gem:
19
+ # https://github.com/braintree/braintree_ruby
20
+ #
21
+ # ==== Debugging Information
22
+ #
23
+ # Setting an ActiveMerchant +wiredump_device+ will automatically
24
+ # configure the Braintree logger (via the Braintree gem's
25
+ # configuration) when the BraintreeBlueGateway is instantiated.
26
+ # Additionally, the log level will be set to +DEBUG+. Therefore,
27
+ # all you have to do is set the +wiredump_device+ and you'll
28
+ # get your debug output from your HTTP interactions with the
29
+ # remote gateway. (Don't enable this in production.)
30
+ #
31
+ # For example:
32
+ #
33
+ # ActiveMerchant::Billing::BraintreeBlueGateway.wiredump_device = Logger.new(STDOUT)
34
+ # # => #<Logger:0x107d385f8 ...>
35
+ #
36
+ # Braintree::Configuration.logger
37
+ # # => (some other logger, created by default by the gem)
38
+ #
39
+ # Braintree::Configuration.logger.level
40
+ # # => 1 (INFO)
41
+ #
42
+ # ActiveMerchant::Billing::BraintreeBlueGateway.new(:merchant_id => 'x', :public_key => 'x', :private_key => 'x')
43
+ #
44
+ # Braintree::Configuration.logger
45
+ # # => #<Logger:0x107d385f8 ...>
46
+ #
47
+ # Braintree::Configuration.logger.level
48
+ # # => 0 (DEBUG)
49
+ #
50
+ # Alternatively, you can avoid setting the +wiredump_device+
51
+ # and set +Braintree::Configuration.logger+ and/or
52
+ # +Braintree::Configuration.logger.level+ directly.
13
53
  class BraintreeBlueGateway < Gateway
14
54
  include BraintreeCommon
15
55
 
@@ -23,8 +63,11 @@ module ActiveMerchant #:nodoc:
23
63
  Braintree::Configuration.public_key = options[:public_key]
24
64
  Braintree::Configuration.private_key = options[:private_key]
25
65
  Braintree::Configuration.environment = (options[:environment] || (test? ? :sandbox : :production)).to_sym
26
- Braintree::Configuration.logger.level = Logger::ERROR if Braintree::Configuration.logger
27
66
  Braintree::Configuration.custom_user_agent = "ActiveMerchant #{ActiveMerchant::VERSION}"
67
+ if wiredump_device
68
+ Braintree::Configuration.logger = wiredump_device
69
+ Braintree::Configuration.logger.level = Logger::DEBUG
70
+ end
28
71
  super
29
72
  end
30
73
 
@@ -105,6 +148,7 @@ module ActiveMerchant #:nodoc:
105
148
  credit_card_params = merge_credit_card_options({
106
149
  :credit_card => {
107
150
  :number => creditcard.number,
151
+ :cvv => creditcard.verification_value,
108
152
  :expiration_month => creditcard.month.to_s.rjust(2, "0"),
109
153
  :expiration_year => creditcard.year.to_s
110
154
  }
@@ -17,6 +17,8 @@ module ActiveMerchant #:nodoc:
17
17
  class CyberSourceGateway < Gateway
18
18
  TEST_URL = 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor'
19
19
  LIVE_URL = 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor'
20
+
21
+ XSD_VERSION = "1.69"
20
22
 
21
23
  # visa, master, american_express, discover
22
24
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
@@ -104,10 +106,10 @@ module ActiveMerchant #:nodoc:
104
106
  # Request an authorization for an amount from CyberSource
105
107
  #
106
108
  # You must supply an :order_id in the options hash
107
- def authorize(money, creditcard, options = {})
108
- requires!(options, :order_id, :email)
109
+ def authorize(money, creditcard_or_reference, options = {})
110
+ requires!(options, :order_id)
109
111
  setup_address_hash(options)
110
- commit(build_auth_request(money, creditcard, options), options )
112
+ commit(build_auth_request(money, creditcard_or_reference, options), options )
111
113
  end
112
114
 
113
115
  def auth_reversal(money, identification, options = {})
@@ -122,10 +124,10 @@ module ActiveMerchant #:nodoc:
122
124
 
123
125
  # Purchase is an auth followed by a capture
124
126
  # You must supply an order_id in the options hash
125
- def purchase(money, creditcard, options = {})
126
- requires!(options, :order_id, :email)
127
+ def purchase(money, creditcard_or_reference, options = {})
128
+ requires!(options, :order_id)
127
129
  setup_address_hash(options)
128
- commit(build_purchase_request(money, creditcard, options), options)
130
+ commit(build_purchase_request(money, creditcard_or_reference, options), options)
129
131
  end
130
132
 
131
133
  def void(identification, options = {})
@@ -141,6 +143,33 @@ module ActiveMerchant #:nodoc:
141
143
  refund(money, identification, options)
142
144
  end
143
145
 
146
+ # Stores a customer subscription/profile with type "on-demand".
147
+ # To charge the card while creating a profile, pass options[:setup_fee] => money
148
+ def store(creditcard, options = {})
149
+ requires!(options, :order_id)
150
+ setup_address_hash(options)
151
+ commit(build_create_subscription_request(creditcard, options), options)
152
+ end
153
+
154
+ # Updates a customer subscription/profile
155
+ def update(reference, creditcard, options = {})
156
+ requires!(options, :order_id)
157
+ setup_address_hash(options)
158
+ commit(build_update_subscription_request(reference, creditcard, options), options)
159
+ end
160
+
161
+ # Removes a customer subscription/profile
162
+ def unstore(reference, options = {})
163
+ requires!(options, :order_id)
164
+ commit(build_delete_subscription_request(reference, options), options)
165
+ end
166
+
167
+ # Retrieves a customer subscription/profile
168
+ def retrieve(reference, options = {})
169
+ requires!(options, :order_id)
170
+ commit(build_retrieve_subscription_request(reference, options), options)
171
+ end
172
+
144
173
  # CyberSource requires that you provide line item information for tax calculations
145
174
  # If you do not have prices for each item or want to simplify the situation then pass in one fake line item that costs the subtotal of the order
146
175
  #
@@ -171,18 +200,17 @@ module ActiveMerchant #:nodoc:
171
200
  commit(build_tax_calculation_request(creditcard, options), options)
172
201
  end
173
202
 
174
- private
203
+ private
204
+
175
205
  # Create all address hash key value pairs so that we still function if we were only provided with one or two of them
176
206
  def setup_address_hash(options)
177
207
  options[:billing_address] = options[:billing_address] || options[:address] || {}
178
208
  options[:shipping_address] = options[:shipping_address] || {}
179
209
  end
180
210
 
181
- def build_auth_request(money, creditcard, options)
211
+ def build_auth_request(money, creditcard_or_reference, options)
182
212
  xml = Builder::XmlMarkup.new :indent => 2
183
- add_address(xml, creditcard, options[:billing_address], options)
184
- add_purchase_data(xml, money, true, options)
185
- add_creditcard(xml, creditcard)
213
+ add_creditcard_or_subscription(xml, money, creditcard_or_reference, options)
186
214
  add_auth_service(xml)
187
215
  add_business_rules_data(xml)
188
216
  xml.target!
@@ -210,11 +238,9 @@ module ActiveMerchant #:nodoc:
210
238
  xml.target!
211
239
  end
212
240
 
213
- def build_purchase_request(money, creditcard, options)
241
+ def build_purchase_request(money, creditcard_or_reference, options)
214
242
  xml = Builder::XmlMarkup.new :indent => 2
215
- add_address(xml, creditcard, options[:billing_address], options)
216
- add_purchase_data(xml, money, true, options)
217
- add_creditcard(xml, creditcard)
243
+ add_creditcard_or_subscription(xml, money, creditcard_or_reference, options)
218
244
  add_purchase_service(xml, options)
219
245
  add_business_rules_data(xml)
220
246
  xml.target!
@@ -249,6 +275,47 @@ module ActiveMerchant #:nodoc:
249
275
  xml.target!
250
276
  end
251
277
 
278
+ def build_create_subscription_request(creditcard, options)
279
+ options[:subscription] = (options[:subscription] || {}).merge(:frequency => "on-demand", :amount => 0, :automatic_renew => false)
280
+
281
+ xml = Builder::XmlMarkup.new :indent => 2
282
+ add_address(xml, creditcard, options[:billing_address], options)
283
+ add_purchase_data(xml, options[:setup_fee] || 0, true, options)
284
+ add_creditcard(xml, creditcard)
285
+ add_creditcard_payment_method(xml)
286
+ add_subscription(xml, options)
287
+ add_purchase_service(xml, options) if options[:setup_fee]
288
+ add_subscription_create_service(xml, options)
289
+ add_business_rules_data(xml)
290
+ xml.target!
291
+ end
292
+
293
+ def build_update_subscription_request(reference, creditcard, options)
294
+ xml = Builder::XmlMarkup.new :indent => 2
295
+ add_address(xml, creditcard, options[:billing_address], options) unless options[:billing_address].blank?
296
+ add_purchase_data(xml, options[:setup_fee], true, options) unless options[:setup_fee].blank?
297
+ add_creditcard(xml, creditcard) if creditcard
298
+ add_creditcard_payment_method(xml) if creditcard
299
+ add_subscription(xml, options, reference)
300
+ add_subscription_update_service(xml, options)
301
+ add_business_rules_data(xml)
302
+ xml.target!
303
+ end
304
+
305
+ def build_delete_subscription_request(reference, options)
306
+ xml = Builder::XmlMarkup.new :indent => 2
307
+ add_subscription(xml, options, reference)
308
+ add_subscription_delete_service(xml, options)
309
+ xml.target!
310
+ end
311
+
312
+ def build_retrieve_subscription_request(reference, options)
313
+ xml = Builder::XmlMarkup.new :indent => 2
314
+ add_subscription(xml, options, reference)
315
+ add_subscription_retrieve_service(xml, options)
316
+ xml.target!
317
+ end
318
+
252
319
  def add_business_rules_data(xml)
253
320
  xml.tag! 'businessRules' do
254
321
  xml.tag!('ignoreAVSResult', 'true') if @options[:ignore_avs]
@@ -272,8 +339,8 @@ module ActiveMerchant #:nodoc:
272
339
  xml.tag! 'merchantID', @options[:login]
273
340
  xml.tag! 'merchantReferenceCode', options[:order_id]
274
341
  xml.tag! 'clientLibrary' ,'Ruby Active Merchant'
275
- xml.tag! 'clientLibraryVersion', '1.0'
276
- xml.tag! 'clientEnvironment' , 'Linux'
342
+ xml.tag! 'clientLibraryVersion', VERSION
343
+ xml.tag! 'clientEnvironment' , RUBY_PLATFORM
277
344
  end
278
345
 
279
346
  def add_purchase_data(xml, money = 0, include_grand_total = false, options={})
@@ -283,17 +350,24 @@ module ActiveMerchant #:nodoc:
283
350
  end
284
351
  end
285
352
 
286
- def add_address(xml, creditcard, address, options, shipTo = false)
353
+ def add_address(xml, creditcard, address, options, shipTo = false)
354
+ requires!(options, :email)
355
+
287
356
  xml.tag! shipTo ? 'shipTo' : 'billTo' do
288
- xml.tag! 'firstName', creditcard.first_name
289
- xml.tag! 'lastName', creditcard.last_name
290
- xml.tag! 'street1', address[:address1]
291
- xml.tag! 'street2', address[:address2]
292
- xml.tag! 'city', address[:city]
293
- xml.tag! 'state', address[:state]
294
- xml.tag! 'postalCode', address[:zip]
295
- xml.tag! 'country', address[:country]
296
- xml.tag! 'email', options[:email]
357
+ xml.tag! 'firstName', creditcard.first_name if creditcard
358
+ xml.tag! 'lastName', creditcard.last_name if creditcard
359
+ xml.tag! 'street1', address[:address1]
360
+ xml.tag! 'street2', address[:address2] unless address[:address2].blank?
361
+ xml.tag! 'city', address[:city]
362
+ xml.tag! 'state', address[:state]
363
+ xml.tag! 'postalCode', address[:zip]
364
+ xml.tag! 'country', address[:country]
365
+ xml.tag! 'company', address[:company] unless address[:company].blank?
366
+ xml.tag! 'companyTaxID', address[:companyTaxID] unless address[:company_tax_id].blank?
367
+ xml.tag! 'phoneNumber', address[:phone_number] unless address[:phone_number].blank?
368
+ xml.tag! 'email', options[:email]
369
+ xml.tag! 'driversLicenseNumber', options[:drivers_license_number] unless options[:drivers_license_number].blank?
370
+ xml.tag! 'driversLicenseState', options[:drivers_license_state] unless options[:drivers_license_state].blank?
297
371
  end
298
372
  end
299
373
 
@@ -329,7 +403,7 @@ module ActiveMerchant #:nodoc:
329
403
  xml.tag! 'ccAuthService', {'run' => 'true'}
330
404
  xml.tag! 'ccCaptureService', {'run' => 'true'}
331
405
  end
332
-
406
+
333
407
  def add_void_service(xml, request_id, request_token)
334
408
  xml.tag! 'voidService', {'run' => 'true'} do
335
409
  xml.tag! 'voidRequestID', request_id
@@ -351,6 +425,60 @@ module ActiveMerchant #:nodoc:
351
425
  end
352
426
  end
353
427
 
428
+ def add_subscription_create_service(xml, options)
429
+ xml.tag! 'paySubscriptionCreateService', {'run' => 'true'}
430
+ end
431
+
432
+ def add_subscription_update_service(xml, options)
433
+ xml.tag! 'paySubscriptionUpdateService', {'run' => 'true'}
434
+ end
435
+
436
+ def add_subscription_delete_service(xml, options)
437
+ xml.tag! 'paySubscriptionDeleteService', {'run' => 'true'}
438
+ end
439
+
440
+ def add_subscription_retrieve_service(xml, options)
441
+ xml.tag! 'paySubscriptionRetrieveService', {'run' => 'true'}
442
+ end
443
+
444
+ def add_subscription(xml, options, reference = nil)
445
+ options[:subscription] ||= {}
446
+
447
+ xml.tag! 'recurringSubscriptionInfo' do
448
+ if reference
449
+ reference_code, subscription_id, request_token = reference.split(";")
450
+ xml.tag! 'subscriptionID', subscription_id
451
+ end
452
+
453
+ xml.tag! 'status', options[:subscription][:status] if options[:subscription][:status]
454
+ xml.tag! 'amount', options[:subscription][:amount] if options[:subscription][:amount]
455
+ xml.tag! 'numberOfPayments', options[:subscription][:occurrences] if options[:subscription][:occurrences]
456
+ xml.tag! 'automaticRenew', options[:subscription][:automatic_renew] if options[:subscription][:automatic_renew]
457
+ xml.tag! 'frequency', options[:subscription][:frequency] if options[:subscription][:frequency]
458
+ xml.tag! 'startDate', options[:subscription][:start_date].strftime("%Y%m%d") if options[:subscription][:start_date]
459
+ xml.tag! 'endDate', options[:subscription][:end_date].strftime("%Y%m%d") if options[:subscription][:end_date]
460
+ xml.tag! 'approvalRequired', options[:subscription][:approval_required] || false
461
+ xml.tag! 'event', options[:subscription][:event] if options[:subscription][:event]
462
+ xml.tag! 'billPayment', options[:subscription][:bill_payment] if options[:subscription][:bill_payment]
463
+ end
464
+ end
465
+
466
+ def add_creditcard_payment_method(xml)
467
+ xml.tag! 'subscription' do
468
+ xml.tag! 'paymentMethod', "credit card"
469
+ end
470
+ end
471
+
472
+ def add_creditcard_or_subscription(xml, money, creditcard_or_reference, options)
473
+ if creditcard_or_reference.is_a?(String)
474
+ add_purchase_data(xml, money, true, options)
475
+ add_subscription(xml, options, creditcard_or_reference)
476
+ else
477
+ add_address(xml, creditcard_or_reference, options[:billing_address], options)
478
+ add_purchase_data(xml, money, true, options)
479
+ add_creditcard(xml, creditcard_or_reference)
480
+ end
481
+ end
354
482
 
355
483
  # Where we actually build the full SOAP request using builder
356
484
  def build_request(body, options)
@@ -366,7 +494,7 @@ module ActiveMerchant #:nodoc:
366
494
  end
367
495
  end
368
496
  xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do
369
- xml.tag! 'requestMessage', {'xmlns' => 'urn:schemas-cybersource-com:transaction-data-1.32'} do
497
+ xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{XSD_VERSION}"} do
370
498
  add_merchant_data(xml, options)
371
499
  xml << body
372
500
  end
@@ -11,14 +11,18 @@ module ActiveMerchant #:nodoc:
11
11
  #
12
12
  # tendollar = 1000
13
13
  #
14
- # Next, create a credit card object using a TC approved test card.
14
+ # The transaction result is based on the cent value of the transaction. $10.15 will return a failed transaction
15
+ # with a response code of "15 – No Issuer", while $10.00 will return "00 – Transaction Approved."
16
+ #
17
+ # Next, create a credit card object using a eWay approved test card number (4444333322221111).
15
18
  #
16
19
  # creditcard = ActiveMerchant::Billing::CreditCard.new(
17
- # :number => '4111111111111111',
20
+ # :number => '4444333322221111',
18
21
  # :month => 8,
19
22
  # :year => 2006,
20
23
  # :first_name => 'Longbob',
21
- # :last_name => 'Longsen'
24
+ # :last_name => 'Longsen',
25
+ # :verification_value => '123'
22
26
  # )
23
27
  # options = {
24
28
  # :order_id => '1230123',
@@ -28,12 +32,12 @@ module ActiveMerchant #:nodoc:
28
32
  # :state => 'WA',
29
33
  # :country => 'Australia',
30
34
  # :zip => '2000'
31
- # }
35
+ # },
32
36
  # :description => 'purchased items'
33
37
  # }
34
38
  #
35
39
  # To finish setting up, create the active_merchant object you will be using, with the eWay gateway. If you have a
36
- # functional eWay account, replace :login with your account info.
40
+ # functional eWay account, replace :login with your Customer ID.
37
41
  #
38
42
  # gateway = ActiveMerchant::Billing::Base.gateway(:eway).new(:login => '87654321')
39
43
  #
@@ -41,7 +45,7 @@ module ActiveMerchant #:nodoc:
41
45
  #
42
46
  # response = gateway.purchase(tendollar, creditcard, options)
43
47
  #
44
- # Sending a transaction to TrustCommerce with active_merchant returns a Response object, which consistently allows you to:
48
+ # Sending a transaction to eWay with active_merchant returns a Response object, which consistently allows you to:
45
49
  #
46
50
  # 1) Check whether the transaction was successful
47
51
  #
@@ -131,7 +135,7 @@ module ActiveMerchant #:nodoc:
131
135
 
132
136
  self.money_format = :cents
133
137
  self.supported_countries = ['AU']
134
- self.supported_cardtypes = [:visa, :master, :american_express]
138
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
135
139
  self.homepage_url = 'http://www.eway.com.au/'
136
140
  self.display_name = 'eWAY'
137
141
 
@@ -143,7 +147,7 @@ module ActiveMerchant #:nodoc:
143
147
 
144
148
  # ewayCustomerEmail, ewayCustomerAddress, ewayCustomerPostcode
145
149
  def purchase(money, creditcard, options = {})
146
- requires!(options, :order_id)
150
+ requires_address!(options)
147
151
 
148
152
  post = {}
149
153
  add_creditcard(post, creditcard)
@@ -161,6 +165,11 @@ module ActiveMerchant #:nodoc:
161
165
  end
162
166
 
163
167
  private
168
+
169
+ def requires_address!(options)
170
+ raise ArgumentError.new("Missing eWay required parameters: address or billing_address") unless (options.has_key?(:address) or options.has_key?(:billing_address))
171
+ end
172
+
164
173
  def add_creditcard(post, creditcard)
165
174
  post[:CardNumber] = creditcard.number
166
175
  post[:CardExpiryMonth] = sprintf("%.2i", creditcard.month)
@@ -0,0 +1,152 @@
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"]["id"] || response["response"]["token"])
120
+ end
121
+
122
+ # Parse the returned JSON, if parse errors are raised then return a detailed error.
123
+ def parse(response)
124
+ begin
125
+ JSON.parse(response)
126
+ rescue JSON::ParserError
127
+ msg = 'Invalid JSON response received from Fat Zebra. Please contact support@fatzebra.com.au if you continue to receive this message.'
128
+ msg += " (The raw response returned by the API was #{response.inspect})"
129
+ {
130
+ "successful" => false,
131
+ "response" => {},
132
+ "errors" => [msg]
133
+ }
134
+ end
135
+ end
136
+
137
+ # Build the URL based on the AM mode and the URI
138
+ def get_url(uri)
139
+ base = test? ? SANDBOX_URL : LIVE_URL
140
+ base + "/" + uri
141
+ end
142
+
143
+ # Builds the auth and U-A headers for the request
144
+ def headers
145
+ {
146
+ "Authorization" => "Basic " + Base64.strict_encode64(@username.to_s + ":" + @token.to_s).strip,
147
+ "User-Agent" => "Fat Zebra v1.0/ActiveMerchant #{ActiveMerchant::VERSION}"
148
+ }
149
+ end
150
+ end
151
+ end
152
+ end