activemerchant 1.24.0 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +31 -0
- data/CONTRIBUTORS +12 -0
- data/README.md +1 -0
- data/lib/active_merchant/billing/base.rb +8 -9
- data/lib/active_merchant/billing/gateway.rb +31 -31
- data/lib/active_merchant/billing/gateways/authorize_net.rb +25 -24
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +45 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +157 -29
- data/lib/active_merchant/billing/gateways/eway.rb +17 -8
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +152 -0
- data/lib/active_merchant/billing/gateways/litle.rb +0 -1
- data/lib/active_merchant/billing/gateways/metrics_global.rb +323 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +12 -9
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +7 -3
- data/lib/active_merchant/billing/gateways/wirecard.rb +79 -84
- data/lib/active_merchant/billing/integrations/easy_pay.rb +30 -0
- data/lib/active_merchant/billing/integrations/easy_pay/common.rb +40 -0
- data/lib/active_merchant/billing/integrations/easy_pay/helper.rb +40 -0
- data/lib/active_merchant/billing/integrations/easy_pay/notification.rb +51 -0
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +1 -1
- data/lib/active_merchant/billing/integrations/paypal_payments_advanced.rb +20 -0
- data/lib/active_merchant/billing/integrations/paypal_payments_advanced/helper.rb +15 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +39 -25
- metadata.gz.sig +0 -0
@@ -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,
|
108
|
-
requires!(options, :order_id
|
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,
|
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,
|
126
|
-
requires!(options, :order_id
|
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,
|
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,
|
211
|
+
def build_auth_request(money, creditcard_or_reference, options)
|
182
212
|
xml = Builder::XmlMarkup.new :indent => 2
|
183
|
-
|
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,
|
241
|
+
def build_purchase_request(money, creditcard_or_reference, options)
|
214
242
|
xml = Builder::XmlMarkup.new :indent => 2
|
215
|
-
|
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',
|
276
|
-
xml.tag! 'clientEnvironment' ,
|
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',
|
289
|
-
xml.tag! 'lastName',
|
290
|
-
xml.tag! 'street1',
|
291
|
-
xml.tag! 'street2', address[:address2]
|
292
|
-
xml.tag! 'city',
|
293
|
-
xml.tag! 'state',
|
294
|
-
xml.tag! 'postalCode',
|
295
|
-
xml.tag! 'country',
|
296
|
-
xml.tag! '
|
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' =>
|
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
|
-
#
|
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 => '
|
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
|
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
|
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
|
-
|
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
|