activemerchant 1.94.0 → 1.99.0

Sign up to get free protection for your applications and to get access to all the features.
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])