activemerchant 1.24.0 → 1.25.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|