activemerchant 1.117.0 → 1.118.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.
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