activemerchant 1.93.0 → 1.98.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +111 -0
  3. data/README.md +3 -0
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +6 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +67 -4
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +106 -22
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +2 -0
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
  12. data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -2
  13. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +56 -9
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +3 -1
  16. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
  18. data/lib/active_merchant/billing/gateways/credorax.rb +29 -3
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +30 -13
  20. data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
  21. data/lib/active_merchant/billing/gateways/decidir.rb +233 -0
  22. data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
  23. data/lib/active_merchant/billing/gateways/epay.rb +13 -2
  24. data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
  25. data/lib/active_merchant/billing/gateways/fat_zebra.rb +6 -0
  26. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
  27. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  28. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  29. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  31. data/lib/active_merchant/billing/gateways/monei.rb +31 -0
  32. data/lib/active_merchant/billing/gateways/mundipagg.rb +3 -2
  33. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  34. data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
  35. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  36. data/lib/active_merchant/billing/gateways/orbital.rb +60 -10
  37. data/lib/active_merchant/billing/gateways/payflow.rb +40 -2
  38. data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
  39. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  40. data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
  41. data/lib/active_merchant/billing/gateways/qvalent.rb +43 -1
  42. data/lib/active_merchant/billing/gateways/realex.rb +32 -9
  43. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  44. data/lib/active_merchant/billing/gateways/stripe.rb +54 -9
  45. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +267 -0
  46. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
  47. data/lib/active_merchant/billing/gateways/trust_commerce.rb +45 -6
  48. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
  49. data/lib/active_merchant/billing/gateways/worldpay.rb +171 -39
  50. data/lib/active_merchant/country.rb +1 -0
  51. data/lib/active_merchant/version.rb +1 -1
  52. metadata +19 -4
@@ -125,6 +125,9 @@ module ActiveMerchant #:nodoc:
125
125
 
126
126
  def purchase(money, payment, options={})
127
127
  # debit
128
+ if payment.is_a?(String)
129
+ options[:registrationId] = payment
130
+ end
128
131
  execute_dbpa(options[:risk_workflow] ? 'PA.CP': 'DB',
129
132
  money, payment, options)
130
133
  end
@@ -156,6 +159,10 @@ module ActiveMerchant #:nodoc:
156
159
  end
157
160
  end
158
161
 
162
+ def store(credit_card, options = {})
163
+ execute_store(credit_card, options.merge(store: true))
164
+ end
165
+
159
166
  def supports_scrubbing?
160
167
  true
161
168
  end
@@ -169,6 +176,15 @@ module ActiveMerchant #:nodoc:
169
176
 
170
177
  private
171
178
 
179
+ def execute_store(payment, options)
180
+ post = {}
181
+ add_payment_method(post, payment, options)
182
+ add_address(post, options)
183
+ add_options(post, options)
184
+ add_3d_secure(post, options)
185
+ commit(post, nil, options)
186
+ end
187
+
172
188
  def execute_dbpa(txtype, money, payment, options)
173
189
  post = {}
174
190
  post[:paymentType] = txtype
@@ -243,6 +259,7 @@ module ActiveMerchant #:nodoc:
243
259
  end
244
260
 
245
261
  def add_payment_method(post, payment, options)
262
+ return if payment.is_a?(String)
246
263
  if options[:registrationId]
