activemerchant 1.62.0 → 1.79.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +420 -2
  3. data/README.md +1 -2
  4. data/lib/active_merchant/billing/credit_card.rb +13 -14
  5. data/lib/active_merchant/billing/credit_card_methods.rb +3 -1
  6. data/lib/active_merchant/billing/gateway.rb +25 -9
  7. data/lib/active_merchant/billing/gateways/adyen.rb +299 -0
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +168 -56
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +4 -2
  10. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +65 -22
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +87 -7
  12. data/lib/active_merchant/billing/gateways/beanstream.rb +2 -0
  13. data/lib/active_merchant/billing/gateways/blue_snap.rb +3 -8
  14. data/lib/active_merchant/billing/gateways/borgun.rb +10 -10
  15. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +1 -0
  16. data/lib/active_merchant/billing/gateways/braintree_blue.rb +49 -15
  17. data/lib/active_merchant/billing/gateways/card_connect.rb +286 -0
  18. data/lib/active_merchant/billing/gateways/card_stream.rb +97 -2
  19. data/lib/active_merchant/billing/gateways/cardprocess.rb +254 -0
  20. data/lib/active_merchant/billing/gateways/cashnet.rb +14 -2
  21. data/lib/active_merchant/billing/gateways/cenpos.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/checkout.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/checkout_v2.rb +44 -14
  24. data/lib/active_merchant/billing/gateways/citrus_pay.rb +0 -1
  25. data/lib/active_merchant/billing/gateways/clearhaus.rb +0 -2
  26. data/lib/active_merchant/billing/gateways/conekta.rb +4 -4
  27. data/lib/active_merchant/billing/gateways/creditcall.rb +71 -9
  28. data/lib/active_merchant/billing/gateways/credorax.rb +117 -5
  29. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  30. data/lib/active_merchant/billing/gateways/cyber_source.rb +54 -15
  31. data/lib/active_merchant/billing/gateways/data_cash.rb +12 -0
  32. data/lib/active_merchant/billing/gateways/dibs.rb +0 -1
  33. data/lib/active_merchant/billing/gateways/digitzs.rb +292 -0
  34. data/lib/active_merchant/billing/gateways/ebanx.rb +296 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +37 -95
  36. data/lib/active_merchant/billing/gateways/element.rb +11 -1
  37. data/lib/active_merchant/billing/gateways/fat_zebra.rb +3 -29
  38. data/lib/active_merchant/billing/gateways/first_pay.rb +12 -10
  39. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +37 -20
  40. data/lib/active_merchant/billing/gateways/forte.rb +0 -1
  41. data/lib/active_merchant/billing/gateways/global_collect.rb +55 -16
  42. data/lib/active_merchant/billing/gateways/global_transport.rb +16 -2
  43. data/lib/active_merchant/billing/gateways/hps.rb +12 -1
  44. data/lib/active_merchant/billing/gateways/iats_payments.rb +2 -2
  45. data/lib/active_merchant/billing/gateways/iveri.rb +251 -0
  46. data/lib/active_merchant/billing/gateways/jetpay.rb +12 -9
  47. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +437 -0
  48. data/lib/active_merchant/billing/gateways/kushki.rb +227 -0
  49. data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -2
  50. data/lib/active_merchant/billing/gateways/litle.rb +107 -30
  51. data/lib/active_merchant/billing/gateways/mercado_pago.rb +262 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +11 -0
  53. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +16 -4
  54. data/lib/active_merchant/billing/gateways/mercury.rb +14 -1
  55. data/lib/active_merchant/billing/gateways/migs.rb +28 -6
  56. data/lib/active_merchant/billing/gateways/moneris.rb +20 -12
  57. data/lib/active_merchant/billing/gateways/moneris_us.rb +11 -0
  58. data/lib/active_merchant/billing/gateways/mundipagg.rb +292 -0
  59. data/lib/active_merchant/billing/gateways/nab_transact.rb +4 -4
  60. data/lib/active_merchant/billing/gateways/netbanx.rb +60 -16
  61. data/lib/active_merchant/billing/gateways/netbilling.rb +0 -1
  62. data/lib/active_merchant/billing/gateways/nmi.rb +12 -1
  63. data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
  64. data/lib/active_merchant/billing/gateways/omise.rb +9 -5
  65. data/lib/active_merchant/billing/gateways/openpay.rb +13 -0
  66. data/lib/active_merchant/billing/gateways/opp.rb +124 -114
  67. data/lib/active_merchant/billing/gateways/optimal_payment.rb +14 -1
  68. data/lib/active_merchant/billing/gateways/orbital.rb +83 -14
  69. data/lib/active_merchant/billing/gateways/pay_hub.rb +2 -2
  70. data/lib/active_merchant/billing/gateways/payeezy.rb +152 -46
  71. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -2
  72. data/lib/active_merchant/billing/gateways/payflow.rb +24 -2
  73. data/lib/active_merchant/billing/gateways/payment_express.rb +3 -2
  74. data/lib/active_merchant/billing/gateways/paymentez.rb +276 -0
  75. data/lib/active_merchant/billing/gateways/paymill.rb +18 -10
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +14 -0
  77. data/lib/active_merchant/billing/gateways/paypal.rb +0 -12
  78. data/lib/active_merchant/billing/gateways/paystation.rb +14 -1
  79. data/lib/active_merchant/billing/gateways/payu_latam.rb +102 -62
  80. data/lib/active_merchant/billing/gateways/pin.rb +5 -0
  81. data/lib/active_merchant/billing/gateways/pro_pay.rb +326 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +12 -1
  83. data/lib/active_merchant/billing/gateways/qbms.rb +11 -0
  84. data/lib/active_merchant/billing/gateways/quickbooks.rb +10 -0
  85. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +21 -17
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +3 -3
  87. data/lib/active_merchant/billing/gateways/qvalent.rb +60 -3
  88. data/lib/active_merchant/billing/gateways/realex.rb +16 -6
  89. data/lib/active_merchant/billing/gateways/redsys.rb +8 -2
  90. data/lib/active_merchant/billing/gateways/safe_charge.rb +262 -0
  91. data/lib/active_merchant/billing/gateways/sage.rb +8 -3
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +29 -13
  93. data/lib/active_merchant/billing/gateways/secure_net.rb +11 -1
  94. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -0
  95. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  96. data/lib/active_merchant/billing/gateways/spreedly_core.rb +53 -7
  97. data/lib/active_merchant/billing/gateways/stripe.rb +84 -26
  98. data/lib/active_merchant/billing/gateways/tns.rb +0 -1
  99. data/lib/active_merchant/billing/gateways/trans_first.rb +3 -2
  100. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +61 -26
  101. data/lib/active_merchant/billing/gateways/trexle.rb +217 -0
  102. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +114 -9
  103. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +45 -22
  104. data/lib/active_merchant/billing/gateways/vanco.rb +1 -1
  105. data/lib/active_merchant/billing/gateways/wepay.rb +79 -46
  106. data/lib/active_merchant/billing/gateways/wirecard.rb +5 -4
  107. data/lib/active_merchant/billing/gateways/worldpay.rb +85 -20
  108. data/lib/active_merchant/billing/gateways/worldpay_us.rb +27 -8
  109. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  110. data/lib/active_merchant/connection.rb +48 -12
  111. data/lib/active_merchant/net_http_ssl_connection.rb +9 -0
  112. data/lib/active_merchant/network_connection_retries.rb +6 -4
  113. data/lib/active_merchant/posts_data.rb +11 -1
  114. data/lib/active_merchant/version.rb +1 -1
  115. data/lib/active_merchant.rb +2 -5
  116. data/lib/certs/cacert.pem +85 -0
  117. data/lib/support/ssl_version.rb +87 -0
  118. metadata +25 -9
  119. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
