activemerchant 1.117.0 → 1.118.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +32 -0
  3. data/README.md +1 -1
  4. data/lib/active_merchant/billing/credit_card.rb +2 -0
  5. data/lib/active_merchant/billing/credit_card_methods.rb +57 -10
  6. data/lib/active_merchant/billing/gateways/adyen.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -0
  8. data/lib/active_merchant/billing/gateways/blue_snap.rb +3 -1
  9. data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -0
  10. data/lib/active_merchant/billing/gateways/credorax.rb +1 -0
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +14 -3
  12. data/lib/active_merchant/billing/gateways/decidir.rb +14 -0
  13. data/lib/active_merchant/billing/gateways/elavon.rb +35 -2
  14. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +17 -6
  15. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/litle.rb +5 -0
  17. data/lib/active_merchant/billing/gateways/orbital.rb +112 -20
  18. data/lib/active_merchant/billing/gateways/payeezy.rb +23 -5
  19. data/lib/active_merchant/billing/gateways/paymentez.rb +21 -1
  20. data/lib/active_merchant/billing/gateways/paypal.rb +10 -2
  21. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -0
  22. data/lib/active_merchant/billing/gateways/pin.rb +11 -0
  23. data/lib/active_merchant/billing/gateways/redsys.rb +34 -5
  24. data/lib/active_merchant/billing/gateways/safe_charge.rb +5 -3
  25. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +7 -0
  26. data/lib/active_merchant/billing/gateways/worldpay.rb +4 -1
  27. data/lib/active_merchant/billing/response.rb +2 -1
  28. data/lib/active_merchant/version.rb +1 -1
  29. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40c5c0774f8eb95c3aff1873f2067aea19df812d49af757df53e8f448b8ad9d1
4
- data.tar.gz: d30077388953e6945c9353f829e8ea38503828e39555594bb76c46c30c0b7f45
3
+ metadata.gz: 506cd11074e8ee661844d74fb2a114665b025952d47517a423f27bd2ca566c49
4
+ data.tar.gz: 35cfe858b3bd6c492558dcd47cf17518edc6dbd96176dbb72abe6df2ff607724
5
5
  SHA512:
6
- metadata.gz: 8ae4e27c577076982790c058395b863f659e9a07e71a5dd904bb755ce7a2f086c60112f25d91f054087a4c62740adf0f8b1cece5968bc8e0ee247b0f3e0ee06d
7
- data.tar.gz: 896c982831e68d0b70813c80c8dfc086302389f8aa13dc8b64fdc0582ef42baab1c75d50f502f681f2abc085f2c74992e0b1f85919d84012af5ba024bab11602
6
+ metadata.gz: 8955f8c555ec9049fa06e76176a2a819e2e1bbe54868eab1c88023ece7dcd722201009b39d238acfedc79a5ac50363c73dbfa776b95f61d3db308f0b7dd897e6
7
+ data.tar.gz: 77736f76e9483256f71abb8799d8bf4804ba0f56992e226f9f185ecb0fed1cb87dc8956e886473a17c4643d3f799e6b9898565c4ec0420b1b3fcefa7471e1d16
data/CHANGELOG CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ == Version 1.118.0 (January 22nd, 2021)
6
+ * Worldpay: Add support for challengeWindowSize [carrigan] #3823
7
+ * Adyen: Update capitalization on subMerchantId field [cdmackeyfree] #3824
8
+ * Maestro and Elo: Update BIN ranges [meagabeth] #3822
9
+ * HPS: Truncate invoice numbers that are too long [curiousepic] #3825
10
+ * Pass network_transaction_id attribute in Response [therufs] #3815
11
+ * Elavon: support standardized stored credentials [therufs] #3816
12
+ * Decidir: update fraud_detection field [cdmackeyfree] #3829
13
+ * Paymentez: Add Olimpica cardtype [meagabeth] #3831
14
+ * SafeCharge: 3DS external MPI data refinements [curiousepic] #3821
15
+ * Credorax: Add support for 3DS Adviser [meagabeth] #3834
16
+ * Adyen: Support subMerchant data [mymir][therufs] #3835
17
+ * Decidir: add device_unique_identifier to card data [cdmackeyfree] #3839
18
+ * BraintreeBlue: add support for account_type field [jimilpatel24] #3840
19
+ * Redsys: Add support for stored_credential [meagabeth] #3844
20
+ * Redsys: add_payment method solution [meagabeth] #3845
21
+ * Stripe Payment Intents: Add support for error_on_requires_action option [tatsianaclifton] #3846
22
+ * Add 3DS 2.0 values to paypal [nebdil] #3285
23
+ * Redsys: Update Mpi Fields [tatsianaclifton] #3855
24
+ * Paypal: Update AuthStatus3ds MPI field [curiousepic] #3857
25
+ * Orbital: Update 3DS support for Mastercard [meagabeth] #3850
26
+ * Payeezy: Support standardized stored credentials [therufs] #3861
27
+ * CyberSource: Update `billing_address` override [meagabeth] #3862
28
+ * Paymentez: Add 3DS MPI field support [carrigan] #3856
29
+ * BlueSnap: Add support `fraud-session-id` field [meagabeth] #3863
30
+ * BlueSnap: Update handling of `transaction-fraud-info` fields [meagabeth] #3866
31
+ * Payeezy: Allow no stored credential transaction id [therufs] #3868
32
+ * Orbital: eCheck processing added [ajawadmirza] #3870
33
+ * FirsdataE4V27: Fixes some apple pay transaction issues [pi3r] #3872
34
+
5
35
  == Version 1.117.0 (November 13th)
6
36
  * Checkout V2: Pass attempt_n3d along with 3ds enabled [naashton] #3805
7
37
  * GlobalCollect: Add support for Third-party 3DS2 data [molbrown] #3801
@@ -17,6 +47,7 @@
17
47
  * Credorax: Allow 3DS1 normalized pass-through, ease version matching [britth] #3812
18
48
  * Redsys: Redsys: Harden 3DS v1/v2 check for External MPI [esmitperez] #3814
19
49
  * Add card types for Stripe, Worldpay, Checkout.com [LinTrieu] #3810
50
+ * ActiveMerchant::Billing::Response: Include `network_transaction_id` attribute [therufs] #3815
20
51
 
21
52
  == Version 1.116.0 (October 28th)
22
53
  * Remove Braintree specific version dependency [pi3r] #3800
@@ -62,6 +93,7 @@
62
93
  * Checkout V2: Support for attempt_n3d 3DS field [naashton] #3790
63
94
  * Elavon: Strip ampersands [therufs] #3795
64
95
  * Paybox: Add support for 3DS 1.0 values [jcpaybox] #3335
96
+ * Decidir: Add additional fraud_detection options [cdmackeyfree] #3812
65
97
 
66
98
  == Version 1.114.0
