activemerchant 1.94.0 → 1.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +120 -1
  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 +65 -2
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +119 -34
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
  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 +2 -1
  16. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +37 -27
  18. data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +51 -11
  20. data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
  21. data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
  22. data/lib/active_merchant/billing/gateways/epay.rb +13 -2
  23. data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
  24. data/lib/active_merchant/billing/gateways/fat_zebra.rb +6 -0
  25. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
  26. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  27. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
  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 +33 -6
  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 +64 -14
  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/redsys.rb +113 -30
  44. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  45. data/lib/active_merchant/billing/gateways/stripe.rb +38 -9
  46. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
  47. data/lib/active_merchant/billing/gateways/tns.rb +10 -5
  48. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
  49. data/lib/active_merchant/billing/gateways/trust_commerce.rb +45 -6
  50. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
  51. data/lib/active_merchant/billing/gateways/worldpay.rb +177 -39
  52. data/lib/active_merchant/country.rb +1 -0
  53. data/lib/active_merchant/version.rb +1 -1
  54. metadata +19 -4
@@ -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
 
@@ -193,28 +193,32 @@ module ActiveMerchant #:nodoc:
193
193
  requires!(options, :order_id)
194
194
 
195
195
  data = {}
196
- add_action(data, :purchase)
196
+ add_action(data, :purchase, options)
197
197
  add_amount(data, money, options)
198
198
  add_order(data, options[:order_id])
199
199
  add_payment(data, payment)
200
+ add_threeds(data, options) if options[:execute_threed]
200
201
  data[:description] = options[:description]
201
202
  data[:store_in_vault] = options[:store]
203
+ data[:sca_exemption] = options[:sca_exemption]
202
204
 
203
- commit data
205
+ commit data, options
204
206
  end
205
207
 
206
208
  def authorize(money, payment, options = {})
207
209
  requires!(options, :order_id)
208
210
 
209
211
  data = {}
210
- add_action(data, :authorize)
212
+ add_action(data, :authorize, options)
211
213
  add_amount(data, money, options)
212
214
  add_order(data, options[:order_id])
213
215
  add_payment(data, payment)
216
+ add_threeds(data, options) if options[:execute_threed]
214
217
  data[:description] = options[:description]
215
218
  data[:store_in_vault] = options[:store]
219
+ data[:sca_exemption] = options[:sca_exemption]
216
220
 
217
- commit data
221
+ commit data, options
218
222
  end
219
223
 
220
224
  def capture(money, authorization, options = {})
@@ -225,7 +229,7 @@ module ActiveMerchant #:nodoc:
225
229
  add_order(data, order_id)
226
230
  data[:description] = options[:description]
227
231
 
228
- commit data
232
+ commit data, options
229
233
  end
230
234
 
231
235
  def void(authorization, options = {})
@@ -236,7 +240,7 @@ module ActiveMerchant #:nodoc:
236
240
  add_order(data, order_id)
237
241
  data[:description] = options[:description]
238
242
 
239
- commit data
243
+ commit data, options
240
244
  end
241
245
 
242
246
  def refund(money, authorization, options = {})
@@ -247,7 +251,7 @@ module ActiveMerchant #:nodoc:
247
251
  add_order(data, order_id)
248
252
  data[:description] = options[:description]
249
253
 
250
- commit data
254
+ commit data, options
251
255
  end
252
256
 
253
257
  def verify(creditcard, options = {})
@@ -278,8 +282,8 @@ module ActiveMerchant #:nodoc:
278
282
 
279
283
  private
280
284
 
281
- def add_action(data, action)
282
- data[:action] = transaction_code(action)
285
+ def add_action(data, action, options = {})
286
+ data[:action] = options[:execute_threed].present? ? '0' : transaction_code(action)
283
287
  end
284
288
 
285
289
  def add_amount(data, money, options)
@@ -295,6 +299,10 @@ module ActiveMerchant #:nodoc:
295
299
  test? ? test_url : live_url
296
300
  end
297
301
 
302
+ def threeds_url
303
+ test? ? 'https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2': 'https://sis.redsys.es/sis/services/SerClsWSEntradaV2'
304
+ end
305
+
298
306
  def add_payment(data, card)
299
307
  if card.is_a?(String)
300
308
  data[:credit_card_token] = card
@@ -311,21 +319,57 @@ module ActiveMerchant #:nodoc:
311
319
  end
312
320
  end
313
321
 