247
264
  post[:card] = {
248
265
  cvv: payment.verification_value,
@@ -278,7 +295,9 @@ module ActiveMerchant #:nodoc:
278
295
  end
279
296
 
280
297
  def build_url(url, authorization, options)
281
- if options[:registrationId]
298
+ if options[:store]
299
+ url.gsub(/payments/, 'registrations')
300
+ elsif options[:registrationId]
282
301
  "#{url.gsub(/payments/, 'registrations')}/#{options[:registrationId]}/payments"
283
302
  elsif authorization
284
303
  "#{url}/#{authorization}"
@@ -465,16 +465,62 @@ module ActiveMerchant #:nodoc:
465
465
  end
466
466
  end
467
467
 
468
- def add_cdpt_eci_and_xid(xml, creditcard)
469
- xml.tag! :AuthenticationECIInd, creditcard.eci
470
- xml.tag! :XID, creditcard.transaction_id if creditcard.transaction_id
468
+ def add_eci(xml, creditcard, three_d_secure)
469
+ eci = if three_d_secure
470
+ three_d_secure[:eci]
471
+ elsif creditcard.is_a?(NetworkTokenizationCreditCard)
472
+ creditcard.eci
473
+ end
474
+
475
+ xml.tag!(:AuthenticationECIInd, eci) if eci
476
+ end
477
+
478
+ def add_xid(xml, creditcard, three_d_secure)
479
+ xid = if three_d_secure && creditcard.brand == 'visa'
480
+ three_d_secure[:xid]
481
+ elsif creditcard.is_a?(NetworkTokenizationCreditCard)
482
+ creditcard.transaction_id
483
+ end
484
+
485
+ xml.tag!(:XID, xid) if xid
486
+ end
487
+
488
+ def add_cavv(xml, creditcard, three_d_secure)
489
+ return unless three_d_secure && creditcard.brand == 'visa'
490
+
491
+ xml.tag!(:CAVV, three_d_secure[:cavv])
492
+ end
493
+
494
+ def add_aav(xml, creditcard, three_d_secure)
495
+ return unless three_d_secure && creditcard.brand == 'master'
496
+
497
+ xml.tag!(:AAV, three_d_secure[:cavv])
471
498
  end
472
499
 
473
- def add_cdpt_payment_cryptogram(xml, creditcard)
500
+ def add_dpanind(xml, creditcard)
501
+ return unless creditcard.is_a?(NetworkTokenizationCreditCard)
502
+
474
503
  xml.tag! :DPANInd, 'Y'
504
+ end
505
+
506
+ def add_digital_token_cryptogram(xml, creditcard)
507
+ return unless creditcard.is_a?(NetworkTokenizationCreditCard)
508
+
475
509
  xml.tag! :DigitalTokenCryptogram, creditcard.payment_cryptogram
476
510
  end
477
511
 
512
+ def add_aevv(xml, creditcard, three_d_secure)
513
+ return unless three_d_secure && creditcard.brand == 'american_express'
514
+
515
+ xml.tag!(:AEVV, three_d_secure[:cavv])
516
+ end
517
+
518
+ def add_pymt_brand_program_code(xml, creditcard, three_d_secure)
519
+ return unless three_d_secure && creditcard.brand == 'american_express'
520
+
521
+ xml.tag!(:PymtBrandProgramCode, 'ASK')
522
+ end
523
+
478
524
  def add_refund(xml, currency=nil)
479
525
  xml.tag! :AccountNum, nil
480
526
 
@@ -633,9 +679,11 @@ module ActiveMerchant #:nodoc:
633
679
 
634
680
  yield xml if block_given?
635
681
 
636
- if creditcard.is_a?(NetworkTokenizationCreditCard)
637
- add_cdpt_eci_and_xid(xml, creditcard)
638
- end
682
+ three_d_secure = parameters[:three_d_secure]
683
+
684
+ add_eci(xml, creditcard, three_d_secure)
685
+ add_cavv(xml, creditcard, three_d_secure)
686
+ add_xid(xml, creditcard, three_d_secure)
639
687
 
640
688
  xml.tag! :OrderID, format_order_id(parameters[:order_id])
641
689
  xml.tag! :Amount, amount(money)
@@ -644,11 +692,12 @@ module ActiveMerchant #:nodoc:
644
692
  add_level_2_tax(xml, parameters)
645
693
  add_level_2_advice_addendum(xml, parameters)
646
694
 
695
+ add_aav(xml, creditcard, three_d_secure)
647
696
  # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
648
697
 
649
- if creditcard.is_a?(NetworkTokenizationCreditCard)
650
- add_cdpt_payment_cryptogram(xml, creditcard)
651
- end
698
+ add_dpanind(xml, creditcard)
699
+ add_aevv(xml, creditcard, three_d_secure)
700
+ add_digital_token_cryptogram(xml, creditcard)
652
701
 
653
702
  if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
654
703
  add_soft_descriptors(xml, parameters[:soft_descriptors])
@@ -666,6 +715,7 @@ module ActiveMerchant #:nodoc:
666
715
 
667
716
  add_level_2_purchase(xml, parameters)
668
717
  add_stored_credentials(xml, parameters)
718
+ add_pymt_brand_program_code(xml, creditcard, three_d_secure)
669
719
  end
670
720
  end
671
721
  xml.target!
@@ -1,3 +1,4 @@
1
+ require 'nokogiri'
1
2
  require 'active_merchant/billing/gateways/payflow/payflow_common_api'
2
3
  require 'active_merchant/billing/gateways/payflow/payflow_response'
3
4
  require 'active_merchant/billing/gateways/payflow_express'
@@ -187,7 +188,44 @@ module ActiveMerchant #:nodoc:
187
188
  end
188
189
  end
189
190
  end
190
- xml.target!
191
+ add_level_two_three_fields(xml.target!, options)
192
+ end
193
+
194
+ def add_level_two_three_fields(xml_string, options)
195
+ if options[:level_two_fields] || options[:level_three_fields]
196
+ xml_doc = Nokogiri::XML.parse(xml_string)
197
+ %i[level_two_fields level_three_fields].each do |fields|
198
+ xml_string = add_fields(xml_doc, options[fields]) if options[fields]
199
+ end
200
+ end
201
+ xml_string
202
+ end
203
+
204
+ def check_fields(parent, fields, xml_doc)
205
+ fields.each do |k, v|
206
+ if v.is_a? String
207
+ new_node = Nokogiri::XML::Node.new(k, xml_doc)
208
+ new_node.add_child(v)
209
+ xml_doc.at_css(parent).add_child(new_node)
210
+ else
211
+ check_subparent_before_continuing(parent, k, xml_doc)
212
+ check_fields(k, v, xml_doc)
213
+ end
214
+ end
215
+ xml_doc
216
+ end
217
+
218
+ def check_subparent_before_continuing(parent, subparent, xml_doc)
219
+ unless xml_doc.at_css(subparent)
220
+ subparent_node = Nokogiri::XML::Node.new(subparent, xml_doc)
221
+ xml_doc.at_css(parent).add_child(subparent_node)
222
+ end
223
+ end
224
+
225
+ def add_fields(xml_doc, options_fields)
226
+ fields_to_add = JSON.parse(options_fields)
227
+ check_fields('Invoice', fields_to_add, xml_doc)
228
+ xml_doc.root.to_s
191
229
  end
192
230
 
193
231
  def build_check_request(action, money, check, options)
@@ -213,7 +251,7 @@ module ActiveMerchant #:nodoc:
213
251
  end
214
252
  end
215
253
  end
216
- xml.target!
254
+ add_level_two_three_fields(xml.target!, options)
217
255
  end
218
256
 
219
257
  def add_credit_card(xml, credit_card, options = {})
@@ -48,6 +48,11 @@ module ActiveMerchant #:nodoc:
48
48
  end
49
49
 
50
50
  def store(credit_card, options={})
51
+ # The store request requires a currency and amount of at least $1 USD.
52
+ # This is used for an authorization that is handled internally by Paymill.
53
+ options[:currency] = 'USD'
54
+ options[:money] = 100
55
+
51
56
  save_card(credit_card, options)
52
57
  end
53
58
 
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
9
9
  include PaypalRecurringApi
10
10
 
11
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
- self.supported_countries = ['US']
12
+ self.supported_countries = ['CA', 'NZ', 'GB', 'US']
13
13
  self.homepage_url = 'https://www.paypal.com/us/webapps/mpp/paypal-payments-pro'
14
14
  self.display_name = 'PayPal Payments Pro (US)'
15
15
 
@@ -90,6 +90,8 @@ module ActiveMerchant #:nodoc:
90
90
  xml.tag! 'n2:Payer', options[:email]
91
91
  add_address(xml, 'n2:Address', address)
92
92
  end
93
+
94
+ add_three_d_secure(xml, options) if options[:three_d_secure]
93
95
  end
94
96
  end
95
97
 
@@ -98,6 +100,17 @@ module ActiveMerchant #:nodoc:
98
100
  xml.tag! 'n2:SoftDescriptorCity', options[:soft_descriptor_city] unless options[:soft_descriptor_city].blank?
99
101
  end
100
102
 
103
+ def add_three_d_secure(xml, options)
104
+ three_d_secure = options[:three_d_secure]
105
+ xml.tag! 'ThreeDSecureRequest' do
106
+ xml.tag! 'MpiVendor3ds', 'Y'
107
+ xml.tag! 'AuthStatus3ds', three_d_secure[:trans_status] unless three_d_secure[:trans_status].blank?
108
+ xml.tag! 'Cavv', three_d_secure[:cavv] unless three_d_secure[:cavv].blank?
109
+ xml.tag! 'Eci3ds', three_d_secure[:eci] unless three_d_secure[:eci].blank?
110
+ xml.tag! 'Xid', three_d_secure[:xid] unless three_d_secure[:xid].blank?
111
+ end
112
+ end
113
+
101
114
  def credit_card_type(type)
102
115
  case type
103
116
  when 'visa' then 'Visa'
@@ -12,13 +12,15 @@ module ActiveMerchant #:nodoc:
12
12
  self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PA', 'PE']
13
13
  self.default_currency = 'USD'
14
14
  self.money_format = :dollars
15
- self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
15
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :naranja, :cabal]
16
16
 