67
99
  * BlueSnap: Add address1,address2,phone,shipping_* support #3749
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Active Merchant
2
- [![Build Status](https://travis-ci.org/activemerchant/active_merchant.svg?branch=master)](https://travis-ci.org/activemerchant/active_merchant)
2
+ [![Build Status](https://github.com/activemerchant/active_merchant/workflows/CI/badge.svg?branch=master)](https://github.com/activemerchant/active_merchant/actions?query=workflow%3ACI)
3
3
  [![Code Climate](https://codeclimate.com/github/activemerchant/active_merchant.svg)](https://codeclimate.com/github/activemerchant/active_merchant)
4
4
 
5
5
  Active Merchant is an extraction from the ecommerce system [Shopify](http://www.shopify.com).
@@ -24,6 +24,7 @@ module ActiveMerchant #:nodoc:
24
24
  # * Naranja
25
25
  # * UnionPay
26
26
  # * Alia
27
+ # * Olimpica
27
28
  #
28
29
  # For testing purposes, use the 'bogus' credit card brand. This skips the vast majority of
29
30
  # validations, allowing you to focus on your core concerns until you're ready to be more concerned
@@ -100,6 +101,7 @@ module ActiveMerchant #:nodoc:
100
101
  # * +'naranja'+
101
102
  # * +'union_pay'+
102
103
  # * +'alia'+
104
+ # * +'olimpica'+
103
105
  #
104
106
  # Or, if you wish to test your implementation, +'bogus'+.
105
107
  #
@@ -30,7 +30,8 @@ module ActiveMerchant #:nodoc:
30
30
  in_bin_range?(num.slice(0, 6), CARNET_RANGES) ||
31
31
  CARNET_BINS.any? { |bin| num.slice(0, bin.size) == bin }
32
32
  )
33
- }
33
+ },
34
+ 'olimpica' => ->(num) { num =~ /^636853\d{10}$/ }
34
35
  }
35
36
 
36
37
  # http://www.barclaycard.co.uk/business/files/bin_rules.pdf
@@ -72,11 +73,57 @@ module ActiveMerchant #:nodoc:
72
73
  ]
73
74
 
74
75
  MAESTRO_BINS = Set.new(
75
- %w[500033 581149]
76
+ %w[ 500057
77
+ 501018 501043 501045 501047 501049 501051 501072 501075 501087 501089 501095
78
+ 501500
79
+ 501879 502113 502301 503175
80
+ 503645 503670
81
+ 504310 504338 504363 504533 504587 504620 504639 504656 504738 504781 504910
82
+ 507001 507002 507004 507082 507090
83
+ 560014 560565 561033
84
+ 572402 572610 572626
85
+ 576904
86
+ 578614
87
+ 581149
88
+ 585274 585697
89
+ 586509
90
+ 588729 588792
91
+ 589244 589407 589471 589605 589633 589647 589671
92
+ 590043 590206 590263 590265 590278 590361 590362 590379 590393 590590
93
+ 591235 591420 591481 591620 591770 591948 591994
94
+ 592024 592161 592184 592186 592201 592384 592393 592528 592566 592704 592735 592879 592884
95
+ 593074 593264 593272 593355 593496 593556 593589 593666 593709 593825 593963 593994
96
+ 594184 594409 594468 594475 594581 594665 594691 594710 594874 594968
97
+ 595355 595364 595532 595547 595561 595568 595743 595929
98
+ 596245 596289 596399 596405 596590 596608 596645 596646 596791 596808 596815 596846
99
+ 597077 597094 597143 597370 597410 597765 597855 597862
100
+ 598053 598054 598395 598585 598793 598794 598815 598835 598838 598880 598889
101
+ 599000 599069 599089 599148 599191 599310 599741 599742 599867
102
+ 601070
103
+ 604983
104
+ 606126
105
+ 636380 636422 636502 636639
106
+ 637046 637756
107
+ 639130
108
+ 690032]
76
109
  )
77
110
 
78
111
  # https://www.mastercard.us/content/dam/mccom/global/documents/mastercard-rules.pdf, page 73
79
112
  MAESTRO_RANGES = [
113
+ (500032..500033),
114
+ (501015..501016),
115
+ (501020..501021),
116
+ (501023..501029),
117
+ (501038..501041),
118
+ (501053..501058),
119
+ (501060..501063),
120
+ (501066..501067),
121
+ (501080..501083),
122
+ (501091..501092),
123
+ (501104..501105),
124
+ (501107..501108),
125
+ (501104..501105),
126
+ (501107..501108),
80
127
  (561200..561269),
81
128
  (561271..561299),
82
129
  (561320..561356),
@@ -101,14 +148,14 @@ module ActiveMerchant #:nodoc:
101
148
 
102
149
  # https://dev.elo.com.br/apis/tabela-de-bins, download csv from left sidebar
103
150
  ELO_RANGES = [
104
- 506707..506708, 506715..506715, 506718..506722, 506724..506724, 506726..506736, 506739..506739, 506741..506743,
105
- 506745..506747, 506753..506753, 506774..506776, 506778..506778, 509000..509001, 509003..509003, 509007..509007,
106
- 509020..509022, 509035..509035, 509039..509042, 509045..509045, 509048..509048, 509051..509071, 509073..509074,
107
- 509077..509080, 509084..509089, 509091..509094, 509098..509098, 509100..509100, 509104..509104, 509106..509109,
108
- 509257..509257, 627780..627780, 636368..636368, 650031..650033, 650035..650045, 650047..650047, 650406..650410,
109
- 650434..650436, 650439..650439, 650485..650504, 650506..650530, 650577..650580, 650582..650591, 650721..650727,
110
- 650901..650922, 650928..650928, 650938..650939, 650946..650948, 650954..650955, 650962..650963, 650967..650967,
111
- 650971..650971, 651652..651667, 651675..651678, 655000..655010, 655012..655015, 655051..655052, 655056..655057
151
+ 506707..506708, 506715..506715, 506717..506722, 506724..506736, 506739..506743,
152
+ 506745..506747, 506753..506753, 506774..506778, 509000..509007, 509009..509014,
153
+ 509020..509030, 509035..509042, 509044..509089, 509091..509101, 509104..509807,
154
+ 509831..509877, 509897..509900, 509918..509964, 509971..509986, 509995..509999,
155
+ 627780..627780, 636368..636368, 650031..650033, 650035..650051, 650057..650081,
156
+ 650406..650439, 650485..650504, 650506..650538, 650552..650598, 650720..650727,
157
+ 650901..650922, 650928..650928, 650938..650939, 650946..650978, 651652..651704,
158
+ 655000..655019, 655021..655057
112
159
  ]
113
160
 
114
161
  # Alelo provides BIN ranges by e-mailing them out periodically.
@@ -227,7 +227,7 @@ module ActiveMerchant #:nodoc:
227
227
  end
228
228
 
229
229
  def add_merchant_data(post, options)
230
- post[:additionalData][:subMerchantId] = options[:sub_merchant_id] if options[:sub_merchant_id]
230
+ post[:additionalData][:subMerchantID] = options[:sub_merchant_id] if options[:sub_merchant_id]
231
231
  post[:additionalData][:subMerchantName] = options[:sub_merchant_name] if options[:sub_merchant_name]
232
232
  post[:additionalData][:subMerchantStreet] = options[:sub_merchant_street] if options[:sub_merchant_street]
233
233
  post[:additionalData][:subMerchantCity] = options[:sub_merchant_city] if options[:sub_merchant_city]
@@ -235,8 +235,8 @@ module ActiveMerchant #:nodoc:
235
235
  post[:additionalData][:subMerchantPostalCode] = options[:sub_merchant_postal_code] if options[:sub_merchant_postal_code]
236
236
  post[:additionalData][:subMerchantCountry] = options[:sub_merchant_country] if options[:sub_merchant_country]
237
237
  post[:additionalData][:subMerchantTaxId] = options[:sub_merchant_tax_id] if options[:sub_merchant_tax_id]
238
- post[:additionalData][:subMerchantId] = options[:sub_merchant_id] if options[:sub_merchant_id]
239
238
  post[:additionalData][:subMerchantMCC] = options[:sub_merchant_mcc] if options[:sub_merchant_mcc]
239
+ post[:additionalData] = post[:additionalData].merge(options[:sub_merchant_data]) if options[:sub_merchant_data]
240
240
  end
241
241
 
242
242
  def add_risk_data(post, options)
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+
2
3
  module ActiveMerchant #:nodoc:
3
4
  module Billing #:nodoc:
4
5
  # ==== Customer Information Manager (CIM)
@@ -319,7 +319,9 @@ module ActiveMerchant
319
319
  def add_fraud_info(doc, payment_method, options)
320
320
  doc.send('transaction-fraud-info') do
321
321
  doc.send('shopper-ip-address', options[:ip]) if options[:ip]
322
-
322
+ if fraud_info = options[:transaction_fraud_info]
323
+ doc.send('fraud-session-id', fraud_info[:fraud_session_id]) if fraud_info[:fraud_session_id]
324
+ end
323
325
  unless payment_method.is_a? String
324
326
  doc.send('shipping-contact-info') do
325
327
  add_shipping_contact_info(doc, payment_method, options)
@@ -583,6 +583,7 @@ module ActiveMerchant #:nodoc:
583
583
  parameters[:device_data] = options[:device_data] if options[:device_data]
584
584
  parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
585
585
 
586
+ add_account_type(parameters, options) if options[:account_type]
586
587
  add_skip_options(parameters, options)
587
588
  add_merchant_account_id(parameters, options)
588
589
 
@@ -609,6 +610,11 @@ module ActiveMerchant #:nodoc:
609
610
  parameters
610
611
  end
611
612
 
613
+ def add_account_type(parameters, options)
614
+ parameters[:options][:credit_card] = {}
615
+ parameters[:options][:credit_card][:account_type] = options[:account_type]
616
+ end
617
+
612
618
  def add_skip_options(parameters, options)
613
619
  parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking] if options[:skip_advanced_fraud_checking]
614
620
  parameters[:options][:skip_avs] = options[:skip_avs] if options[:skip_avs]
@@ -331,6 +331,7 @@ module ActiveMerchant #:nodoc:
331
331
  three_ds_2_options = options[:three_ds_2]
332
332
  browser_info = three_ds_2_options[:browser_info]
333
333
  post[:'3ds_initiate'] = options[:three_ds_initiate] || '01'
334
+ post[:f23] = options[:f23] if options[:f23]
334
335
  post[:'3ds_purchasedate'] = Time.now.utc.strftime('%Y%m%d%I%M%S')
335
336
  options.dig(:stored_credential, :initiator) == 'merchant' ? post[:'3ds_channel'] = '03' : post[:'3ds_channel'] = '02'
336
337
  post[:'3ds_redirect_url'] = three_ds_2_options[:notification_url]
@@ -256,8 +256,9 @@ module ActiveMerchant #:nodoc:
256
256
 
257
257
  private
258
258
 
259
- # Create all address hash key value pairs so that we still function if we
260
- # were only provided with one or two of them or even none
259
+ # Create all required address hash key value pairs
260
+ # If a value of nil is received, that value will be passed on to the gateway and will not be replaced with a default value
261
+ # Billing address fields received without an override value or with an empty string value will be replaced with the default_address values
261
262
  def setup_address_hash(options)
262
263
  default_address = {
263
264
  address1: 'Unspecified',
@@ -268,10 +269,20 @@ module ActiveMerchant #:nodoc:
268
269
  }
269
270
 
270
271
  submitted_address = options[:billing_address] || options[:address] || default_address
271
- options[:billing_address] = default_address.merge(submitted_address.symbolize_keys) { |_k, default, submitted| submitted.blank? ? default : submitted }
272
+ options[:billing_address] = default_address.merge(submitted_address.symbolize_keys) { |_k, default, submitted| check_billing_field_value(default, submitted) }
272
273
  options[:shipping_address] = options[:shipping_address] || {}
273
274
  end
274
275
 
276
+ def check_billing_field_value(default, submitted)
277
+ if submitted.nil?
278
+ nil
279
+ elsif submitted.blank?
280
+ default
281
+ else
282
+ submitted
283
+ end
284
+ end
285
+
275
286
  def build_auth_request(money, creditcard_or_reference, options)
276
287
  xml = Builder::XmlMarkup.new indent: 2
277
288
  add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
@@ -170,6 +170,12 @@ module ActiveMerchant #:nodoc:
170
170
  card_data[:security_code] = credit_card.verification_value if credit_card.verification_value?
171
171
  card_data[:card_holder_name] = credit_card.name if credit_card.name
172
172
 
173
+ # the device_unique_id has to be sent in via the card data (as device_unique_identifier) no other fraud detection fields require this
174
+ if options[:fraud_detection].present?
175
+ card_data[:fraud_detection] = {} if (options[:fraud_detection][:device_unique_id]).present?
176
+ card_data[:fraud_detection][:device_unique_identifier] = (options[:fraud_detection][:device_unique_id]) if (options[:fraud_detection][:device_unique_id]).present?
177
+ end
178
+
173
179
  # additional data used for Visa transactions
174
180
  card_data[:card_holder_door_number] = options[:card_holder_door_number].to_i if options[:card_holder_door_number]
175
181
  card_data[:card_holder_birthday] = options[:card_holder_birthday] if options[:card_holder_birthday]
@@ -210,6 +216,14 @@ module ActiveMerchant #:nodoc:
210
216
  hsh[:channel] = options[:channel] if valid_fraud_detection_option?(options[:channel])
211
217
  hsh[:dispatch_method] = options[:dispatch_method] if valid_fraud_detection_option?(options[:dispatch_method])
212
218
  hsh[:csmdds] = options[:csmdds] if valid_fraud_detection_option?(options[:csmdds])
219
+ hsh[:device_unique_id] = options[:device_unique_id] if valid_fraud_detection_option?(options[:device_unique_id])
220
+ hsh[:bill_to] = options[:bill_to] if valid_fraud_detection_option?(options[:bill_to])
221
+ hsh[:purchase_totals] = options[:purchase_totals] if valid_fraud_detection_option?(options[:purchase_totals])
222
+ hsh[:customer_in_site] = options[:customer_in_site] if valid_fraud_detection_option?(options[:customer_in_site])
223
+ hsh[:retail_transaction_data] = options[:retail_transaction_data] if valid_fraud_detection_option?(options[:retail_transaction_data])
224
+ hsh[:ship_to] = options[:ship_to] if valid_fraud_detection_option?(options[:ship_to])
225
+ hsh[:tax_voucher_required] = options[:tax_voucher_required] if valid_fraud_detection_option?(options[:tax_voucher_required])
226
+ hsh[:copy_paste_card_data] = options[:copy_paste_card_data] if valid_fraud_detection_option?(options[:copy_paste_card_data])
213
227
  end
214
228
  end
215
229
 
@@ -285,10 +285,12 @@ module ActiveMerchant #:nodoc:
285
285
 
286
286
  def add_auth_purchase_params(xml, options)
287
287
  xml.ssl_dynamic_dba options[:dba] if options.has_key?(:dba)
288
- xml.ssl_merchant_initiated_unscheduled options[:merchant_initiated_unscheduled] if options.has_key?(:merchant_initiated_unscheduled)
288
+ xml.ssl_merchant_initiated_unscheduled merchant_initiated_unscheduled(options) if merchant_initiated_unscheduled(options)
289
289
  xml.ssl_customer_code options[:customer] if options.has_key?(:customer)
290
290
  xml.ssl_customer_number options[:customer_number] if options.has_key?(:customer_number)
291
+ xml.ssl_entry_mode entry_mode(options) if entry_mode(options)
291
292
  add_custom_fields(xml, options) if options[:custom_fields]
293
+ add_stored_credential(xml, options) if options[:stored_credential]
292
294
  end
293
295
 
294
296
  def add_custom_fields(xml, options)
@@ -337,6 +339,32 @@ module ActiveMerchant #:nodoc:
337
339
  }
338
340
  end
339
341
 
342
+ def add_stored_credential(xml, options)
343
+ network_transaction_id = options.dig(:stored_credential, :network_transaction_id)
344
+ case
345
+ when network_transaction_id.nil?
346
+ return
347
+ when network_transaction_id.to_s.include?('|')
348
+ oar_data, ps2000_data = options[:stored_credential][:network_transaction_id].split('|')
349
+ xml.ssl_oar_data oar_data unless oar_data.nil? || oar_data.empty?
350
+ xml.ssl_ps2000_data ps2000_data unless ps2000_data.nil? || ps2000_data.empty?
351
+ when network_transaction_id.to_s.length > 22
352
+ xml.ssl_oar_data options.dig(:stored_credential, :network_transaction_id)
353
+ else
354
+ xml.ssl_ps2000_data options.dig(:stored_credential, :network_transaction_id)
355
+ end
356
+ end
357
+
358
+ def merchant_initiated_unscheduled(options)
359
+ return options[:merchant_initiated_unscheduled] if options[:merchant_initiated_unscheduled]
360
+ return 'Y' if options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
361
+ end
362
+
363
+ def entry_mode(options)
364
+ return options[:entry_mode] if options[:entry_mode]
365
+ return 12 if options[:stored_credential]
366
+ end
367
+
340
368
  def build_xml_request
341
369
  builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
342
370
  xml.txn do
@@ -362,10 +390,15 @@ module ActiveMerchant #:nodoc:
362
390
  authorization: authorization_from(response),
363
391
  error_code: response[:errorCode],
364
392
  avs_result: { code: response[:avs_response] },
365
- cvv_result: response[:cvv2_response]
393
+ cvv_result: response[:cvv2_response],
394
+ network_transaction_id: build_network_transaction_id(response)
366
395
  )