314
- def commit(data)
315
- parse(ssl_post(url, "entrada=#{CGI.escape(xml_request_from(data))}", headers))
322
+ def add_threeds(data, options)
323
+ if options[:execute_threed] == true
324
+ data[:threeds] = {threeDSInfo: 'CardData'}
325
+ end
326
+ end
327
+
328
+ def determine_3ds_action(threeds_hash)
329
+ return 'iniciaPeticion' if threeds_hash[:threeDSInfo] == 'CardData'
330
+ return 'trataPeticion' if threeds_hash[:threeDSInfo] == 'AuthenticationData' ||
331
+ threeds_hash[:threeDSInfo] == 'ChallengeResponse'
332
+ end
333
+
334
+ def commit(data, options = {})
335
+ if data[:threeds]
336
+ action = determine_3ds_action(data[:threeds])
337
+ request = <<-EOS
338
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://webservice.sis.sermepa.es" xmlns:intf="http://webservice.sis.sermepa.es" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
339
+ <soapenv:Header/>
340
+ <soapenv:Body>
341
+ <intf:#{action} xmlns:intf="http://webservice.sis.sermepa.es">
342
+ <intf:datoEntrada>
343
+ <![CDATA[#{xml_request_from(data, options)}]]>
344
+ </intf:datoEntrada>
345
+ </intf:#{action}>
346
+ </soapenv:Body>
347
+ </soapenv:Envelope>
348
+ EOS
349
+ parse(ssl_post(threeds_url, request, headers(action)), action)
350
+ else
351
+ parse(ssl_post(url, "entrada=#{CGI.escape(xml_request_from(data, options))}", headers), action)
352
+ end
316
353
  end
317
354
 
318
- def headers
319
- {
320
- 'Content-Type' => 'application/x-www-form-urlencoded'
321
- }
355
+ def headers(action=nil)
356
+ if action
357
+ {
358
+ 'Content-Type' => 'text/xml',
359
+ 'SOAPAction' => action
360
+ }
361
+ else
362
+ {
363
+ 'Content-Type' => 'application/x-www-form-urlencoded'
364
+ }
365
+ end
322
366
  end
323
367
 
324
- def xml_request_from(data)
368
+ def xml_request_from(data, options = {})
325
369
  if sha256_authentication?
326
- build_sha256_xml_request(data)
370
+ build_sha256_xml_request(data, options)
327
371
  else
328
- build_sha1_xml_request(data)
372
+ build_sha1_xml_request(data, options)
329
373
  end
330
374
  end
331
375
 
@@ -351,30 +395,30 @@ module ActiveMerchant #:nodoc:
351
395
  Digest::SHA1.hexdigest(str)
352
396
  end
353
397
 
354
- def build_sha256_xml_request(data)
398
+ def build_sha256_xml_request(data, options = {})
355
399
  xml = Builder::XmlMarkup.new
356
400
  xml.instruct!
357
401
  xml.REQUEST do
358
- build_merchant_data(xml, data)
402
+ build_merchant_data(xml, data, options)
359
403
  xml.DS_SIGNATUREVERSION 'HMAC_SHA256_V1'
360
- xml.DS_SIGNATURE sign_request(merchant_data_xml(data), data[:order_id])
404
+ xml.DS_SIGNATURE sign_request(merchant_data_xml(data, options), data[:order_id])
361
405
  end
362
406
  xml.target!
363
407
  end
364
408
 
365
- def build_sha1_xml_request(data)
409
+ def build_sha1_xml_request(data, options = {})
366
410
  xml = Builder::XmlMarkup.new :indent => 2
367
- build_merchant_data(xml, data)
411
+ build_merchant_data(xml, data, options)
368
412
  xml.target!
369
413
  end
370
414
 
371
- def merchant_data_xml(data)
415
+ def merchant_data_xml(data, options = {})
372
416
  xml = Builder::XmlMarkup.new
373
- build_merchant_data(xml, data)
417
+ build_merchant_data(xml, data, options)
374
418
  xml.target!
375
419
  end
376
420
 
377
- def build_merchant_data(xml, data)
421
+ def build_merchant_data(xml, data, options = {})
378
422
  xml.DATOSENTRADA do
379
423
  # Basic elements
380
424
  xml.DS_Version 0.1
@@ -383,9 +427,10 @@ module ActiveMerchant #:nodoc:
383
427
  xml.DS_MERCHANT_ORDER data[:order_id]
384
428
  xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
385
429
  xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
386
- xml.DS_MERCHANT_TERMINAL @options[:terminal]
430
+ xml.DS_MERCHANT_TERMINAL options[:terminal] || @options[:terminal]
387
431
  xml.DS_MERCHANT_MERCHANTCODE @options[:login]
388
432
  xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data) unless sha256_authentication?
433
+ xml.DS_MERCHANT_EXCEP_SCA data[:sca_exemption] if data[:sca_exemption]
389
434
 
390
435
  # Only when card is present
391
436
  if data[:card]
@@ -398,22 +443,42 @@ module ActiveMerchant #:nodoc:
398
443
  xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token]