@@ -36,24 +36,25 @@ module ActiveMerchant
36
36
  }
37
37
 
38
38
  STANDARD_ERROR_CODE_MAPPING = {
39
- '36' => STANDARD_ERROR_CODE[:incorrect_number],
40
- '237' => STANDARD_ERROR_CODE[:invalid_number],
41
- '2315' => STANDARD_ERROR_CODE[:invalid_number],
42
- '37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
43
- '2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
44
- '378' => STANDARD_ERROR_CODE[:invalid_cvc],
45
- '38' => STANDARD_ERROR_CODE[:expired_card],
46
- '2317' => STANDARD_ERROR_CODE[:expired_card],
47
- '244' => STANDARD_ERROR_CODE[:incorrect_cvc],
48
- '227' => STANDARD_ERROR_CODE[:incorrect_address],
49
39
  '2127' => STANDARD_ERROR_CODE[:incorrect_address],
50
40
  '22' => STANDARD_ERROR_CODE[:card_declined],
41
+ '227' => STANDARD_ERROR_CODE[:incorrect_address],
51
42
  '23' => STANDARD_ERROR_CODE[:card_declined],
52
- '3153' => STANDARD_ERROR_CODE[:processing_error],
43
+ '2315' => STANDARD_ERROR_CODE[:invalid_number],
44
+ '2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
45
+ '2317' => STANDARD_ERROR_CODE[:expired_card],
53
46
  '235' => STANDARD_ERROR_CODE[:processing_error],
47
+ '237' => STANDARD_ERROR_CODE[:invalid_number],
54
48
  '24' => STANDARD_ERROR_CODE[:pickup_card],
49
+ '244' => STANDARD_ERROR_CODE[:incorrect_cvc],
55
50
  '300' => STANDARD_ERROR_CODE[:config_error],
56
- '384' => STANDARD_ERROR_CODE[:config_error]
51
+ '3153' => STANDARD_ERROR_CODE[:processing_error],
52
+ '3155' => STANDARD_ERROR_CODE[:unsupported_feature],
53
+ '36' => STANDARD_ERROR_CODE[:incorrect_number],
54
+ '37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
55
+ '378' => STANDARD_ERROR_CODE[:invalid_cvc],
56
+ '38' => STANDARD_ERROR_CODE[:expired_card],
57
+ '384' => STANDARD_ERROR_CODE[:config_error],
57
58
  }