17
17
  BRAND_MAP = {
18
18
  'visa' => 'VISA',
19
19
  'master' => 'MASTERCARD',
20
20
  'american_express' => 'AMEX',
21
- 'diners_club' => 'DINERS'
21
+ 'diners_club' => 'DINERS',
22
+ 'naranja' => 'NARANJA',
23
+ 'cabal' => 'CABAL'
22
24
  }
23
25
 
24
26
  MINIMUMS = {
@@ -195,6 +197,7 @@ module ActiveMerchant #:nodoc:
195
197
  buyer[:fullName] = buyer_hash[:name]
196
198
  buyer[:dniNumber] = buyer_hash[:dni_number]
197
199
  buyer[:dniType] = buyer_hash[:dni_type]
200
+ buyer[:merchantBuyerId] = buyer_hash[:merchant_buyer_id]
198
201
  buyer[:cnpj] = buyer_hash[:cnpj] if @options[:payment_country] == 'BR'
199
202
  buyer[:emailAddress] = buyer_hash[:email]
200
203
  buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
@@ -203,6 +206,7 @@ module ActiveMerchant #:nodoc:
203
206
  buyer[:fullName] = payment_method.name.strip
204
207
  buyer[:dniNumber] = options[:dni_number]
205
208
  buyer[:dniType] = options[:dni_type]
209
+ buyer[:merchantBuyerId] = options[:merchant_buyer_id]
206
210
  buyer[:cnpj] = options[:cnpj] if @options[:payment_country] == 'BR'
207
211
  buyer[:emailAddress] = options[:email]
208
212
  buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
@@ -27,6 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  add_order_number(post, options)
28
28
  add_payment_method(post, payment_method)
29
29
  add_verification_value(post, payment_method)
30
+ add_stored_credential_data(post, payment_method, options)
30
31
  add_customer_data(post, options)
31
32
  add_soft_descriptors(post, options)
32
33
 
@@ -39,6 +40,7 @@ module ActiveMerchant #:nodoc:
39
40
  add_order_number(post, options)
40
41
  add_payment_method(post, payment_method)
41
42
  add_verification_value(post, payment_method)
43
+ add_stored_credential_data(post, payment_method, options)
42
44
  add_customer_data(post, options)
43
45
  add_soft_descriptors(post, options)
44
46
 
@@ -61,6 +63,7 @@ module ActiveMerchant #:nodoc:
61
63
  add_reference(post, authorization, options)
62
64
  add_customer_data(post, options)
63
65
  add_soft_descriptors(post, options)
66
+ post['order.ECI'] = options[:eci] || 'SSL'
64
67
 
65
68
  commit('refund', post)
66
69
  end
@@ -124,7 +127,6 @@ module ActiveMerchant #:nodoc:
124
127
  def add_invoice(post, money, options)
125
128
  post['order.amount'] = amount(money)
126
129
  post['card.currency'] = CURRENCY_CODES[options[:currency] || currency(money)]
127
- post['order.ECI'] = options[:eci] || 'SSL'
128
130
  end
129
131
 
130
132
  def add_payment_method(post, payment_method)
@@ -134,6 +136,46 @@ module ActiveMerchant #:nodoc:
134
136
  post['card.expiryMonth'] = format(payment_method.month, :two_digits)
135
137
  end
136
138
 
139
+ def add_stored_credential_data(post, payment_method, options)
140
+ post['order.ECI'] = options[:eci] || eci(options)
141
+ if (stored_credential = options[:stored_credential]) && %w(visa master).include?(payment_method.brand)
142
+ post['card.posEntryMode'] = stored_credential[:initial_transaction] ? 'MANUAL' : 'STORED_CREDENTIAL'
143
+ stored_credential_usage(post, payment_method, options) unless stored_credential[:initiator] && stored_credential[:initiator] == 'cardholder'
144
+ post['order.authTraceId'] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
145
+ end
146
+ end
147
+
148
+ def stored_credential_usage(post, payment_method, options)
149
+ return unless payment_method.brand == 'visa'
150
+ stored_credential = options[:stored_credential]
151
+ if stored_credential[:initial_transaction]
152
+ post['card.storedCredentialUsage'] = 'INITIAL_STORAGE'
153
+ elsif stored_credential[:reason_type] == ('recurring' || 'installment')
154
+ post['card.storedCredentialUsage'] = 'RECURRING'
155
+ elsif stored_credential[:reason_type] == 'unscheduled'
156
+ post['card.storedCredentialUsage'] = 'UNSCHEDULED'
157
+ end
158
+ end
159
+
160
+ def eci(options)
161
+ if options.dig(:stored_credential, :initial_transaction)
162
+ 'SSL'
163
+ elsif options.dig(:stored_credential, :initiator) && options[:stored_credential][:initiator] == 'cardholder'
164
+ 'MTO'
165
+ elsif options.dig(:stored_credential, :reason_type)
166
+ case options[:stored_credential][:reason_type]
167
+ when 'recurring'
168
+ 'REC'
169
+ when 'installment'
170
+ 'INS'
171
+ when 'unscheduled'
172
+ 'MTO'
173
+ end
174
+ else
175
+ 'SSL'
176
+ end
177
+ end
178
+
137
179
  def add_verification_value(post, payment_method)
138
180
  post['card.CVN'] = payment_method.verification_value
139
181
  end
@@ -42,7 +42,8 @@ module ActiveMerchant
42
42
 
43
43
  def initialize(options = {})
44
44
  requires!(options, :login, :password)
45
- options[:refund_hash] = Digest::SHA1.hexdigest(options[:rebate_secret]) if options.has_key?(:rebate_secret)
45
+ options[:refund_hash] = Digest::SHA1.hexdigest(options[:rebate_secret]) if options[:rebate_secret].present?
46
+ options[:credit_hash] = Digest::SHA1.hexdigest(options[:refund_secret]) if options[:refund_secret].present?
46
47
  super
47
48
  end
48
49
 
@@ -70,9 +71,9 @@ module ActiveMerchant
70
71
  commit(request)
71
72
  end
72
73
 
73
- def credit(money, authorization, options = {})
74
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
75
- refund(money, authorization, options)
74
+ def credit(money, creditcard, options = {})
75
+ request = build_credit_request(money, creditcard, options)
76
+ commit(request)
76
77
  end
77
78
 
78
79
  def void(authorization, options = {})
@@ -184,6 +185,22 @@ module ActiveMerchant
184
185
  xml.target!
185
186
  end
186
187
 
188
+ def build_credit_request(money, credit_card, options)
189
+ timestamp = new_timestamp
190
+ xml = Builder::XmlMarkup.new :indent => 2
191
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'credit' do
192
+ add_merchant_details(xml, options)
193
+ xml.tag! 'orderid', sanitize_order_id(options[:order_id])
194
+ add_amount(xml, money, options)
195
+ add_card(xml, credit_card)
196
+ xml.tag! 'refundhash', @options[:credit_hash] if @options[:credit_hash]
197
+ xml.tag! 'autosettle', 'flag' => 1
198
+ add_comments(xml, options)
199
+ add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
200
+ end
201
+ xml.target!
202
+ end
203
+
187
204
  def build_void_request(authorization, options)
188
205
  timestamp = new_timestamp
189
206
  xml = Builder::XmlMarkup.new :indent => 2
@@ -289,12 +306,18 @@ module ActiveMerchant
289
306
  end
290
307
 
291
308
  def add_three_d_secure(xml, options)
292
- if options[:three_d_secure]
293
- xml.tag! 'mpi' do
294
- xml.tag! 'cavv', options[:three_d_secure][:cavv]
295
- xml.tag! 'eci', options[:three_d_secure][:eci]
296
- xml.tag! 'xid', options[:three_d_secure][:xid]
309
+ return unless three_d_secure = options[:three_d_secure]
310
+ version = three_d_secure.fetch(:version, '')
311
+ xml.tag! 'mpi' do
312
+ if version =~ /^2/
313
+ xml.tag! 'authentication_value', three_d_secure[:cavv]
314
+ xml.tag! 'ds_trans_id', three_d_secure[:ds_transaction_id]
315
+ else
316
+ xml.tag! 'cavv', three_d_secure[:cavv]
317
+ xml.tag! 'xid', three_d_secure[:xid]
297
318
  end
319
+ xml.tag! 'eci', three_d_secure[:eci]
320
+ xml.tag! 'message_version', version
298
321
  end
299
322
  end
300
323