activemerchant 1.94.0 → 1.99.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +120 -1
- data/README.md +3 -0
- data/lib/active_merchant/billing/avs_result.rb +4 -5
- data/lib/active_merchant/billing/credit_card.rb +6 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +65 -2
- data/lib/active_merchant/billing/gateway.rb +10 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +119 -34
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
- data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -2
- data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +56 -9
- data/lib/active_merchant/billing/gateways/card_connect.rb +2 -1
- data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +37 -27
- data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
- data/lib/active_merchant/billing/gateways/cyber_source.rb +51 -11
- data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
- data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
- data/lib/active_merchant/billing/gateways/epay.rb +13 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +6 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
- data/lib/active_merchant/billing/gateways/hps.rb +46 -1
- data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
- data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +8 -0
- data/lib/active_merchant/billing/gateways/monei.rb +31 -0
- data/lib/active_merchant/billing/gateways/mundipagg.rb +33 -6
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
- data/lib/active_merchant/billing/gateways/opp.rb +20 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +60 -10
- data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
- data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
- data/lib/active_merchant/billing/gateways/qvalent.rb +43 -1
- data/lib/active_merchant/billing/gateways/realex.rb +32 -9
- data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
- data/lib/active_merchant/billing/gateways/stripe.rb +38 -9
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
- data/lib/active_merchant/billing/gateways/tns.rb +10 -5
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +45 -6
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
- data/lib/active_merchant/billing/gateways/worldpay.rb +177 -39
- data/lib/active_merchant/country.rb +1 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +19 -4
@@ -6,6 +6,10 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
self.display_name = 'Credorax Gateway'
|
7
7
|
self.homepage_url = 'https://www.credorax.com/'
|
8
8
|
|
9
|
+
# NOTE: the IP address you run the remote tests from will need to be
|
10
|
+
# whitelisted by Credorax; contact support@credorax.com as necessary to
|
11
|
+
# request your IP address be added to the whitelist for your test
|
12
|
+
# account.
|
9
13
|
self.test_url = 'https://intconsole.credorax.com/intenv/service/gateway'
|
10
14
|
|
11
15
|
# The live URL is assigned on a per merchant basis once certification has passed
|
@@ -15,7 +19,7 @@ module ActiveMerchant #:nodoc:
|
|
15
19
|
# ActiveMerchant::Billing::CredoraxGateway.live_url = "https://assigned-subdomain.credorax.net/crax_gate/service/gateway"
|
16
20
|
self.live_url = 'https://assigned-subdomain.credorax.net/crax_gate/service/gateway'
|
17
21
|
|
18
|
-
self.supported_countries = %w(
|
22
|
+
self.supported_countries = %w(AD AT BE BG HR CY CZ DK EE FR DE GI GR GG HU IS IE IM IT JE LV LI LT LU MT MC NO PL PT RO SM SK ES SE CH GB)
|
19
23
|
self.default_currency = 'EUR'
|
20
24
|
self.currencies_without_fractions = %w(CLP JPY KRW PYG VND)
|
21
25
|
self.currencies_with_three_decimal_places = %w(BHD JOD KWD OMR RSD TND)
|
@@ -131,6 +135,7 @@ module ActiveMerchant #:nodoc:
|
|
131
135
|
add_echo(post, options)
|
132
136
|
add_submerchant_id(post, options)
|
133
137
|
add_transaction_type(post, options)
|
138
|
+
add_processor(post, options)
|
134
139
|
|
135
140
|
commit(:purchase, post)
|
136
141
|
end
|
@@ -145,6 +150,7 @@ module ActiveMerchant #:nodoc:
|
|
145
150
|
add_echo(post, options)
|
146
151
|
add_submerchant_id(post, options)
|
147
152
|
add_transaction_type(post, options)
|
153
|
+
add_processor(post, options)
|
148
154
|
|
149
155
|
commit(:authorize, post)
|
150
156
|
end
|
@@ -156,6 +162,7 @@ module ActiveMerchant #:nodoc:
|
|
156
162
|
add_customer_data(post, options)
|
157
163
|
add_echo(post, options)
|
158
164
|
add_submerchant_id(post, options)
|
165
|
+
add_processor(post, options)
|
159
166
|
|
160
167
|
commit(:capture, post)
|
161
168
|
end
|
@@ -167,6 +174,7 @@ module ActiveMerchant #:nodoc:
|
|
167
174
|
add_echo(post, options)
|
168
175
|
add_submerchant_id(post, options)
|
169
176
|
post[:a1] = generate_unique_id
|
177
|
+
add_processor(post, options)
|
170
178
|
|
171
179
|
commit(:void, post, reference_action)
|
172
180
|
end
|
@@ -178,6 +186,7 @@ module ActiveMerchant #:nodoc:
|
|
178
186
|
add_customer_data(post, options)
|
179
187
|
add_echo(post, options)
|
180
188
|
add_submerchant_id(post, options)
|
189
|
+
add_processor(post, options)
|
181
190
|
|
182
191
|
commit(:refund, post)
|
183
192
|
end
|
@@ -191,6 +200,7 @@ module ActiveMerchant #:nodoc:
|
|
191
200
|
add_echo(post, options)
|
192
201
|
add_submerchant_id(post, options)
|
193
202
|
add_transaction_type(post, options)
|
203
|
+
add_processor(post, options)
|
194
204
|
|
195
205
|
commit(:credit, post)
|
196
206
|
end
|
@@ -264,8 +274,56 @@ module ActiveMerchant #:nodoc:
|
|
264
274
|
end
|
265
275
|
|
266
276
|
def add_3d_secure(post, options)
|
267
|
-
|
268
|
-
|
277
|
+
if options[:eci] && options[:xid]
|
278
|
+
add_3d_secure_1_data(post, options)
|
279
|
+
elsif options[:execute_threed] && options[:three_ds_2]
|
280
|
+
three_ds_2_options = options[:three_ds_2]
|
281
|
+
browser_info = three_ds_2_options[:browser_info]
|
282
|
+
post[:'3ds_initiate'] = options[:three_ds_initiate] || '01'
|
283
|
+
post[:'3ds_purchasedate'] = Time.now.utc.strftime('%Y%m%d%I%M%S')
|
284
|
+
post[:'3ds_channel'] = '02'
|
285
|
+
post[:'3ds_redirect_url'] = three_ds_2_options[:notification_url]
|
286
|
+
post[:'3ds_challengewindowsize'] = options[:three_ds_challenge_window_size] || '03'
|
287
|
+
post[:'3ds_version'] = options[:three_ds_version] if options[:three_ds_version]
|
288
|
+
post[:d5] = browser_info[:user_agent]
|
289
|
+
post[:'3ds_transtype'] = options[:transaction_type] || '01'
|
290
|
+
post[:'3ds_browsertz'] = browser_info[:timezone]
|
291
|
+
post[:'3ds_browserscreenwidth'] = browser_info[:width]
|
292
|
+
post[:'3ds_browserscreenheight'] = browser_info[:height]
|
293
|
+
post[:'3ds_browsercolordepth'] = browser_info[:depth]
|
294
|
+
post[:d6] = browser_info[:language]
|
295
|
+
post[:'3ds_browserjavaenabled'] = browser_info[:java]
|
296
|
+
post[:'3ds_browseracceptheader'] = browser_info[:accept_header]
|
297
|
+
if (shipping_address = options[:shipping_address])
|
298
|
+
post[:'3ds_shipaddrstate'] = shipping_address[:state]
|
299
|
+
post[:'3ds_shipaddrpostcode'] = shipping_address[:zip]
|
300
|
+
post[:'3ds_shipaddrline2'] = shipping_address[:address2]
|
301
|
+
post[:'3ds_shipaddrline1'] = shipping_address[:address1]
|
302
|
+
post[:'3ds_shipaddrcountry'] = shipping_address[:country]
|
303
|
+
post[:'3ds_shipaddrcity'] = shipping_address[:city]
|
304
|
+
end
|
305
|
+
elsif options[:three_d_secure]
|
306
|
+
add_normalized_3d_secure_2_data(post, options)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def add_3d_secure_1_data(post, options)
|
311
|
+
post[:i8] = build_i8(options[:eci], options[:cavv], options[:xid])
|
312
|
+
end
|
313
|
+
|
314
|
+
def add_normalized_3d_secure_2_data(post, options)
|
315
|
+
three_d_secure_options = options[:three_d_secure]
|
316
|
+
|
317
|
+
post[:i8] = build_i8(
|
318
|
+
three_d_secure_options[:eci],
|
319
|
+
three_d_secure_options[:cavv]
|
320
|
+
)
|
321
|
+
post[:'3ds_version'] = three_d_secure_options[:version]
|
322
|
+
post[:'3ds_dstrxid'] = three_d_secure_options[:ds_transaction_id]
|
323
|
+
end
|
324
|
+
|
325
|
+
def build_i8(eci, cavv=nil, xid=nil)
|
326
|
+
"#{eci}:#{cavv || 'none'}:#{xid || 'none'}"
|
269
327
|
end
|
270
328
|
|
271
329
|
def add_echo(post, options)
|
@@ -280,6 +338,12 @@ module ActiveMerchant #:nodoc:
|
|
280
338
|
|
281
339
|
def add_transaction_type(post, options)
|
282
340
|
post[:a9] = options[:transaction_type] if options[:transaction_type]
|
341
|
+
post[:a2] = '3' if options.dig(:metadata, :manual_entry)
|
342
|
+
end
|
343
|
+
|
344
|
+
def add_processor(post, options)
|
345
|
+
post[:r1] = options[:processor] || 'CREDORAX'
|
346
|
+
post[:r2] = options[:processor_merchant_id] if options[:processor_merchant_id]
|
283
347
|
end
|
284
348
|
|
285
349
|
ACTIONS = {
|
@@ -291,7 +355,8 @@ module ActiveMerchant #:nodoc:
|
|
291
355
|
credit: '6',
|
292
356
|
purchase_void: '7',
|
293
357
|
refund_void: '8',
|
294
|
-
capture_void: '9'
|
358
|
+
capture_void: '9',
|
359
|
+
threeds_completion: '92'
|
295
360
|
}
|
296
361
|
|
297
362
|
def commit(action, params, reference_action = nil)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
3
|
# Initial setup instructions can be found in
|
4
|
-
# http://cybersource.com/
|
4
|
+
# http://apps.cybersource.com/library/documentation/dev_guides/SOAP_Toolkits/SOAP_toolkits.pdf
|
5
5
|
#
|
6
6
|
# Important Notes
|
7
7
|
# * For checks you can purchase and store.
|
@@ -24,10 +24,12 @@ module ActiveMerchant #:nodoc:
|
|
24
24
|
self.test_url = 'https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor'
|
25
25
|
self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor'
|
26
26
|
|
27
|
-
|
27
|
+
# Schema files can be found here: https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/
|
28
|
+
TEST_XSD_VERSION = '1.159'
|
29
|
+
PRODUCTION_XSD_VERSION = '1.159'
|
28
30
|
|
29
31
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro, :elo]
|
30
|
-
self.supported_countries = %w(US BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB)
|
32
|
+
self.supported_countries = %w(US BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB PK)
|
31
33
|
|
32
34
|
self.default_currency = 'USD'
|
33
35
|
self.currencies_without_fractions = %w(JPY)
|
@@ -256,6 +258,7 @@ module ActiveMerchant #:nodoc:
|
|
256
258
|
def build_auth_request(money, creditcard_or_reference, options)
|
257
259
|
xml = Builder::XmlMarkup.new :indent => 2
|
258
260
|
add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
|
261
|
+
add_threeds_2_ucaf_data(xml, creditcard_or_reference, options)
|
259
262
|
add_decision_manager_fields(xml, options)
|
260
263
|
add_mdd_fields(xml, options)
|
261
264
|
add_auth_service(xml, creditcard_or_reference, options)
|
@@ -263,6 +266,8 @@ module ActiveMerchant #:nodoc:
|
|
263
266
|
add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
|
264
267
|
add_business_rules_data(xml, creditcard_or_reference, options)
|
265
268
|
add_stored_credential_options(xml, options)
|
269
|
+
add_issuer_additional_data(xml, options)
|
270
|
+
|
266
271
|
xml.target!
|
267
272
|
end
|
268
273
|
|
@@ -291,6 +296,7 @@ module ActiveMerchant #:nodoc:
|
|
291
296
|
def build_purchase_request(money, payment_method_or_reference, options)
|
292
297
|
xml = Builder::XmlMarkup.new :indent => 2
|
293
298
|
add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
|
299
|
+
add_threeds_2_ucaf_data(xml, payment_method_or_reference, options)
|
294
300
|
add_decision_manager_fields(xml, options)
|
295
301
|
add_mdd_fields(xml, options)
|
296
302
|
if !payment_method_or_reference.is_a?(String) && card_brand(payment_method_or_reference) == 'check'
|
@@ -301,6 +307,8 @@ module ActiveMerchant #:nodoc:
|
|
301
307
|
add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference)
|
302
308
|
add_business_rules_data(xml, payment_method_or_reference, options) unless options[:pinless_debit_card]
|
303
309
|
end
|
310
|
+
add_issuer_additional_data(xml, options)
|
311
|
+
|
304
312
|
xml.target!
|
305
313
|
end
|
306
314
|
|
@@ -485,6 +493,14 @@ module ActiveMerchant #:nodoc:
|
|
485
493
|
end
|
486
494
|
end
|
487
495
|
|
496
|
+
def add_issuer_additional_data(xml, options)
|
497
|
+
return unless options[:issuer_additional_data]
|
498
|
+
|
499
|
+
xml.tag! 'issuer' do
|
500
|
+
xml.tag! 'additionalData', options[:issuer_additional_data]
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
488
504
|
def add_mdd_fields(xml, options)
|
489
505
|
return unless options.keys.any? { |key| key.to_s.start_with?('mdd_field') }
|
490
506
|
|
@@ -516,19 +532,41 @@ module ActiveMerchant #:nodoc:
|
|
516
532
|
add_auth_network_tokenization(xml, payment_method, options)
|
517
533
|
else
|
518
534
|
xml.tag! 'ccAuthService', {'run' => 'true'} do
|
519
|
-
|
535
|
+
if options[:three_d_secure]
|
536
|
+
add_normalized_threeds_2_data(xml, payment_method, options)
|
537
|
+
else
|
538
|
+
indicator = options[:commerce_indicator] || stored_credential_commerce_indicator(options)
|
539
|
+
xml.tag!('commerceIndicator', indicator) if indicator
|
540
|
+
end
|
520
541
|
end
|
521
542
|
end
|
522
543
|
end
|
523
544
|
|
524
|
-
def
|
525
|
-
|
526
|
-
|
527
|
-
|
545
|
+
def add_normalized_threeds_2_data(xml, payment_method, options)
|
546
|
+
threeds_2_options = options[:three_d_secure]
|
547
|
+
|
548
|
+
xml.tag!('cavv', threeds_2_options[:cavv]) if threeds_2_options[:cavv] && card_brand(payment_method).to_sym != :master
|
549
|
+
xml.tag!('cavvAlgorithm', threeds_2_options[:cavv_algorithm]) if threeds_2_options[:cavv_algorithm]
|
550
|
+
xml.tag!('paSpecificationVersion', threeds_2_options[:version]) if threeds_2_options[:version]
|
551
|
+
xml.tag!('directoryServerTransactionID', threeds_2_options[:ds_transaction_id]) if threeds_2_options[:ds_transaction_id]
|
552
|
+
xml.tag!('commerceIndicator', options[:commerce_indicator]) if options[:commerce_indicator]
|
553
|
+
xml.tag!('eciRaw', threeds_2_options[:eci]) if threeds_2_options[:eci]
|
554
|
+
xml.tag!('xid', threeds_2_options[:xid]) if threeds_2_options[:xid]
|
555
|
+
xml.tag!('veresEnrolled', threeds_2_options[:enrolled]) if threeds_2_options[:enrolled]
|
556
|
+
xml.tag!('paresStatus', threeds_2_options[:authentication_response_status]) if threeds_2_options[:authentication_response_status]
|
557
|
+
end
|
558
|
+
|
559
|
+
def add_threeds_2_ucaf_data(xml, payment_method, options)
|
560
|
+
return unless options[:three_d_secure] && card_brand(payment_method).to_sym == :master
|
561
|
+
|
562
|
+
xml.tag! 'ucaf' do
|
563
|
+
xml.tag!('authenticationData', options[:three_d_secure][:cavv])
|
564
|
+
xml.tag!('collectionIndicator', options[:collection_indicator]) if options[:collection_indicator]
|
528
565
|
end
|
529
566
|
end
|
530
567
|
|
531
|
-
def
|
568
|
+
def stored_credential_commerce_indicator(options)
|
569
|
+
return unless options[:stored_credential]
|
532
570
|
return if options[:stored_credential][:initial_transaction]
|
533
571
|
case options[:stored_credential][:reason_type]
|
534
572
|
when 'installment' then 'install'
|
@@ -550,7 +588,7 @@ module ActiveMerchant #:nodoc:
|
|
550
588
|
xml.tag!('commerceIndicator', 'vbv')
|
551
589
|
xml.tag!('xid', payment_method.payment_cryptogram)
|
552
590
|
end
|
553
|
-
when :
|
591
|
+
when :master
|
554
592
|
xml.tag! 'ucaf' do
|
555
593
|
xml.tag!('authenticationData', payment_method.payment_cryptogram)
|
556
594
|
xml.tag!('collectionIndicator', '2')
|
@@ -713,6 +751,8 @@ module ActiveMerchant #:nodoc:
|
|
713
751
|
|
714
752
|
# Where we actually build the full SOAP request using builder
|
715
753
|
def build_request(body, options)
|
754
|
+
xsd_version = test? ? TEST_XSD_VERSION : PRODUCTION_XSD_VERSION
|
755
|
+
|
716
756
|
xml = Builder::XmlMarkup.new :indent => 2
|
717
757
|
xml.instruct!
|
718
758
|
xml.tag! 's:Envelope', {'xmlns:s' => 'http://schemas.xmlsoap.org/soap/envelope/'} do
|
@@ -725,7 +765,7 @@ module ActiveMerchant #:nodoc:
|
|
725
765
|
end
|
726
766
|
end
|
727
767
|
xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do
|
728
|
-
xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{
|
768
|
+
xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{xsd_version}"} do
|
729
769
|
add_merchant_data(xml, options)
|
730
770
|
xml << body
|
731
771
|
end
|
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
|
7
7
|
self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY', 'TR']
|
8
8
|
self.default_currency = 'USD'
|
9
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
|
9
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja, :cabal]
|
10
10
|
|
11
11
|
self.homepage_url = 'https://dlocal.com/'
|
12
12
|
self.display_name = 'dLocal'
|
@@ -0,0 +1,245 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class DecidirGateway < Gateway
|
4
|
+
self.test_url = 'https://developers.decidir.com/api/v2'
|
5
|
+
self.live_url = 'https://live.decidir.com/api/v2'
|
6
|
+
|
7
|
+
self.supported_countries = ['AR']
|
8
|
+
self.money_format = :cents
|
9
|
+
self.default_currency = 'ARS'
|
10
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :naranja, :cabal]
|
11
|
+
|
12
|
+
self.homepage_url = 'http://www.decidir.com'
|
13
|
+
self.display_name = 'Decidir'
|
14
|
+
|
15
|
+
STANDARD_ERROR_CODE_MAPPING = {
|
16
|
+
1 => STANDARD_ERROR_CODE[:call_issuer],
|
17
|
+
2 => STANDARD_ERROR_CODE[:call_issuer],
|
18
|
+
3 => STANDARD_ERROR_CODE[:config_error],
|
19
|
+
4 => STANDARD_ERROR_CODE[:pickup_card],
|
20
|
+
5 => STANDARD_ERROR_CODE[:card_declined],
|
21
|
+
7 => STANDARD_ERROR_CODE[:pickup_card],
|
22
|
+
12 => STANDARD_ERROR_CODE[:processing_error],
|
23
|
+
14 => STANDARD_ERROR_CODE[:invalid_number],
|
24
|
+
28 => STANDARD_ERROR_CODE[:processing_error],
|
25
|
+
38 => STANDARD_ERROR_CODE[:incorrect_pin],
|
26
|
+
39 => STANDARD_ERROR_CODE[:invalid_number],
|
27
|
+
43 => STANDARD_ERROR_CODE[:pickup_card],
|
28
|
+
45 => STANDARD_ERROR_CODE[:card_declined],
|
29
|
+
46 => STANDARD_ERROR_CODE[:invalid_number],
|
30
|
+
47 => STANDARD_ERROR_CODE[:card_declined],
|
31
|
+
48 => STANDARD_ERROR_CODE[:card_declined],
|
32
|
+
49 => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
33
|
+
51 => STANDARD_ERROR_CODE[:card_declined],
|
34
|
+
53 => STANDARD_ERROR_CODE[:card_declined],
|
35
|
+
54 => STANDARD_ERROR_CODE[:expired_card],
|
36
|
+
55 => STANDARD_ERROR_CODE[:incorrect_pin],
|
37
|
+
56 => STANDARD_ERROR_CODE[:card_declined],
|
38
|
+
57 => STANDARD_ERROR_CODE[:card_declined],
|
39
|
+
76 => STANDARD_ERROR_CODE[:call_issuer],
|
40
|
+
96 => STANDARD_ERROR_CODE[:processing_error],
|
41
|
+
97 => STANDARD_ERROR_CODE[:processing_error],
|
42
|
+
}
|
43
|
+
|
44
|
+
def initialize(options={})
|
45
|
+
requires!(options, :api_key)
|
46
|
+
super
|
47
|
+
@options[:preauth_mode] ||= false
|
48
|
+
end
|
49
|
+
|
50
|
+
def purchase(money, payment, options={})
|
51
|
+
raise ArgumentError, 'Purchase is not supported on Decidir gateways configured with the preauth_mode option' if @options[:preauth_mode]
|
52
|
+
|
53
|
+
post = {}
|
54
|
+
add_auth_purchase_params(post, money, payment, options)
|
55
|
+
commit(:post, 'payments', post)
|
56
|
+
end
|
57
|
+
|
58
|
+
def authorize(money, payment, options={})
|
59
|
+
raise ArgumentError, 'Authorize is not supported on Decidir gateways unless the preauth_mode option is enabled' unless @options[:preauth_mode]
|
60
|
+
|
61
|
+
post = {}
|
62
|
+
add_auth_purchase_params(post, money, payment, options)
|
63
|
+
commit(:post, 'payments', post)
|
64
|
+
end
|
65
|
+
|
66
|
+
def capture(money, authorization, options={})
|
67
|
+
raise ArgumentError, 'Capture is not supported on Decidir gateways unless the preauth_mode option is enabled' unless @options[:preauth_mode]
|
68
|
+
|
69
|
+
post = {}
|
70
|
+
add_amount(post, money, options)
|
71
|
+
commit(:put, "payments/#{authorization}", post)
|
72
|
+
end
|
73
|
+
|
74
|
+
def refund(money, authorization, options={})
|
75
|
+
post = {}
|
76
|
+
add_amount(post, money, options)
|
77
|
+
commit(:post, "payments/#{authorization}/refunds", post)
|
78
|
+
end
|
79
|
+
|
80
|
+
def void(authorization, options={})
|
81
|
+
post = {}
|
82
|
+
commit(:post, "payments/#{authorization}/refunds", post)
|
83
|
+
end
|
84
|
+
|
85
|
+
def verify(credit_card, options={})
|
86
|
+
raise ArgumentError, 'Verify is not supported on Decidir gateways unless the preauth_mode option is enabled' unless @options[:preauth_mode]
|
87
|
+
|
88
|
+
MultiResponse.run(:use_first_response) do |r|
|
89
|
+
r.process { authorize(100, credit_card, options) }
|
90
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def supports_scrubbing?
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def scrub(transcript)
|
99
|
+
transcript.
|
100
|
+
gsub(%r((apikey: )\w+)i, '\1[FILTERED]').
|
101
|
+
gsub(%r((\"card_number\\\":\\\")\d+), '\1[FILTERED]').
|
102
|
+
gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]').
|
103
|
+
gsub(%r((\"emv_issuer_data\\\":\\\")\d+), '\1[FILTERED]')
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def add_auth_purchase_params(post, money, credit_card, options)
|
109
|
+
post[:payment_method_id] = add_payment_method_id(credit_card)
|
110
|
+
post[:site_transaction_id] = options[:order_id]
|
111
|
+
post[:bin] = credit_card.number[0..5]
|
112
|
+
post[:payment_type] = options[:payment_type] || 'single'
|
113
|
+
post[:installments] = options[:installments] ? options[:installments].to_i : 1
|
114
|
+
post[:description] = options[:description] if options[:description]
|
115
|
+
post[:email] = options[:email] if options[:email]
|
116
|
+
post[:sub_payments] = []
|
117
|
+
|
118
|
+
add_invoice(post, money, options)
|
119
|
+
add_payment(post, credit_card, options)
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_payment_method_id(credit_card)
|
123
|
+
if options[:payment_method_id]
|
124
|
+
options[:payment_method_id].to_i
|
125
|
+
elsif CreditCard.brand?(credit_card.number) == 'cabal'
|
126
|
+
63
|
127
|
+
elsif CreditCard.brand?(credit_card.number) == 'naranja'
|
128
|
+
24
|
129
|
+
else
|
130
|
+
1
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_invoice(post, money, options)
|
135
|
+
add_amount(post, money, options)
|
136
|
+
post[:currency] = (options[:currency] || currency(money))
|
137
|
+
end
|
138
|
+
|
139
|
+
def add_amount(post, money, options)
|
140
|
+
currency = (options[:currency] || currency(money))
|
141
|
+
post[:amount] = localized_amount(money, currency).to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_payment(post, credit_card, options)
|
145
|
+
card_data = {}
|
146
|
+
card_data[:card_number] = credit_card.number
|
147
|
+
card_data[:card_expiration_month] = format(credit_card.month, :two_digits)
|
148
|
+
card_data[:card_expiration_year] = format(credit_card.year, :two_digits)
|
149
|
+
card_data[:security_code] = credit_card.verification_value if credit_card.verification_value?
|
150
|
+
card_data[:card_holder_name] = credit_card.name if credit_card.name
|
151
|
+
|
152
|
+
# additional data used for Visa transactions
|
153
|
+
card_data[:card_holder_door_number] = options[:card_holder_door_number].to_i if options[:card_holder_door_number]
|
154
|
+
card_data[:card_holder_birthday] = options[:card_holder_birthday] if options[:card_holder_birthday]
|
155
|
+
|
156
|
+
card_data[:card_holder_identification] = {}
|
157
|
+
card_data[:card_holder_identification][:type] = options[:card_holder_identification_type] if options[:card_holder_identification_type]
|
158
|
+
card_data[:card_holder_identification][:number] = options[:card_holder_identification_number] if options[:card_holder_identification_number]
|
159
|
+
|
160
|
+
post[:card_data] = card_data
|
161
|
+
end
|
162
|
+
|
163
|
+
def headers(options = {})
|
164
|
+
{
|
165
|
+
'apikey' => @options[:api_key],
|
166
|
+
'Content-type' => 'application/json',
|
167
|
+
'Cache-Control' => 'no-cache'
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
def commit(method, endpoint, parameters, options={})
|
172
|
+
url = "#{(test? ? test_url : live_url)}/#{endpoint}"
|
173
|
+
|
174
|
+
begin
|
175
|
+
raw_response = ssl_request(method, url, post_data(parameters), headers(options))
|
176
|
+
response = parse(raw_response)
|
177
|
+
rescue ResponseError => e
|
178
|
+
raw_response = e.response.body
|
179
|
+
response = parse(raw_response)
|
180
|
+
end
|
181
|
+
|
182
|
+
success = success_from(response)
|
183
|
+
Response.new(
|
184
|
+
success,
|
185
|
+
message_from(success, response),
|
186
|
+
response,
|
187
|
+
authorization: authorization_from(response),
|
188
|
+
test: test?,
|
189
|
+
error_code: success ? nil : error_code_from(response)
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
def post_data(parameters = {})
|
194
|
+
parameters.to_json
|
195
|
+
end
|
196
|
+
|
197
|
+
def parse(body)
|
198
|
+
JSON.parse(body)
|
199
|
+
rescue JSON::ParserError
|
200
|
+
{
|
201
|
+
'message' => "A non-JSON response was received from Decidir where one was expected. The raw response was:\n\n#{body}"
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
def message_from(success, response)
|
206
|
+
return response['status'] if success
|
207
|
+
return response['message'] if response['message']
|
208
|
+
|
209
|
+
message = nil
|
210
|
+
|
211
|
+
if error = response.dig('status_details', 'error')
|
212
|
+
message = error.dig('reason', 'description')
|
213
|
+
elsif response['error_type']
|
214
|
+
if response['validation_errors']
|
215
|
+
message = response['validation_errors'].map { |errors| "#{errors['code']}: #{errors['param']}" }.join(', ')
|
216
|
+
end
|
217
|
+
message ||= response['error_type']
|
218
|
+
end
|
219
|
+
|
220
|
+
message
|
221
|
+
end
|
222
|
+
|
223
|
+
def success_from(response)
|
224
|
+
response['status'] == 'approved' || response['status'] == 'pre_approved'
|
225
|
+
end
|
226
|
+
|
227
|
+
def authorization_from(response)
|
228
|
+
response['id']
|
229
|
+
end
|
230
|
+
|
231
|
+
def error_code_from(response)
|
232
|
+
error_code = nil
|
233
|
+
if error = response.dig('status_details', 'error')
|
234
|
+
code = error.dig('reason', 'id')
|
235
|
+
error_code = STANDARD_ERROR_CODE_MAPPING[code]
|
236
|
+
error_code ||= error['type']
|
237
|
+
elsif response['error_type']
|
238
|
+
error_code = response['error_type'] if response['validation_errors']
|
239
|
+
end
|
240
|
+
|
241
|
+
error_code || STANDARD_ERROR_CODE[:processing_error]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|