367
396
  end
368
397
 
398
+ def build_network_transaction_id(response)
399
+ "#{response[:oar_data]}|#{response[:ps2000_data]}"
400
+ end
401
+
369
402
  def headers
370
403
  {
371
404
  'Accept' => 'application/xml',
@@ -212,8 +212,8 @@ module ActiveMerchant #:nodoc:
212
212
  xml.tag! 'Expiry_Date', expdate(credit_card)
213
213
  xml.tag! 'CardHoldersName', credit_card.name
214
214
  xml.tag! 'CardType', card_type(credit_card.brand)
215
- xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id]
216
215
 
216
+ add_wallet_provider_id(xml, credit_card, options)
217
217
  add_credit_card_eci(xml, credit_card, options)
218
218
  add_credit_card_verification_strings(xml, credit_card, options)
219
219
  end
@@ -221,10 +221,9 @@ module ActiveMerchant #:nodoc:
221
221
 
222
222
  def add_credit_card_eci(xml, credit_card, options)
223
223
  eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == 'discover'
224
- # Discover requires any Apple Pay transaction, regardless of in-app
225
- # or web, and regardless of the ECI contained in the PKPaymentToken,
226
- # to have an ECI value explicitly of 04.
227
- '04'
224
+ # Payeezy requires an ECI of 5 for apple pay transactions
225
+ # See: https://support.payeezy.com/hc/en-us/articles/203730589-Ecommerce-Flag-Values
226
+ '05'
228
227
  else
