activemerchant 1.94.0 → 1.99.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.
- 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
|