58
59
 
59
60
  MARKET_TYPE = {
@@ -91,6 +92,7 @@ module ActiveMerchant
91
92
  APPLE_PAY_DATA_DESCRIPTOR = "COMMON.APPLE.INAPP.PAYMENT"
92
93
 
93
94
  PAYMENT_METHOD_NOT_SUPPORTED_ERROR = "155"
95
+ INELIGIBLE_FOR_ISSUING_CREDIT_ERROR = "54"
94
96
 
95
97
  def initialize(options={})
96
98
  requires!(options, :login, :password)
@@ -130,11 +132,20 @@ module ActiveMerchant
130
132
  end
131
133
 
132
134
  def refund(amount, authorization, options={})
133
- if auth_was_for_cim?(authorization)
135
+ response = if auth_was_for_cim?(authorization)
134
136
  cim_refund(amount, authorization, options)
135
137
  else
136
138
  normal_refund(amount, authorization, options)
137
139
  end
140
+
141
+ return response if response.success?
142
+ return response unless options[:force_full_refund_if_unsettled]
143
+
144
+ if response.params["response_reason_code"] == INELIGIBLE_FOR_ISSUING_CREDIT_ERROR
145
+ void(authorization, options)
146
+ else
147
+ response
148
+ end
138
149
  end
139
150
 
140
151
  def void(authorization, options={})
@@ -156,10 +167,10 @@ module ActiveMerchant
156
167
  xml.transactionType('refundTransaction')
157
168
  xml.amount(amount(amount))
158
169
 
159
- add_payment_source(xml, payment)
160
- add_invoice(xml, options)
170
+ add_payment_source(xml, payment, options, :credit)
171
+ xml.refTransId(transaction_id_from(options[:transaction_id])) if options[:transaction_id]
172
+ add_invoice(xml, 'refundTransaction', options)
161
173
  add_customer_data(xml, payment, options)
162
- add_line_items(xml, options)
163
174
  add_settings(xml, payment, options)
164
175
  add_user_fields(xml, amount, options)
165
176
  end
@@ -181,6 +192,12 @@ module ActiveMerchant
181
192
  end
182
193
  end
183
194
 
195
+ def unstore(authorization)
196
+ customer_profile_id, _, _ = split_authorization(authorization)
197
+
198
+ delete_customer_profile(customer_profile_id)
199
+ end
200
+
184
201
  def verify_credentials
185
202
  response = commit(:verify_credentials) { }
186
203
  response.success?
@@ -229,11 +246,15 @@ module ActiveMerchant
229
246
  xml.transactionRequest do
230
247
  xml.transactionType(transaction_type)
231
248
  xml.amount(amount(amount))
232
- add_payment_source(xml, payment)
233
- add_invoice(xml, options)
249
+ add_payment_source(xml, payment, options)
250
+ add_invoice(xml, transaction_type, options)
251
+ add_tax_fields(xml, options)
252
+ add_duty_fields(xml, options)
253
+ add_shipping_fields(xml, options)
254
+ add_tax_exempt_status(xml, options)
255
+ add_po_number(xml, options)
234
256
  add_customer_data(xml, payment, options)
235
257
  add_market_type_device_type(xml, payment, options)
236
- add_line_items(xml, options)
237
258
  add_settings(xml, payment, options)
238
259
  add_user_fields(xml, amount, options)
239
260
  end
@@ -244,8 +265,12 @@ module ActiveMerchant
244
265
  xml.transaction do
245
266
  xml.send(transaction_type) do
246
267
  xml.amount(amount(amount))
247
- add_payment_source(xml, payment)
248
- add_invoice(xml, options)
268
+ add_tax_fields(xml, options)
269
+ add_shipping_fields(xml, options)
270
+ add_duty_fields(xml, options)
271
+ add_payment_source(xml, payment, options)
272
+ add_invoice(xml, transaction_type, options)
273
+ add_tax_exempt_status(xml, options)
249
274
  end
250
275
  end
251
276
  end
@@ -256,6 +281,9 @@ module ActiveMerchant
256
281
  xml.transaction do
257
282
  xml.profileTransPriorAuthCapture do
258
283
  xml.amount(amount(amount))
284
+ add_tax_fields(xml, options)
285
+ add_shipping_fields(xml, options)
286
+ add_duty_fields(xml, options)
259
287
  xml.transId(transaction_id_from(authorization))
260
288
  end
261
289
  end
@@ -268,8 +296,13 @@ module ActiveMerchant
268
296
  xml.transactionRequest do
269
297
  xml.transactionType('priorAuthCaptureTransaction')
270
298
  xml.amount(amount(amount))
299
+ add_tax_fields(xml, options)
300
+ add_duty_fields(xml, options)
301
+ add_shipping_fields(xml, options)
302
+ add_tax_exempt_status(xml, options)
303
+ add_po_number(xml, options)
271
304
  xml.refTransId(transaction_id_from(authorization))
272
- add_invoice(xml, options)
305
+ add_invoice(xml, "capture", options)
273
306
  add_user_fields(xml, amount, options)
274
307
  end
275
308
  end
@@ -283,8 +316,11 @@ module ActiveMerchant
283
316
  xml.transaction do
284
317
  xml.profileTransRefund do
285
318
  xml.amount(amount(amount))
319
+ add_tax_fields(xml, options)
320
+ add_shipping_fields(xml, options)
321
+ add_duty_fields(xml, options)
286
322
  xml.creditCardNumberMasked(card_number)
287
- add_invoice(xml, options)
323
+ add_invoice(xml, "profileTransRefund", options)
288
324
  xml.transId(transaction_id)
289
325
  end
290
326
  end
@@ -306,7 +342,12 @@ module ActiveMerchant
306
342
  end
307
343
  xml.refTransId(transaction_id)
308
344
 
309
- add_invoice(xml, options)
345
+ add_invoice(xml, 'refundTransaction', options)
346
+ add_tax_fields(xml, options)
347
+ add_duty_fields(xml, options)
348
+ add_shipping_fields(xml, options)
349
+ add_tax_exempt_status(xml, options)
350
+ add_po_number(xml, options)
310
351
  add_customer_data(xml, nil, options)
311
352
  add_user_fields(xml, amount, options)
312
353
  end
@@ -334,29 +375,16 @@ module ActiveMerchant
334
375
  end
335
376
  end
336
377
 
337
- def add_payment_source(xml, source)
378
+ def add_payment_source(xml, source, options, action = nil)
338
379
  return unless source
339
380
  if source.is_a?(String)
340
- add_token_payment_method(xml, source)
381
+ add_token_payment_method(xml, source, options)
341
382
  elsif card_brand(source) == 'check'
342
383
  add_check(xml, source)
343
384
  elsif card_brand(source) == 'apple_pay'
344
385
  add_apple_pay_payment_token(xml, source)
345
386
  else
346
- add_credit_card(xml, source)
347
- end
348
- end
349
-
350
- def add_line_items(xml, options)
351
- return unless options[:line_items]
352
- xml.lineItems do
353
- options[:line_items].each do |line_item|
354
- xml.lineItem do
355
- line_item.each do |key, value|
356
- xml.send(camel_case_lower(key), value)
357
- end
358
- end
359
- end
387
+ add_credit_card(xml, source, action)
360
388
  end
361
389
  end
362
390
 
@@ -384,10 +412,10 @@ module ActiveMerchant
384
412
  ActiveMerchant.deprecated "Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead."
385
413
  set_duplicate_window(xml, self.class.duplicate_window)
386
414
  end
387
- if options[:email_customer]
415
+ if options.key?(:email_customer)
388
416
  xml.setting do
389
417
  xml.settingName("emailCustomer")
390
- xml.settingValue("true")
418
+ xml.settingValue(options[:email_customer] ? "true" : "false")
391
419
  end
392
420
  end
393
421
  if options[:header_email_receipt]
@@ -396,6 +424,12 @@ module ActiveMerchant
396
424
  xml.settingValue(options[:header_email_receipt])
397
425
  end
398
426
  end
427
+ if options[:test_request]
428
+ xml.setting do
429
+ xml.settingName("testRequest")
430
+ xml.settingValue("1")
431
+ end
432
+ end
399
433
  end
400
434
  end
401
435
 
@@ -423,7 +457,7 @@ module ActiveMerchant
423
457
  end
424
458
  end
425
459
 
426
- def add_credit_card(xml, credit_card)
460
+ def add_credit_card(xml, credit_card, action)
427
461
  if credit_card.track_data
428
462
  add_swipe_data(xml, credit_card)
429
463
  else
@@ -434,7 +468,7 @@ module ActiveMerchant
434
468
  if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand)