229
228
  (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI
230
229
  end
@@ -276,10 +275,22 @@ module ActiveMerchant #:nodoc:
276
275
  xml.tag! 'Expiry_Date', expdate(credit_card)
277
276
  xml.tag! 'CardHoldersName', credit_card.name
278
277
  xml.tag! 'CardType', card_type(credit_card.brand)
279
- xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id]
278
+
279
+ add_wallet_provider_id(xml, credit_card, options)
280
280
  add_card_authentication_data(xml, options)
281
281
  end
282
282
 
283
+ def add_wallet_provider_id(xml, credit_card, options)
284
+ provider_id = if options[:wallet_provider_id]
285
+ options[:wallet_provider_id]
286
+ elsif credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay
287
+ # See: https://support.payeezy.com/hc/en-us/articles/206601408-First-Data-Payeezy-Gateway-Web-Service-API-Reference-Guide#3.9
288
+ 4
289
+ end
290
+
291
+ xml.tag! 'WalletProviderID', provider_id if provider_id
292
+ end
293
+
283
294
  def add_customer_data(xml, options)
284
295
  xml.tag! 'Customer_Ref', options[:customer] if options[:customer]
285
296
  xml.tag! 'Client_IP', options[:ip] if options[:ip]
@@ -210,7 +210,7 @@ module ActiveMerchant #:nodoc:
210
210
  def add_details(xml, options)
211
211
  xml.hps :AdditionalTxnFields do
212
212
  xml.hps :Description, options[:description] if options[:description]
213
- xml.hps :InvoiceNbr, options[:order_id] if options[:order_id]
213
+ xml.hps :InvoiceNbr, options[:order_id][0..59] if options[:order_id]
214
214
  xml.hps :CustomerID, options[:customer_id] if options[:customer_id]
215
215
  end
216
216
  end
@@ -5,7 +5,10 @@ module ActiveMerchant #:nodoc:
5
5
  class LitleGateway < Gateway
6
6
  SCHEMA_VERSION = '9.14'
7
7
 
8
+ class_attribute :postlive_url
9
+
8
10
  self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online'
11
+ self.postlive_url = 'https://payments.vantivpostlive.com/vap/communicator/online'
9
12
  self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online'
10
13
 
11
14
  self.supported_countries = ['US']
@@ -513,6 +516,8 @@ module ActiveMerchant #:nodoc:
513
516
  end