399
444
  xml.DS_MERCHANT_DIRECTPAYMENT 'true'
400
445
  end
446
+
447
+ # Set moto flag only if explicitly requested via moto field
448
+ # Requires account configuration to be able to use
449
+ if options.dig(:moto) && options.dig(:metadata, :manual_entry)
450
+ xml.DS_MERCHANT_DIRECTPAYMENT 'moto'
451
+ end
452
+
453
+ if data[:threeds]
454
+ xml.DS_MERCHANT_EMV3DS data[:threeds].to_json
455
+ end
401
456
  end
402
457
  end
403
458
 
404
- def parse(data)
459
+ def parse(data, action)
405
460
  params = {}
406
461
  success = false
407
462
  message = ''
408
463
  options = @options.merge(:test => test?)
409
464
  xml = Nokogiri::XML(data)
410
465
  code = xml.xpath('//RETORNOXML/CODIGO').text
411
- if code == '0'
466
+
467
+ if ['iniciaPeticion', 'trataPeticion'].include?(action)
468
+ vxml = Nokogiri::XML(data).remove_namespaces!.xpath("//Envelope/Body/#{action}Response/#{action}Return").inner_text
469
+ xml = Nokogiri::XML(vxml)
470
+ node = (action == 'iniciaPeticion' ? 'INFOTARJETA' : 'OPERACION')
471
+ op = xml.xpath("//RETORNOXML/#{node}")
472
+ op.children.each do |element|
473
+ params[element.name.downcase.to_sym] = element.text
474
+ end
475
+ message = response_text_3ds(xml, params)
476
+ success = params.size > 0 && is_success_response?(params[:ds_response])
477
+ elsif code == '0'
412
478
  op = xml.xpath('//RETORNOXML/OPERACION')
413
479
  op.children.each do |element|
414
480
  params[element.name.downcase.to_sym] = element.text
415
481
  end
416
-
417
482
  if validate_signature(params)
418
483
  message = response_text(params[:ds_response])
419
484
  options[:authorization] = build_authorization(params)
@@ -474,6 +539,20 @@ module ActiveMerchant #:nodoc:
474
539
  RESPONSE_TEXTS[code] || 'Unkown code, please check in manual'
475
540
  end
476
541
 
542
+ def response_text_3ds(xml, params)
543
+ code = xml.xpath('//RETORNOXML/CODIGO').text
544
+ message = ''
545
+ if code != '0'
546
+ message = "#{code} ERROR"
547
+ elsif params[:ds_emv3ds]
548
+ three_ds_data = JSON.parse(params[:ds_emv3ds])
549
+ message = three_ds_data['threeDSInfo']
550
+ elsif params[:ds_response]
551
+ message = response_text(params[:ds_response])
552
+ end
553
+ message
554
+ end
555
+
477
556
  def is_success_response?(code)
478
557
  (code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i)
479
558
  end
@@ -523,6 +602,10 @@ module ActiveMerchant #:nodoc:
523
602
  xml_signed_fields += data[:ds_cardnumber]
524
603
  end
525
604
 
605
+ if data[:ds_emv3ds]
606
+ xml_signed_fields += data[:ds_emv3ds]
607
+ end
608
+
526
609
  xml_signed_fields + data[:ds_transactiontype] + data[:ds_securepayment]
527
610
  end
528
611
 
@@ -35,19 +35,13 @@ module ActiveMerchant #:nodoc:
35
35
  # Public: Run a purchase transaction.
36
36
  #
37
37
  # money - The monetary amount of the transaction in cents.
38
- # payment_method - The CreditCard or the Spreedly payment method token.
38
+ # payment_method - The CreditCard or Check or the Spreedly payment method token.
39
39
  # options - A hash of options:
40
40
  # :store - Retain the payment method if the purchase
41
41
  # succeeds. Defaults to false. (optional)
42
42
  def purchase(money, payment_method, options = {})
43
- if payment_method.is_a?(String)
44
- purchase_with_token(money, payment_method, options)
45
- else
46
- MultiResponse.run do |r|
47
- r.process { save_card(options[:store], payment_method, options) }
48
- r.process { purchase_with_token(money, r.authorization, options) }
49
- end
50
- end
43
+ request = build_transaction_request(money, payment_method, options)
44
+ commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
51
45
  end
52
46
 
53
47
  # Public: Run an authorize transaction.
@@ -58,14 +52,8 @@ module ActiveMerchant #:nodoc:
58
52
  # :store - Retain the payment method if the authorize
59
53
  # succeeds. Defaults to false. (optional)
60
54
  def authorize(money, payment_method, options = {})
61
- if payment_method.is_a?(String)
62
- authorize_with_token(money, payment_method, options)
63
- else
64
- MultiResponse.run do |r|
65
- r.process { save_card(options[:store], payment_method, options) }
66
- r.process { authorize_with_token(money, r.authorization, options) }
67
- end
68
- end
55
+ request = build_transaction_request(money, payment_method, options)
56
+ commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
69
57
  end
70
58
 
71
59
  def capture(money, authorization, options={})
@@ -79,6 +67,7 @@ module ActiveMerchant #:nodoc:
79
67
  def refund(money, authorization, options={})
80
68
  request = build_xml_request('transaction') do |doc|
81
69
  add_invoice(doc, money, options)
70
+ add_extra_options(:gateway_specific_fields, doc, options)
82
71
  end
83
72
 
84
73
  commit("transactions/#{authorization}/credit.xml", request)
@@ -155,32 +144,25 @@ module ActiveMerchant #:nodoc:
155
144
  end
156
145
 
157
146
  def purchase_with_token(money, payment_method_token, options)
158
- request = auth_purchase_request(money, payment_method_token, options)
147
+ request = build_transaction_request(money, payment_method_token, options)
159
148
  commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
160
149
  end
161
150
 
162
151
  def authorize_with_token(money, payment_method_token, options)
163
- request = auth_purchase_request(money, payment_method_token, options)
152
+ request = build_transaction_request(money, payment_method_token, options)
164
153
  commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
165
154
  end
166
155
 
167
156
  def verify_with_token(payment_method_token, options)
168
- request = build_xml_request('transaction') do |doc|
169
- add_invoice(doc, nil, options)
170
- doc.payment_method_token(payment_method_token)
171
- doc.retain_on_success(true) if options[:store]
172
- add_extra_options(:gateway_specific_fields, doc, options)
173
- end
174
-
157
+ request = build_transaction_request(nil, payment_method_token, options)
175
158
  commit("gateways/#{@options[:gateway_token]}/verify.xml", request)
176
159
  end
177
160
 
178
- def auth_purchase_request(money, payment_method_token, options)
161
+ def build_transaction_request(money, payment_method, options)
179
162
  build_xml_request('transaction') do |doc|
180
163
  add_invoice(doc, money, options)
164
+ add_payment_method(doc, payment_method, options)
181
165
  add_extra_options(:gateway_specific_fields, doc, options)
182
- doc.payment_method_token(payment_method_token)
183
- doc.retain_on_success(true) if options[:store]
184
166
  end
185
167
  end
186
168
 
@@ -190,6 +172,27 @@ module ActiveMerchant #:nodoc:
190
172
  doc.order_id(options[:order_id])
191
173
  doc.ip(options[:ip]) if options[:ip]
192
174
  doc.description(options[:description]) if options[:description]
175
+
176
+ if options[:merchant_name_descriptor]
177
+ doc.merchant_name_descriptor(options[:merchant_name_descriptor])
178
+ end
179
+ if options[:merchant_location_descriptor]
180
+ doc.merchant_location_descriptor(options[:merchant_location_descriptor])
181
+ end
182
+ end
183
+
184
+ def add_payment_method(doc, payment_method, options)
185
+ doc.retain_on_success(true) if options[:store]
186
+
187
+ if payment_method.is_a?(String)
188
+ doc.payment_method_token(payment_method)
189
+ elsif payment_method.is_a?(CreditCard)
190
+ add_credit_card(doc, payment_method, options)
191
+ elsif payment_method.is_a?(Check)
192
+ add_bank_account(doc, payment_method, options)
193
+ else
194
+ raise TypeError, 'Payment method not supported'
195
+ end
193
196
  end
194
197
 
195
198
  def add_credit_card(doc, credit_card, options)
@@ -210,6 +213,17 @@ module ActiveMerchant #:nodoc:
210
213
  end
211
214
  end
212
215
 
216
+ def add_bank_account(doc, bank_account, options)
217
+ doc.bank_account do
218
+ doc.first_name(bank_account.first_name)
219
+ doc.last_name(bank_account.last_name)
220
+ doc.bank_routing_number(bank_account.routing_number)
221
+ doc.bank_account_number(bank_account.account_number)
222
+ doc.bank_account_type(bank_account.account_type)
223
+ doc.bank_account_holder_type(bank_account.account_holder_type)
224
+ end
225
+ end
226
+
213
227
  def add_extra_options(type, doc, options)
214
228
  doc.send(type) do
215
229
  extra_options_to_doc(doc, options[type])