435
469
  xml.cardCode(credit_card.verification_value)
436
470
  end
437
- if credit_card.is_a?(NetworkTokenizationCreditCard)
471
+ if credit_card.is_a?(NetworkTokenizationCreditCard) && action != :credit
438
472
  xml.cryptogram(credit_card.payment_cryptogram)
439
473
  end
440
474
  end
@@ -455,8 +489,10 @@ module ActiveMerchant
455
489
  end
456
490
  end
457
491
 
458
- def add_token_payment_method(xml, token)
492
+ def add_token_payment_method(xml, token, options)
459
493
  customer_profile_id, customer_payment_profile_id, _ = split_authorization(token)
494
+ customer_profile_id = options[:customer_profile_id] if options[:customer_profile_id]
495
+ customer_payment_profile_id = options[:customer_payment_profile_id] if options[:customer_payment_profile_id]
460
496
  xml.customerProfileId(customer_profile_id)
461
497
  xml.customerPaymentProfileId(customer_payment_profile_id)
462
498
  end
@@ -508,7 +544,7 @@ module ActiveMerchant
508
544
 
509
545
  def add_customer_data(xml, payment_source, options)
510
546
  xml.customer do
511
- xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\d+$/
547
+ xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\w+$/
512
548
  xml.email(options[:email]) unless empty?(options[:email])
513
549
  end
514
550
 
@@ -518,8 +554,11 @@ module ActiveMerchant
518
554
  xml.customerIP(options[:ip]) unless empty?(options[:ip])
519
555
 
520
556
  xml.cardholderAuthentication do
521
- xml.authenticationIndicator(options[:authentication_indicator])
522
- xml.cardholderAuthenticationValue(options[:cardholder_authentication_value])
557
+ three_d_secure = options.fetch(:three_d_secure, {})
558
+ xml.authenticationIndicator(
559
+ options[:authentication_indicator] || three_d_secure[:eci])
560
+ xml.cardholderAuthenticationValue(
561
+ options[:cardholder_authentication_value] || three_d_secure[:cavv])
523
562
  end
524
563
  end
525
564
 
@@ -528,13 +567,15 @@ module ActiveMerchant
528
567
 
529
568
  xml.billTo do
530
569
  first_name, last_name = names_from(payment_source, address, options)
570
+ state = state_from(address, options)
571
+ full_address = "#{address[:address1]} #{address[:address2]}".strip
572
+
531
573
  xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
532
574
  xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
533
-
534
575
  xml.company(truncate(address[:company], 50)) unless empty?(address[:company])
535
- xml.address(truncate(address[:address1], 60))
576
+ xml.address(truncate(full_address, 60))
536
577
  xml.city(truncate(address[:city], 40))
537
- xml.state(empty?(address[:state]) ? 'n/a' : truncate(address[:state], 40))
578
+ xml.state(truncate(state, 40))
538
579
  xml.zip(truncate((address[:zip] || options[:zip]), 20))
539
580
  xml.country(truncate(address[:country], 60))
540
581
  xml.phoneNumber(truncate(address[:phone], 25)) unless empty?(address[:phone])
@@ -552,12 +593,12 @@ module ActiveMerchant
552
593
  else
553
594
  [address[:first_name], address[:last_name]]
554
595
  end
596
+ full_address = "#{address[:address1]} #{address[:address2]}".strip
555
597
 
556
598
  xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
557
599
  xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
558
-
559
600
  xml.company(truncate(address[:company], 50)) unless empty?(address[:company])
560
- xml.address(truncate(address[:address1], 60))
601
+ xml.address(truncate(full_address, 60))
561
602
  xml.city(truncate(address[:city], 40))
562
603
  xml.state(truncate(address[:state], 40))
563
604
  xml.zip(truncate(address[:zip], 20))
@@ -570,13 +611,68 @@ module ActiveMerchant
570
611
  xml.refId(truncate(options[:order_id], 20))
571
612
  end
572
613
 
573
- def add_invoice(xml, options)
614
+ def add_invoice(xml, transaction_type, options)
574
615
  xml.order do
575
616
  xml.invoiceNumber(truncate(options[:order_id], 20))
576
617
  xml.description(truncate(options[:description], 255))
618
+ xml.purchaseOrderNumber(options[:po_number]) if options[:po_number] && transaction_type.start_with?("profileTrans")
619
+ end
620
+
621
+ # Authorize.net API requires lineItems to be placed directly after order tag
622
+ if options[:line_items]
623
+ xml.lineItems do
624
+ options[:line_items].each do |line_item|
625
+ xml.lineItem do
626
+ line_item.each do |key, value|
627
+ xml.send(camel_case_lower(key), value)
628
+ end
629
+ end
630
+ end
631
+ end
632
+ end
633
+ end
634
+
635
+ def add_tax_fields(xml, options)
636
+ tax = options[:tax]
637
+ if tax.is_a?(Hash)
638
+ xml.tax do
639
+ xml.amount(amount(tax[:amount].to_i))
640
+ xml.name(tax[:name])
641
+ xml.description(tax[:description])
642
+ end
643
+ end
644
+ end
645
+
646
+ def add_duty_fields(xml, options)
647
+ duty = options[:duty]
648
+ if duty.is_a?(Hash)
649
+ xml.duty do
650
+ xml.amount(amount(duty[:amount].to_i))
651
+ xml.name(duty[:name])
652
+ xml.description(duty[:description])
653
+ end
577
654
  end
578
655
  end
579
656
 
657
+ def add_shipping_fields(xml, options)
658
+ shipping = options[:shipping]
659
+ if shipping.is_a?(Hash)
660
+ xml.shipping do
661
+ xml.amount(amount(shipping[:amount].to_i))
662
+ xml.name(shipping[:name])
663
+ xml.description(shipping[:description])
664
+ end
665
+ end
666
+ end
667
+
668
+ def add_tax_exempt_status(xml, options)
669
+ xml.taxExempt(options[:tax_exempt]) if options[:tax_exempt]
670
+ end
671
+
672
+ def add_po_number(xml, options)
673
+ xml.poNumber(options[:po_number]) if options[:po_number]
674
+ end
675
+
580
676
  def create_customer_payment_profile(credit_card, options)
581
677
  commit(:cim_store_update) do |xml|
582
678
  xml.customerProfileId options[:customer_profile_id]
@@ -616,6 +712,12 @@ module ActiveMerchant
616
712
  end
617
713
  end
618
714
 
715
+ def delete_customer_profile(customer_profile_id)
716
+ commit(:cim_store_delete_customer) do |xml|
717
+ xml.customerProfileId(customer_profile_id)
718
+ end
719
+ end
720
+
619
721
  def names_from(payment_source, address, options)
620
722
  if payment_source && !payment_source.is_a?(PaymentToken) && !payment_source.is_a?(String)
621
723
  first_name, last_name = split_names(address[:name])
@@ -625,6 +727,14 @@ module ActiveMerchant
625
727
  end
626
728
  end
627
729
 
730
+ def state_from(address, options)
731
+ if ["US", "CA"].include?(address[:country])
732
+ address[:state] || 'NC'
733
+ else
734
+ address[:state] || 'n/a'
735
+ end
736
+ end
737
+
628
738
  def headers
629
739
  { 'Content-Type' => 'text/xml' }
630
740
  end
@@ -683,6 +793,8 @@ module ActiveMerchant
683
793
  "createCustomerProfileRequest"
684
794
  elsif action == :cim_store_update
685
795
  "createCustomerPaymentProfileRequest"
796
+ elsif action == :cim_store_delete_customer
797
+ "deleteCustomerProfileRequest"
686
798
  elsif action == :verify_credentials
687
799
  "authenticateTestRequest"
688
800
  elsif is_cim_action?(action)
@@ -798,7 +910,7 @@ module ActiveMerchant
798
910
  if cim?(action) || (action == :verify_credentials)
799
911
  response[:result_code] == "Ok"
800
912
  else
801
- response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
913
+ [APPROVED, FRAUD_REVIEW].include?(response[:response_code]) && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
802
914
  end
803
915
  end
804
916
 
@@ -827,7 +939,7 @@ module ActiveMerchant
827
939
  end
828
940
 
829
941
  def cim?(action)
830
- (action == :cim_store) || (action == :cim_store_update)
942
+ (action == :cim_store) || (action == :cim_store_update) || (action == :cim_store_delete_customer)
831
943
  end
832
944
 
833
945
  def transaction_id_from(authorization)
@@ -858,7 +858,9 @@ module ActiveMerchant #:nodoc:
858
858
 
859
859
  response_params = parse(action, xml)
860
860
 
861
- message = response_params['messages']['message']['text']
861
+ message_element= response_params["messages"]["message"]
862
+ first_error = message_element.is_a?(Array) ? message_element.first : message_element
863
+ message = first_error['text']
862
864
  test_mode = @options[:test_requests] || message =~ /Test Mode/
863
865
  success = response_params['messages']['result_code'] == 'Ok'
864
866
  response_params['direct_response'] = parse_direct_response(response_params['direct_response']) if response_params['direct_response']
@@ -867,7 +869,7 @@ module ActiveMerchant #:nodoc:
867
869
  response_options = {}
868
870
  response_options[:test] = test_mode
869
871
  response_options[:authorization] = transaction_id || response_params['customer_profile_id'] || (response_params['profile'] ? response_params['profile']['customer_profile_id'] : nil)
870
- response_options[:error_code] = response_params['messages']['message']['code'] unless success
872
+ response_options[:error_code] = first_error['code'] unless success
871
873
 
872
874
  Response.new(success, message, response_params, response_options)
873
875
  end
@@ -4,8 +4,9 @@ module ActiveMerchant #:nodoc:
4
4
  self.test_url = 'https://pal-test.barclaycardsmartpay.com/pal/servlet'
5
5
  self.live_url = 'https://pal-live.barclaycardsmartpay.com/pal/servlet'
6
6
 
7
- self.supported_countries = ['AL', 'AD', 'AM', 'AT', 'AZ', 'BY', 'BE', 'BA', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'GE', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'KZ', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'MD', 'MC', 'ME', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'SM', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'TR', 'UA', 'GB', 'VA']
7
+ self.supported_countries = ['AL', 'AD', 'AM', 'AT', 'AZ', 'BY', 'BE', 'BA', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'KZ', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'MD', 'MC', 'ME', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'SM', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'TR', 'UA', 'GB', 'VA']
8
8
  self.default_currency = 'EUR'
9
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
9
10
  self.money_format = :cents
10
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro]
11
12
 
@@ -32,15 +33,9 @@ module ActiveMerchant #:nodoc:
32
33
  post = payment_request(money, options)
33
34
  post[:amount] = amount_hash(money, options[:currency])
34
35
  post[:card] = credit_card_hash(creditcard)
35
-
36
- if address = (options[:billing_address] || options[:address])
37
- post[:billingAddress] = address_hash(address)
38
- end
39
-
40
- if options[:shipping_address]
41
- post[:deliveryAddress] = address_hash(options[:shipping_address])
42
- end
43
-
36
+ post[:billingAddress] = billing_address_hash(options) if options[:billing_address]
37
+ post[:deliveryAddress] = shipping_address_hash(options) if options[:shipping_address]
38
+ add_3ds(post, options) if options[:execute_threed]
44
39
  commit('authorise', post)
45
40
  end
46
41
 
@@ -66,6 +61,10 @@ module ActiveMerchant #:nodoc:
66
61
  post = payment_request(money, options)
67
62
  post[:amount] = amount_hash(money, options[:currency])
68
63
  post[:card] = credit_card_hash(creditcard)
64
+ post[:dateOfBirth] = options[:date_of_birth] if options[:date_of_birth]
65
+ post[:entityType] = options[:entity_type] if options[:entity_type]
66
+ post[:nationality] = options[:nationality] if options[:nationality]
67
+ post[:shopperName] = options[:shopper_name] if options[:shopper_name]
69
68
 
70
69
  commit('refundWithData', post)
71
70
  end
@@ -138,7 +137,7 @@ module ActiveMerchant #:nodoc:
138
137
  response,
139
138
  test: test?,
140
139
  avs_result: AVSResult.new(:code => parse_avs_code(response)),
141
- authorization: response['recurringDetailReference'] || response['pspReference']
140
+ authorization: response['recurringDetailReference'] || authorization_from(post, response)
142
141
  )
143
142
 
144
143
  rescue ResponseError => e
@@ -157,6 +156,13 @@ module ActiveMerchant #:nodoc:
157
156
  raise
158
157
  end
159
158
 
159
+ def authorization_from(parameters, response)
160
+ authorization = [parameters[:originalReference], response['pspReference']].compact
161
+
162
+ return nil if authorization.empty?
163
+ return authorization.join("#")
164
+ end
165
+
160
166
  def parse_avs_code(response)
161
167
  AVS_MAPPING[response["avsResult"][0..1].strip] if response["avsResult"]
162
168
  end
@@ -206,8 +212,8 @@ module ActiveMerchant #:nodoc:
206
212
  end
207
213
 
208
214
  def success_from(response)
209
- return true if response.has_key?('authCode')
210
215
  return true if response['result'] == 'Success'
216
+ return true if response['resultCode'] == 'Authorised'
211
217
  return true if response['resultCode'] == 'Received'
212
218
  successful_responses = %w([capture-received] [cancel-received] [refund-received])
213
219
  successful_responses.include?(response['response'])
@@ -217,30 +223,57 @@ module ActiveMerchant #:nodoc:
217
223
  case action
218
224
  when 'store'
219
225
  "#{test? ? self.test_url : self.live_url}/Recurring/v12/storeToken"
226
+ when 'finalize3ds'
227
+ "#{test? ? self.test_url : self.live_url}/Payment/v12/authorise3d"
220
228
  else
221
229
  "#{test? ? self.test_url : self.live_url}/Payment/v12/#{action}"
222
230
  end
223
231
  end
224
232
 
225
- def address_hash(address)
226
- full_address = "#{address[:address1]} #{address[:address2]}" if address
227
- street = address[:street] if address[:street]
228
- house = address[:houseNumberOrName] if address[:houseNumberOrName]
233
+ def billing_address_hash(options)
234
+ address = options[:address] || options[:billing_address] if options[:address] || options[:billing_address]
235
+ street = options[:street] || parse_street(address)
236
+ house = options[:house_number] || parse_house_number(address)
237
+
238
+ create_address_hash(address, house, street)
239
+ end
240
+
241
+ def shipping_address_hash(options)
242
+ address = options[:shipping_address]
243
+ street = options[:shipping_street] || parse_street(address)
244
+ house = options[:shipping_house_number] || parse_house_number(address)
229
245
 
246
+ create_address_hash(address, house, street)
247
+ end
248
+
249
+ def parse_street(address)
250
+ address_to_parse = "#{address[:address1]} #{address[:address2]}"
251
+ street = address[:street] || address_to_parse.split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' ')
252
+ street.empty? ? "Not Provided" : street
253
+ end
254
+
255
+ def parse_house_number(address)
256
+ address_to_parse = "#{address[:address1]} #{address[:address2]}"
257
+ house = address[:houseNumberOrName] || address_to_parse.split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' ')
258
+ house.empty? ? "Not Provided" : house
259
+ end
260
+
261
+ def create_address_hash(address, house, street)
230
262
  hash = {}
263
+ hash[:houseNumberOrName] = house
264
+ hash[:street] = street
231
265
  hash[:city] = address[:city] if address[:city]
232
- hash[:street] = street || full_address.split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' ')
233
- hash[:houseNumberOrName] = house || full_address.split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' ')
234
- hash[:postalCode] = address[:zip] if address[:zip]
235
266
  hash[:stateOrProvince] = address[:state] if address[:state]
267
+ hash[:postalCode] = address[:zip] if address[:zip]
236
268
  hash[:country] = address[:country] if address[:country]
237
269
  hash
238
270
  end
239
271
 
240
272
  def amount_hash(money, currency)
273
+ currency = currency || currency(money)
241
274
  hash = {}
242
- hash[:currency] = currency || currency(money)
243
- hash[:value] = amount(money) if money
275
+ hash[:currency] = currency
276
+ hash[:value] = localized_amount(money, currency) if money
244
277
  hash
245
278
  end
246
279
 
@@ -257,10 +290,14 @@ module ActiveMerchant #:nodoc:
257
290
  def modification_request(reference, options)
258
291
  hash = {}
259
292
  hash[:merchantAccount] = @options[:merchant]
260
- hash[:originalReference] = reference if reference
293
+ hash[:originalReference] = psp_reference_from(reference)
261
294
  hash.keep_if { |_, v| v }
262
295
  end
263
296
 
297
+ def psp_reference_from(authorization)
298
+ authorization.nil? ? nil : authorization.split("#").first
299
+ end
300
+
264
301
  def payment_request(money, options)
265
302
  hash = {}
266
303
  hash[:merchantAccount] = @options[:merchant]
@@ -268,6 +305,7 @@ module ActiveMerchant #:nodoc:
268
305
  hash[:shopperEmail] = options[:email] if options[:email]
269
306
  hash[:shopperIP] = options[:ip] if options[:ip]
270
307
  hash[:shopperReference] = options[:customer] if options[:customer]
308
+ hash[:shopperInteraction] = options[:shopper_interaction] if options[:shopper_interaction]
271
309
  hash.keep_if { |_, v| v }
272
310
  end
273
311
 
@@ -278,6 +316,11 @@ module ActiveMerchant #:nodoc:
278
316
  hash[:shopperReference] = options[:customer] if options[:customer]
279
317
  hash.keep_if { |_, v| v }
280
318
  end
319
+
320
+ def add_3ds(post, options)
321
+ post[:additionalData] = { executeThreeD: 'true' }
322
+ post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
323
+ end
281
324
  end
282
325
  end
283
326
  end