514
517
 
515
518
  def url
519
+ return postlive_url if @options[:url_override].to_s == 'postlive'
520
+
516
521
  test? ? test_url : live_url
517
522
  end
518
523
 
@@ -30,7 +30,7 @@ module ActiveMerchant #:nodoc:
30
30
  class OrbitalGateway < Gateway
31
31
  include Empty
32
32
 
33
- API_VERSION = '7.7'
33
+ API_VERSION = '8.1'
34
34
 
35
35
  POST_HEADERS = {
36
36
  'MIME-Version' => '1.1',
@@ -183,6 +183,37 @@ module ActiveMerchant #:nodoc:
183
183
 
184
184
  SENSITIVE_FIELDS = %i[account_num cc_account_num]
185
185
 
186
+ # Bank account types to be used for check processing
187
+ ACCOUNT_TYPE = {
188
+ 'savings' => 'S',
189
+ 'checking' => 'C'
190
+ }
191
+
192
+ # Fixed possible values for orbital ECP attributes
193
+ # Auth methods for electronic checks can be:
194
+ # Written, Internet, Telephonic, Account Receivable, Point of Purchase.
195
+ # Default auth method for ECP is Internet (I).
196
+ # Bank payment delivery can be either ACH (Automated Clearing House) or Best Possible.
197
+ # Default Bank Payment Delivery is Best Possible (B).
198
+ # Action codes to be used for Early Warning System and additional validations.
199
+ # Valid combinations of Message Type and Action Code to be used are:
200
+ # A W1
201
+ # AC W1
202
+ # FC W4
203
+ # R W6
204
+ # FC W8
205
+ # A W3
206
+ # AC W3
207
+ # FC W5
208
+ # R W7
209
+ # Default Action code for ECP is nil.
210
+ # Electronic check to be processed on same day (Y) or next day (N).
211
+ # Default ECP Same Day Index is Yes (Y).
212
+ ECP_AUTH_METHODS = %w[W I T A P]
213
+ ECP_BANK_PAYMENT = %w[A B]
214
+ ECP_ACTION_CODES = %w[LO ND NC W1 W3 W4 W5 W6 W7 W8 W9]
215
+ ECP_SAME_DAY = %w[Y N]
216
+
186
217
  def initialize(options = {})
187
218
  requires!(options, :merchant_id)
188
219
  requires!(options, :login, :password) unless options[:ip_authentication]
@@ -191,12 +222,12 @@ module ActiveMerchant #:nodoc:
191
222
  end
192
223
 
193
224
  # A – Authorization request
194
- def authorize(money, creditcard, options = {})
195
- order = build_new_order_xml(AUTH_ONLY, money, creditcard, options) do |xml|
196
- add_creditcard(xml, creditcard, options[:currency])
197
- add_address(xml, creditcard, options)
225
+ def authorize(money, payment_source, options = {})
226
+ order = build_new_order_xml(AUTH_ONLY, money, payment_source, options) do |xml|
227
+ add_payment_source(xml, payment_source, options)
228
+ add_address(xml, payment_source, options)
198
229
  if @options[:customer_profiles]
199
- add_customer_data(xml, creditcard, options)
230
+ add_customer_data(xml, payment_source, options)
200
231
  add_managed_billing(xml, options)
201
232
  end
202
233
  end
@@ -211,12 +242,12 @@ module ActiveMerchant #:nodoc:
211
242
  end
212
243
 
213
244
  # AC – Authorization and Capture
214
- def purchase(money, creditcard, options = {})
215
- order = build_new_order_xml(AUTH_AND_CAPTURE, money, creditcard, options) do |xml|
216
- add_creditcard(xml, creditcard, options[:currency])
217
- add_address(xml, creditcard, options)
245
+ def purchase(money, payment_source, options = {})
246
+ order = build_new_order_xml(options[:force_capture] ? FORCE_AUTH_AND_CAPTURE : AUTH_AND_CAPTURE, money, payment_source, options) do |xml|
247
+ add_payment_source(xml, payment_source, options)
248
+ add_address(xml, payment_source, options)
218
249
  if @options[:customer_profiles]
219
- add_customer_data(xml, creditcard, options)
250
+ add_customer_data(xml, payment_source, options)
220
251
  add_managed_billing(xml, options)
221
252
  end
222
253
  end
@@ -478,6 +509,31 @@ module ActiveMerchant #:nodoc:
478
509
  end
479
510
  end
480
511
 
512
+ # Payment can be done through either Credit Card or Electronic Check
513
+ def add_payment_source(xml, payment_source, options = {})
514
+ if payment_source.instance_of?(ActiveMerchant::Billing::Check)
515
+ add_echeck(xml, payment_source, options)
516
+ else
517
+ add_creditcard(xml, payment_source, options[:currency])
518
+ end
519
+ end
520
+
521
+ # Adds Electronic Check attributes
522
+ def add_echeck(xml, check, options = {})
523
+ xml.tag! :CardBrand, 'EC'
524
+ xml.tag! :CurrencyCode, currency_code(options[:currency])
525
+ xml.tag! :CurrencyExponent, currency_exponents(options[:currency])
526
+ unless check.nil?
527
+
528
+ xml.tag! :BCRtNum, check.routing_number
529
+ xml.tag! :CheckDDA, check.account_number if check.account_number
530
+ xml.tag! :BankAccountType, ACCOUNT_TYPE[check.account_type] if ACCOUNT_TYPE[check.account_type]
531
+ xml.tag! :ECPAuthMethod, options[:auth_method] if options[:auth_method] && ECP_AUTH_METHODS.include?(options[:auth_method])
532
+ xml.tag! :BankPmtDelv, options[:payment_delivery] if options[:payment_delivery] && ECP_BANK_PAYMENT.include?(options[:payment_delivery])
533
+ end
534
+ end
535
+
536
+ # Adds Credit Card attributes
481
537
  def add_creditcard(xml, creditcard, currency = nil)
482
538
  unless creditcard.nil?
483
539
  xml.tag! :AccountNum, creditcard.number
@@ -532,6 +588,24 @@ module ActiveMerchant #:nodoc:
532
588
  xml.tag!(:AAV, three_d_secure[:cavv])
533
589
  end
534
590
 
591
+ def add_mc_program_protocol(xml, creditcard, three_d_secure)
592
+ return unless three_d_secure && creditcard.brand == 'master'
593
+
594
+ xml.tag!(:MCProgramProtocol, three_d_secure[:version]) if three_d_secure[:version]
595
+ end
596
+
597
+ def add_mc_directory_trans_id(xml, creditcard, three_d_secure)
598
+ return unless three_d_secure && creditcard.brand == 'master'
599
+
600
+ xml.tag!(:MCDirectoryTransID, three_d_secure[:ds_transaction_id]) if three_d_secure[:ds_transaction_id]
601
+ end
602
+
603
+ def add_ucafind(xml, creditcard, three_d_secure)
604
+ return unless three_d_secure && creditcard.brand == 'master'
605
+
606
+ xml.tag! :UCAFInd, '4'
607
+ end
608
+
535
609
  def add_dpanind(xml, creditcard)
536
610
  return unless creditcard.is_a?(NetworkTokenizationCreditCard)
537
611
 
@@ -587,6 +661,18 @@ module ActiveMerchant #:nodoc:
587
661
  end
588
662
  end
589
663
 
664
+ # Adds ECP conditional attributes depending on other attribute values
665
+ def add_ecp_details(xml, parameters = {})
666
+ requires!(parameters, :check_serial_number) if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
667
+ xml.tag! :ECPActionCode, parameters[:action_code] if parameters[:action_code] && ECP_ACTION_CODES.include?(parameters[:action_code])
668
+ xml.tag! :ECPCheckSerialNumber, parameters[:check_serial_number] if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
669
+ if parameters[:auth_method]&.eql?('P')
670
+ xml.tag! :ECPTerminalCity, parameters[:terminal_city] if parameters[:terminal_city]
671
+ xml.tag! :ECPTerminalState, parameters[:terminal_state] if parameters[:terminal_state]
672
+ xml.tag! :ECPImageReferenceNumber, parameters[:image_reference_number] if parameters[:image_reference_number]
673
+ end
674
+ end
675
+
590
676
  def add_stored_credentials(xml, parameters)
591
677
  return unless parameters[:mit_stored_credential_ind] == 'Y' || parameters[:stored_credential] && !parameters[:stored_credential].values.all?(&:nil?)
592
678
 
@@ -695,7 +781,7 @@ module ActiveMerchant #:nodoc:
695
781
  @options[:ip_authentication] == true
696
782
  end
697
783
 
698
- def build_new_order_xml(action, money, creditcard, parameters = {})
784
+ def build_new_order_xml(action, money, payment_source, parameters = {})
699
785
  requires!(parameters, :order_id)
700
786
  xml = xml_envelope
701
787
  xml.tag! :Request do
@@ -720,9 +806,9 @@ module ActiveMerchant #:nodoc:
720
806
 
721
807
  three_d_secure = parameters[:three_d_secure]
722
808
 
723
- add_eci(xml, creditcard, three_d_secure)
724
- add_cavv(xml, creditcard, three_d_secure)
725
- add_xid(xml, creditcard, three_d_secure)
809
+ add_eci(xml, payment_source, three_d_secure)
810
+ add_cavv(xml, payment_source, three_d_secure)
811
+ add_xid(xml, payment_source, three_d_secure)
726
812
 
727
813
  xml.tag! :OrderID, format_order_id(parameters[:order_id])
728
814
  xml.tag! :Amount, amount(money)
@@ -731,7 +817,7 @@ module ActiveMerchant #:nodoc:
731
817
  add_level2_tax(xml, parameters)
732
818
  add_level2_advice_addendum(xml, parameters)
733
819
 
734
- add_aav(xml, creditcard, three_d_secure)
820
+ add_aav(xml, payment_source, three_d_secure)
735
821
  # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
736
822
 
737
823
  if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
@@ -740,9 +826,11 @@ module ActiveMerchant #:nodoc:
740
826
  add_soft_descriptors_from_hash(xml, parameters[:soft_descriptors])
741
827
  end
742
828
 
743
- add_dpanind(xml, creditcard)
744
- add_aevv(xml, creditcard, three_d_secure)
745
- add_digital_token_cryptogram(xml, creditcard)
829
+ add_dpanind(xml, payment_source)
830
+ add_aevv(xml, payment_source, three_d_secure)
831
+ add_digital_token_cryptogram(xml, payment_source)
832
+
833
+ xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && ECP_SAME_DAY.include?(parameters[:same_day]) && payment_source.instance_of?(ActiveMerchant::Billing::Check)
746
834
 
747
835
  set_recurring_ind(xml, parameters)
748
836
 
@@ -756,9 +844,13 @@ module ActiveMerchant #:nodoc:
756
844
  add_level3_purchase(xml, parameters)
757
845
  add_level3_tax(xml, parameters)
758
846
  add_line_items(xml, parameters) if parameters[:line_items]
847
+ add_ecp_details(xml, parameters) if payment_source.instance_of?(ActiveMerchant::Billing::Check)
759
848
  add_card_indicators(xml, parameters)
760
849
  add_stored_credentials(xml, parameters)
761
- add_pymt_brand_program_code(xml, creditcard, three_d_secure)
850
+ add_pymt_brand_program_code(xml, payment_source, three_d_secure)
851
+ add_mc_program_protocol(xml, payment_source, three_d_secure)
852
+ add_mc_directory_trans_id(xml, payment_source, three_d_secure)
853
+ add_ucafind(xml, payment_source, three_d_secure)
762
854
  end
763
855
  end
764
856
  xml.target!
@@ -247,16 +247,34 @@ module ActiveMerchant
247
247
  end
248
248
 
249
249
  def add_stored_credentials(params, options)
250
- if options[:sequence]
250
+ if options[:sequence] || options[:stored_credential]
251
251
  params[:stored_credentials] = {}
252
- params[:stored_credentials][:cardbrand_original_transaction_id] = options[:cardbrand_original_transaction_id] if options[:cardbrand_original_transaction_id]
253
- params[:stored_credentials][:sequence] = options[:sequence]
254
- params[:stored_credentials][:initiator] = options[:initiator] if options[:initiator]
255
- params[:stored_credentials][:is_scheduled] = options[:is_scheduled]
252
+ params[:stored_credentials][:cardbrand_original_transaction_id] = original_transaction_id(options) if original_transaction_id(options)
253
+ params[:stored_credentials][:initiator] = initiator(options) if initiator(options)
254
+ params[:stored_credentials][:sequence] = options[:sequence] || sequence(options[:stored_credential][:initial_transaction])
255
+ params[:stored_credentials][:is_scheduled] = options[:is_scheduled] || is_scheduled(options[:stored_credential][:reason_type])
256
256
  params[:stored_credentials][:auth_type_override] = options[:auth_type_override] if options[:auth_type_override]
257
257
  end
258
258
  end
259
259
 
260
+ def original_transaction_id(options)
261
+ return options[:cardbrand_original_transaction_id] if options[:cardbrand_original_transaction_id]
262
+ return options[:stored_credential][:network_transaction_id] if options.dig(:stored_credential, :network_transaction_id)
263
+ end
264
+
265
+ def initiator(options)
266
+ return options[:initiator] if options[:initiator]
267
+ return options[:stored_credential][:initiator].upcase if options.dig(:stored_credential, :initiator)
268
+ end
269
+
270
+ def sequence(initial_transaction)
271
+ initial_transaction ? 'FIRST' : 'SUBSEQUENT'
272
+ end
273
+
274
+ def is_scheduled(reason_type)
275
+ reason_type == 'recurring' ? 'true' : 'false'
276
+ end
277
+
260
278
  def commit(params, options)
261
279
  url = base_url(options) + endpoint(params)
262
280
 
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
9
9
 
10
10
  self.supported_countries = %w[MX EC CO BR CL PE]
11
11
  self.default_currency = 'USD'
12
- self.supported_cardtypes = %i[visa master american_express diners_club elo alia]
12
+ self.supported_cardtypes = %i[visa master american_express diners_club elo alia olimpica]
13
13
 
14
14
  self.homepage_url = 'https://secure.paymentez.com/'
15
15
  self.display_name = 'Paymentez'
@@ -175,9 +175,29 @@ module ActiveMerchant #:nodoc:
175
175
  extra_params = {}
176
176
  extra_params.merge!(options[:extra_params]) if options[:extra_params]
177
177
 
178
+ add_external_mpi_fields(extra_params, options)
179
+
178
180
  post['extra_params'] = extra_params unless extra_params.empty?
179
181
  end
180
182
 
183
+ def add_external_mpi_fields(extra_params, options)
184
+ three_d_secure_options = options[:three_d_secure]
185
+ return unless three_d_secure_options
186
+
187
+ auth_data = {
188
+ cavv: three_d_secure_options[:cavv],
189
+ xid: three_d_secure_options[:xid],
190
+ eci: three_d_secure_options[:eci],
191
+ version: three_d_secure_options[:version],
192
+ reference_id: three_d_secure_options[:three_ds_server_trans_id],
193
+ status: three_d_secure_options[:authentication_response_status] || three_d_secure_options[:directory_response_status]
194
+ }.compact
195
+
196
+ return if auth_data.empty?
197
+
198
+ extra_params[:auth_data] = auth_data
199
+ end
200
+
181
201
  def parse(body)
182
202
  JSON.parse(body)
183
203
  end
@@ -58,7 +58,7 @@ module ActiveMerchant #:nodoc:
58
58
  xml = Builder::XmlMarkup.new indent: 2
59
59
  xml.tag! transaction_type + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
60
60
  xml.tag! transaction_type + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
61
- xml.tag! 'n2:Version', API_VERSION
61
+ xml.tag! 'n2:Version', api_version(options)
62
62
  xml.tag! 'n2:' + transaction_type + 'RequestDetails' do
63
63
  xml.tag! 'n2:ReferenceID', reference_id if transaction_type == 'DoReferenceTransaction'
64
64
  xml.tag! 'n2:PaymentAction', action
@@ -73,6 +73,12 @@ module ActiveMerchant #:nodoc:
73
73
  xml.target!
74
74
  end
75
75
 
76
+ def api_version(options)
77
+ return API_VERSION_3DS2 if options.dig(:three_d_secure, :version) =~ /^2/
78
+
79
+ API_VERSION
80
+ end
81
+
76
82
  def add_credit_card(xml, credit_card, address, options)
77
83
  xml.tag! 'n2:CreditCard' do
78
84
  xml.tag! 'n2:CreditCardType', credit_card_type(card_brand(credit_card))
@@ -104,10 +110,12 @@ module ActiveMerchant #:nodoc:
104
110
  three_d_secure = options[:three_d_secure]
105
111
  xml.tag! 'ThreeDSecureRequest' do
106
112
  xml.tag! 'MpiVendor3ds', 'Y'
107
- xml.tag! 'AuthStatus3ds', three_d_secure[:trans_status] unless three_d_secure[:trans_status].blank?
113
+ xml.tag! 'AuthStatus3ds', three_d_secure[:authentication_response_status] || three_d_secure[:trans_status] if three_d_secure[:authentication_response_status] || three_d_secure[:trans_status]
108
114
  xml.tag! 'Cavv', three_d_secure[:cavv] unless three_d_secure[:cavv].blank?
109
115
  xml.tag! 'Eci3ds', three_d_secure[:eci] unless three_d_secure[:eci].blank?
110
116
  xml.tag! 'Xid', three_d_secure[:xid] unless three_d_secure[:xid].blank?
117
+ xml.tag! 'ThreeDSVersion', three_d_secure[:version] unless three_d_secure[:version].blank?
118
+ xml.tag! 'DSTransactionId', three_d_secure[:ds_transaction_id] unless three_d_secure[:ds_transaction_id].blank?
111
119
  end
112
120
  end
113
121
 
@@ -5,6 +5,7 @@ module ActiveMerchant #:nodoc:
5
5
  include Empty
6
6
 
7
7
  API_VERSION = '124'
8
+ API_VERSION_3DS2 = '214.0'
8
9
 
9
10
  URLS = {
10
11
  :test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
@@ -30,6 +30,7 @@ module ActiveMerchant #:nodoc:
30
30
  add_address(post, creditcard, options)
31
31
  add_capture(post, options)
32
32
  add_metadata(post, options)
33
+ add_3ds(post, options)
33
34
 
34
35
  commit(:post, 'charges', post, options)
35
36
  end
@@ -158,6 +159,16 @@ module ActiveMerchant #:nodoc:
158
159
  post[:metadata] = options[:metadata] if options[:metadata]
159
160
  end
160
161
 
162
+ def add_3ds(post, options)
163
+ if options[:three_d_secure]
164
+ post[:three_d_secure] = {}
165
+ post[:three_d_secure][:version] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
166
+ post[:three_d_secure][:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
167
+ post[:three_d_secure][:cavv] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
168
+ post[:three_d_secure][:transaction_id] = options[:three_d_secure][:ds_transaction_id] || options[:three_d_secure][:xid]
169
+ end
170
+ end
171
+
161
172
  def headers(params = {})
162
173
  result = {
163
174
  'Content-Type' => 'application/json',
@@ -203,6 +203,7 @@ module ActiveMerchant #:nodoc:
203
203
  add_payment(data, payment)
204
204
  add_external_mpi_fields(data, options)
205
205
  add_threeds(data, options) if options[:execute_threed]
206
+ add_stored_credential_options(data, options)
206
207
  data[:description] = options[:description]
207
208
  data[:store_in_vault] = options[:store]
208
209
  data[:sca_exemption] = options[:sca_exemption]
@@ -220,6 +221,7 @@ module ActiveMerchant #:nodoc:
220
221
  add_payment(data, payment)
221
222
  add_external_mpi_fields(data, options)
222
223
  add_threeds(data, options) if options[:execute_threed]
224
+ add_stored_credential_options(data, options)
223
225
  data[:description] = options[:description]
224
226
  data[:store_in_vault] = options[:store]
225
227
  data[:sca_exemption] = options[:sca_exemption]
@@ -331,18 +333,39 @@ module ActiveMerchant #:nodoc:
331
333
  return unless options[:three_d_secure]
332
334
 
333
335
  if options[:three_d_secure][:version] == THREE_DS_V2
334
- data[:threeDSServerTransID] = options[:three_d_secure][:xid] if options[:three_d_secure][:xid]
336
+ data[:threeDSServerTransID] = options[:three_d_secure][:three_ds_server_trans_id] if options[:three_d_secure][:three_ds_server_trans_id]
335
337
  data[:dsTransID] = options[:three_d_secure][:ds_transaction_id] if options[:three_d_secure][:ds_transaction_id]
336
338
  data[:authenticacionValue] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
337
339
  data[:protocolVersion] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
338
-
339
340
  data[:authenticacionMethod] = options[:authentication_method] if options[:authentication_method]
340
341
  data[:authenticacionType] = options[:authentication_type] if options[:authentication_type]
341
342
  data[:authenticacionFlow] = options[:authentication_flow] if options[:authentication_flow]
343
+ data[:eci_v2] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
342
344
  elsif options[:three_d_secure][:version] == THREE_DS_V1
343
345
  data[:txid] = options[:three_d_secure][:xid] if options[:three_d_secure][:xid]
344
346
  data[:cavv] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
345
- data[:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
347
+ data[:eci_v1] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
348
+ end
349
+ end
350
+
351
+ def add_stored_credential_options(data, options)
352
+ return unless options[:stored_credential]
353
+
354
+ case options[:stored_credential][:initial_transaction]
355
+ when true
356
+ data[:DS_MERCHANT_COF_INI] = 'S'
357
+ when false
358
+ data[:DS_MERCHANT_COF_INI] = 'N'
359
+ data[:DS_MERCHANT_COF_TXNID] = options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
360
+ end
361
+
362
+ case options[:stored_credential][:reason_type]
363
+ when 'recurring'
364
+ data[:DS_MERCHANT_COF_TYPE] = 'R'
365
+ when 'installment'
366
+ data[:DS_MERCHANT_COF_TYPE] = 'I'
367
+ when 'unscheduled'
368
+ return
346
369
  end
347
370
  end
348
371
 
@@ -487,6 +510,12 @@ module ActiveMerchant #:nodoc:
487
510
  xml.DS_MERCHANT_DIRECTPAYMENT 'moto' if options.dig(:moto) && options.dig(:metadata, :manual_entry)
488
511
 
489
512
  xml.DS_MERCHANT_EMV3DS data[:threeds].to_json if data[:threeds]
513
+
514
+ if options[:stored_credential]
515
+ xml.DS_MERCHANT_COF_INI data[:DS_MERCHANT_COF_INI]
516
+ xml.DS_MERCHANT_COF_TYPE data[:DS_MERCHANT_COF_TYPE]
517
+ xml.DS_MERCHANT_COF_TXNID data[:DS_MERCHANT_COF_TXNID] if data[:DS_MERCHANT_COF_TXNID]
518
+ end
490
519
  end
491
520
  end
492
521
 
@@ -496,13 +525,13 @@ module ActiveMerchant #:nodoc:
496
525
  ds_merchant_mpi_external = {}
497
526
  ds_merchant_mpi_external[:TXID] = data[:txid] if data[:txid]
498
527
  ds_merchant_mpi_external[:CAVV] = data[:cavv] if data[:cavv]
499
- ds_merchant_mpi_external[:ECI] = data[:eci] if data[:eci]
528
+ ds_merchant_mpi_external[:ECI] = data[:eci_v1] if data[:eci_v1]
500
529
 
501
530
  ds_merchant_mpi_external[:threeDSServerTransID] = data[:threeDSServerTransID] if data[:threeDSServerTransID]
502
531
  ds_merchant_mpi_external[:dsTransID] = data[:dsTransID] if data[:dsTransID]
503
532
  ds_merchant_mpi_external[:authenticacionValue] = data[:authenticacionValue] if data[:authenticacionValue]
504
533
  ds_merchant_mpi_external[:protocolVersion] = data[:protocolVersion] if data[:protocolVersion]
505
-
534
+ ds_merchant_mpi_external[:Eci] = data[:eci_v2] if data[:eci_v2]
506
535
  ds_merchant_mpi_external[:authenticacionMethod] = data[:authenticacionMethod] if data[:authenticacionMethod]
507
536
  ds_merchant_mpi_external[:authenticacionType] = data[:authenticacionType] if data[:authenticacionType]
508
537
  ds_merchant_mpi_external[:authenticacionFlow] = data[:authenticacionFlow] if data[:authenticacionFlow]
@@ -170,11 +170,13 @@ module ActiveMerchant #:nodoc:
170
170
  end
171
171
 
172
172
  def add_external_mpi_data(post, options)
173
+ version = options[:three_d_secure][:ds_transaction_id] ? '2' : '1'
174
+
173
175
  post[:sg_eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
174
176
  post[:sg_cavv] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
175
- post[:sg_dsTransID] = options[:three_d_secure][:ds_transaction_id] if options[:three_d_secure][:ds_transaction_id]
176
- post[:sg_threeDSProtocolVersion] = options[:three_d_secure][:version] || (options[:three_d_secure][:ds_transaction_id] ? '2' : '1')
177
- post[:sg_xid] = options[:three_d_secure][:xid]
177
+ post[:sg_dsTransID] = options[:three_d_secure][:ds_transaction_id] if version == '2'
178
+ post[:sg_threeDSProtocolVersion] = version
179
+ post[:sg_xid] = options[:three_d_secure][:xid] if version == '1'
178
180
  post[:sg_IsExternalMPI] = 1
179
181
  end
180
182
 
@@ -30,6 +30,7 @@ module ActiveMerchant #:nodoc:
30
30
  add_shipping_address(post, options)
31
31
  setup_future_usage(post, options)
32
32
  add_exemption(post, options)
33
+ add_error_on_requires_action(post, options)
33
34
  request_three_d_secure(post, options)
34
35
 
35
36
  CREATE_INTENT_ATTRIBUTES.each do |attribute|
@@ -269,6 +270,12 @@ module ActiveMerchant #:nodoc:
269
270
  post[:payment_method_options][:card][:moto] = true if options[:moto]
270
271
  end
271
272
 
273
+ def add_error_on_requires_action(post, options = {})
274
+ return unless options[:confirm]
275
+
276
+ post[:error_on_requires_action] = true if options[:error_on_requires_action]
277
+ end
278
+
272
279
  def request_three_d_secure(post, options = {})
273
280
  return unless options[:request_three_d_secure] && %w(any automatic).include?(options[:request_three_d_secure])
274
281
 
@@ -260,7 +260,10 @@ module ActiveMerchant #:nodoc:
260
260
  end
261
261
 
262
262
  def add_additional_3ds_data(xml, options)
263
- xml.additional3DSData 'dfReferenceId' => options[:session_id]
263
+ additional_data = { 'dfReferenceId' => options[:session_id] }
264
+ additional_data['challengeWindowSize'] = options[:browser_size] if options[:browser_size]
265
+
266
+ xml.additional3DSData additional_data
264
267
  end
265
268
 
266
269
  def add_3ds_exemption(xml, options)
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  end
5
5
 
6
6
  class Response
7
- attr_reader :params, :message, :test, :authorization, :avs_result, :cvv_result, :error_code, :emv_authorization
7
+ attr_reader :params, :message, :test, :authorization, :avs_result, :cvv_result, :error_code, :emv_authorization, :network_transaction_id
8
8
 
9
9
  def success?
10
10
  @success
@@ -25,6 +25,7 @@ module ActiveMerchant #:nodoc:
25
25
  @fraud_review = options[:fraud_review]
26
26
  @error_code = options[:error_code]
27
27
  @emv_authorization = options[:emv_authorization]
28
+ @network_transaction_id = options[:network_transaction_id]
28
29
 
29
30
  @avs_result = if options[:avs_result].kind_of?(AVSResult)
30
31
  options[:avs_result].to_hash
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.117.0'
2
+ VERSION = '1.118.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.117.0
4
+ version: 1.118.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-13 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport