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
@@ -3,24 +3,18 @@ require 'nokogiri'
3
3
  module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
5
5
  class LitleGateway < Gateway
6
- SCHEMA_VERSION = '9.4'
6
+ SCHEMA_VERSION = '9.12'
7
7
 
8
- self.test_url = 'https://www.testlitle.com/sandbox/communicator/online'
9
- self.live_url = 'https://payments.litle.com/vap/communicator/online'
8
+ self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online'
9
+ self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online'
10
10
 
11
11
  self.supported_countries = ['US']
12
12
  self.default_currency = 'USD'
13
13
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
14
14
 
15
- self.homepage_url = 'http://www.litle.com/'
16
- self.display_name = 'Litle & Co.'
15
+ self.homepage_url = 'http://www.vantiv.com/'
16
+ self.display_name = 'Vantiv eCommerce'
17
17
 
18
- # Public: Create a new Litle gateway.
19
- #
20
- # options - A hash of options:
21
- # :login - The user.
22
- # :password - The password.
23
- # :merchant_id - The merchant id.
24
18
  def initialize(options={})
25
19
  requires!(options, :login, :password, :merchant_id)
26
20
  super
@@ -29,23 +23,33 @@ module ActiveMerchant #:nodoc:
29
23
  def purchase(money, payment_method, options={})
30
24
  request = build_xml_request do |doc|
31
25
  add_authentication(doc)
32
- doc.sale(transaction_attributes(options)) do
33
- add_auth_purchase_params(doc, money, payment_method, options)
26
+ if check?(payment_method)
27
+ doc.echeckSale(transaction_attributes(options)) do
28
+ add_echeck_purchase_params(doc, money, payment_method, options)
29
+ end
30
+ else
31
+ doc.sale(transaction_attributes(options)) do
32
+ add_auth_purchase_params(doc, money, payment_method, options)
33
+ end
34
34
  end
35
35
  end
36
-
37
- commit(:sale, request, money)
36
+ check?(payment_method) ? commit(:echeckSales, request, money) : commit(:sale, request, money)
38
37
  end
39
38
 
40
39
  def authorize(money, payment_method, options={})
41
40
  request = build_xml_request do |doc|
42
41
  add_authentication(doc)
43
- doc.authorization(transaction_attributes(options)) do
44
- add_auth_purchase_params(doc, money, payment_method, options)
42
+ if check?(payment_method)
43
+ doc.echeckVerification(transaction_attributes(options)) do
44
+ add_echeck_purchase_params(doc, money, payment_method, options)
45
+ end
46
+ else
47
+ doc.authorization(transaction_attributes(options)) do
48
+ add_auth_purchase_params(doc, money, payment_method, options)
49
+ end
45
50
  end
46
51
  end
47
-
48
- commit(:authorization, request, money)
52
+ check?(payment_method) ? commit(:echeckVerification, request, money) : commit(:authorization, request, money)
49
53
  end
50
54
 
51
55
  def capture(money, authorization, options={})
@@ -68,19 +72,24 @@ module ActiveMerchant #:nodoc:
68
72
  refund(money, authorization, options)
69
73
  end
70
74
 
71
- def refund(money, authorization, options={})
72
- transaction_id, _, _ = split_authorization(authorization)
73
-
75
+ def refund(money, payment, options={})
74
76
  request = build_xml_request do |doc|
75
77
  add_authentication(doc)
76
78
  add_descriptor(doc, options)
77
- doc.credit(transaction_attributes(options)) do
78
- doc.litleTxnId(transaction_id)
79
- doc.amount(money) if money
79
+ doc.send(refund_type(payment), transaction_attributes(options)) do
80
+ if payment.is_a?(String)
81
+ transaction_id, kind, _ = split_authorization(payment)
82
+ doc.litleTxnId(transaction_id)
83
+ doc.amount(money) if money
84
+ elsif check?(payment)
85
+ add_echeck_purchase_params(doc, money, payment, options)
86
+ else
87
+ add_auth_purchase_params(doc, money, payment, options)
88
+ end
80
89
  end
81
90
  end
82
91
 
83
- commit(:credit, request)
92
+ commit(refund_type(payment), request)
84
93
  end
85
94
 
86
95
  def verify(creditcard, options = {})
@@ -111,6 +120,11 @@ module ActiveMerchant #:nodoc:
111
120
  doc.orderId(truncate(options[:order_id], 24))
112
121
  if payment_method.is_a?(String)
113
122
  doc.paypageRegistrationId(payment_method)
123
+ elsif check?(payment_method)
124
+ doc.echeckForToken do
125
+ doc.accNum(payment_method.account_number)
126
+ doc.routingNum(payment_method.routing_number)
127
+ end
114
128
  else
115
129
  doc.accountNumber(payment_method.number)
116
130
  doc.cardValidationNum(payment_method.verification_value) if payment_method.verification_value
@@ -130,6 +144,8 @@ module ActiveMerchant #:nodoc:
130
144
  gsub(%r((<user>).+(</user>)), '\1[FILTERED]\2').
131
145
  gsub(%r((<password>).+(</password>)), '\1[FILTERED]\2').
132
146
  gsub(%r((<number>).+(</number>)), '\1[FILTERED]\2').
147
+ gsub(%r((<accNum>).+(</accNum>)), '\1[FILTERED]\2').
148
+ gsub(%r((<routingNum>).+(</routingNum>)), '\1[FILTERED]\2').
133
149
  gsub(%r((<cardValidationNum>).+(</cardValidationNum>)), '\1[FILTERED]\2').
134
150
  gsub(%r((<accountNumber>).+(</accountNumber>)), '\1[FILTERED]\2').
135
151
  gsub(%r((<paypageRegistrationId>).+(</paypageRegistrationId>)), '\1[FILTERED]\2').
@@ -137,6 +153,7 @@ module ActiveMerchant #:nodoc:
137
153
  end
138
154
 
139
155
  private
156
+
140
157
  CARD_TYPE = {
141
158
  'visa' => 'VI',
142
159
  'master' => 'MC',
@@ -165,7 +182,27 @@ module ActiveMerchant #:nodoc:
165
182
  }
166
183
 
167
184
  def void_type(kind)
168
- (kind == 'authorization') ? :authReversal : :void
185
+ if kind == 'authorization'
186
+ :authReversal
187
+ elsif kind == 'echeckSales'
188
+ :echeckVoid
189
+ else
190
+ :void
191
+ end
192
+ end
193
+
194
+ def refund_type(payment)
195
+ transaction_id, kind, _ = split_authorization(payment)
196
+ if check?(payment) || kind == 'echeckSales'
197
+ :echeckCredit
198
+ else
199
+ :credit
200
+ end
201
+ end
202
+
203
+ def check?(payment_method)
204
+ return false if payment_method.is_a?(String)
205
+ card_brand(payment_method) == 'check'
169
206
  end
170
207
 
171
208
  def add_authentication(doc)
@@ -181,12 +218,32 @@ module ActiveMerchant #:nodoc:
181
218
  add_order_source(doc, payment_method, options)
182
219
  add_billing_address(doc, payment_method, options)
183
220
  add_shipping_address(doc, payment_method, options)
184
- add_payment_method(doc, payment_method)
221
+ add_payment_method(doc, payment_method, options)
185
222
  add_pos(doc, payment_method)
186
223
  add_descriptor(doc, options)
224
+ add_merchant_data(doc, options)
187
225
  add_debt_repayment(doc, options)
188
226
  end
189
227
 
228
+ def add_merchant_data(doc, options={})
229
+ if options[:affiliate] || options[:campaign] || options[:merchant_grouping_id]
230
+ doc.merchantData do
231
+ doc.affiliate(options[:affiliate]) if options[:affiliate]
232
+ doc.campaign(options[:campaign]) if options[:campaign]
233
+ doc.merchantGroupingId(options[:merchant_grouping_id]) if options[:merchant_grouping_id]
234
+ end
235
+ end
236
+ end
237
+
238
+ def add_echeck_purchase_params(doc, money, payment_method, options)
239
+ doc.orderId(truncate(options[:order_id], 24))
240
+ doc.amount(money)
241
+ add_order_source(doc, payment_method, options)
242
+ add_billing_address(doc, payment_method, options)
243
+ add_payment_method(doc, payment_method, options)
244
+ add_descriptor(doc, options)
245
+ end
246
+
190
247
  def add_descriptor(doc, options)
191
248
  if options[:descriptor_name] || options[:descriptor_phone]
192
249
  doc.customBilling do
@@ -200,7 +257,7 @@ module ActiveMerchant #:nodoc:
200
257
  doc.debtRepayment(true) if options[:debt_repayment] == true
201
258
  end
202
259
 
203
- def add_payment_method(doc, payment_method)
260
+ def add_payment_method(doc, payment_method, options)
204
261
  if payment_method.is_a?(String)
205
262
  doc.token do
206
263
  doc.litleToken(payment_method)
@@ -209,6 +266,13 @@ module ActiveMerchant #:nodoc:
209
266
  doc.card do
210
267
  doc.track(payment_method.track_data)
211
268
  end
269
+ elsif check?(payment_method)
270
+ doc.echeck do
271
+ doc.accType(payment_method.account_type)
272
+ doc.accNum(payment_method.account_number)
273
+ doc.routingNum(payment_method.routing_number)
274
+ doc.checkNum(payment_method.number)
275
+ end
212
276
  else
213
277
  doc.card do
214
278
  doc.type_(CARD_TYPE[payment_method.brand])
@@ -220,6 +284,11 @@ module ActiveMerchant #:nodoc:
220
284
  doc.cardholderAuthentication do
221
285
  doc.authenticationValue(payment_method.payment_cryptogram)
222
286
  end
287
+ elsif options[:order_source] && options[:order_source].start_with?('3ds')
288
+ doc.cardholderAuthentication do
289
+ doc.authenticationValue(options[:cavv]) if options[:cavv]
290
+ doc.authenticationTransactionId(options[:xid]) if options[:xid]
291
+ end
223
292
  end
224
293
  end
225
294
  end
@@ -228,7 +297,13 @@ module ActiveMerchant #:nodoc:
228
297
  return if payment_method.is_a?(String)
229
298
 
230
299
  doc.billToAddress do
231
- doc.name(payment_method.name)
300
+ if check?(payment_method)
301
+ doc.name(payment_method.name)
302
+ doc.firstName(payment_method.first_name)
303
+ doc.lastName(payment_method.last_name)
304
+ else
305
+ doc.name(payment_method.name)
306
+ end
232
307
  doc.email(options[:email]) if options[:email]
233
308
 
234
309
  add_address(doc, options[:billing_address])
@@ -261,6 +336,8 @@ module ActiveMerchant #:nodoc:
261
336
  doc.orderSource(options[:order_source])
262
337
  elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :apple_pay
263
338
  doc.orderSource('applepay')
339
+ elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :android_pay
340
+ doc.orderSource('androidpay')
264
341
  elsif payment_method.respond_to?(:track_data) && payment_method.track_data.present?
265
342
  doc.orderSource('retail')
266
343
  else
@@ -0,0 +1,262 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class MercadoPagoGateway < Gateway
4
+ self.live_url = self.test_url = 'https://api.mercadopago.com/v1'
5
+
6
+ self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY']
7
+ self.supported_cardtypes = [:visa, :master, :american_express]
8
+
9
+ self.homepage_url = 'https://www.mercadopago.com/'
10
+ self.display_name = 'Mercado Pago'
11
+ self.money_format = :dollars
12
+
13
+ CARD_BRAND = {
14
+ "american_express" => "amex",
15
+ "diners_club" => "diners"
16
+ }
17
+
18
+ def initialize(options={})
19
+ requires!(options, :access_token)
20
+ super
21
+ end
22
+
23
+ def purchase(money, payment, options={})
24
+ MultiResponse.run do |r|
25
+ r.process { commit("tokenize", "card_tokens", card_token_request(money, payment, options)) }
26
+ options.merge!(card_brand: (CARD_BRAND[payment.brand] || payment.brand))
27
+ options.merge!(card_token: r.authorization.split("|").first)
28
+ r.process { commit("purchase", "payments", purchase_request(money, payment, options) ) }
29
+ end
30
+ end
31
+
32
+ def authorize(money, payment, options={})
33
+ MultiResponse.run do |r|
34
+ r.process { commit("tokenize", "card_tokens", card_token_request(money, payment, options)) }
35
+ options.merge!(card_brand: (CARD_BRAND[payment.brand] || payment.brand))
36
+ options.merge!(card_token: r.authorization.split("|").first)
37
+ r.process { commit("authorize", "payments", authorize_request(money, payment, options) ) }
38
+ end
39
+ end
40
+
41
+ def capture(money, authorization, options={})
42
+ post = {}
43
+ authorization, _ = authorization.split("|")
44
+ post[:capture] = true
45
+ post[:transaction_amount] = amount(money).to_f
46
+ commit("capture", "payments/#{authorization}", post)
47
+ end
48
+
49
+ def refund(money, authorization, options={})
50
+ post = {}
51
+ authorization, original_amount = authorization.split("|")
52
+ post[:amount] = amount(money).to_f if original_amount && original_amount.to_f > amount(money).to_f
53
+ commit("refund", "payments/#{authorization}/refunds", post)
54
+ end
55
+
56
+ def void(authorization, options={})
57
+ authorization, _ = authorization.split("|")
58
+ post = { status: "cancelled" }
59
+ commit("void", "payments/#{authorization}", post)
60
+ end
61
+
62
+ def verify(credit_card, options={})
63
+ MultiResponse.run(:use_first_response) do |r|
64
+ r.process { authorize(100, credit_card, options) }
65
+ r.process(:ignore_result) { void(r.authorization, options) }
66
+ end
67
+ end
68
+
69
+ def supports_scrubbing?
70
+ true
71
+ end
72
+
73
+ def scrub(transcript)
74
+ transcript.
75
+ gsub(%r((access_token=).*?([^\s]+)), '\1[FILTERED]').
76
+ gsub(%r((\"card_number\\\":\\\")\d+), '\1[FILTERED]').
77
+ gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]')
78
+ end
79
+
80
+ private
81
+
82
+ def card_token_request(money, payment, options = {})
83
+ post = {}
84
+ post[:card_number] = payment.number
85
+ post[:security_code] = payment.verification_value
86
+ post[:expiration_month] = payment.month
87
+ post[:expiration_year] = payment.year
88
+ post[:cardholder] = {
89
+ name: payment.name,
90
+ identification: {
91
+ type: options[:cardholder_identification_type],
92
+ number: options[:cardholder_identification_number]
93
+ }
94
+ }
95
+ post
96
+ end
97
+
98
+ def purchase_request(money, payment, options = {})
99
+ post = {}
100
+ add_invoice(post, money, options)
101
+ add_payment(post, options)
102
+ add_additional_data(post, options)
103
+ add_customer_data(post, payment, options)
104
+ add_address(post, options)
105
+ post[:binary_mode] = (options[:binary_mode].nil? ? true : options[:binary_mode])
106
+ post
107
+ end
108
+
109
+ def authorize_request(money, payment, options = {})
110
+ post = purchase_request(money, payment, options)
111
+ post.merge!(capture: false)
112
+ post
113
+ end
114
+
115
+ def add_additional_data(post, options)
116
+ post[:sponsor_id] = options[:sponsor_id]
117
+ post[:device_id] = options[:device_id] if options[:device_id]
118
+ post[:additional_info] = {
119
+ ip_address: options[:ip_address]
120
+ }.merge(options[:additional_info] || {})
121
+
122
+
123
+ add_address(post, options)
124
+ add_shipping_address(post, options)
125
+ end
126
+
127
+ def add_customer_data(post, payment, options)
128
+ post[:payer] = {
129
+ email: options[:email],
130
+ first_name: payment.first_name,
131
+ last_name: payment.last_name
132
+ }
133
+ end
134
+
135
+ def add_address(post, options)
136
+ if address = (options[:billing_address] || options[:address])
137
+
138
+ post[:additional_info].merge!({
139
+ payer: {
140
+ address: {
141
+ zip_code: address[:zip],
142
+ street_name: "#{address[:address1]} #{address[:address2]}"
143
+ }
144
+ }
145
+ })
146
+ end
147
+ end
148
+
149
+ def add_shipping_address(post, options)
150
+ if address = options[:shipping_address]
151
+
152
+ post[:additional_info].merge!({
153
+ shipments: {
154
+ receiver_address: {
155
+ zip_code: address[:zip],
156
+ street_name: "#{address[:address1]} #{address[:address2]}"
157
+ }
158
+ }
159
+ })
160
+ end
161
+ end
162
+
163
+ def split_street_address(address1)
164
+ street_number = address1.split(" ").first
165
+
166
+ if street_name = address1.split(" ")[1..-1]
167
+ street_name = street_name.join(" ")
168
+ else
169
+ nil
170
+ end
171
+
172
+ [street_number, street_name]
173
+ end
174
+
175
+ def add_invoice(post, money, options)
176
+ post[:transaction_amount] = amount(money).to_f
177
+ post[:description] = options[:description]
178
+ post[:installments] = options[:installments] ? options[:installments].to_i : 1
179
+ post[:statement_descriptor] = options[:statement_descriptor] if options[:statement_descriptor]
180
+ post[:external_reference] = options[:order_id] || SecureRandom.hex(16)
181
+ end
182
+
183
+ def add_payment(post, options)
184
+ post[:token] = options[:card_token]
185
+ post[:payment_method_id] = options[:card_brand]
186
+ end
187
+
188
+ def parse(body)
189
+ JSON.parse(body)
190
+ end
191
+
192
+ def commit(action, path, parameters)
193
+ if ["capture", "void"].include?(action)
194
+ response = parse(ssl_request(:put, url(path), post_data(parameters), headers))
195
+ else
196
+ response = parse(ssl_post(url(path), post_data(parameters), headers(parameters)))
197
+ end
198
+
199
+ Response.new(
200
+ success_from(action, response),
201
+ message_from(response),
202
+ response,
203
+ authorization: authorization_from(response, parameters),
204
+ test: test?,
205
+ error_code: error_code_from(action, response)
206
+ )
207
+ end
208
+
209
+ def success_from(action, response)
210
+ if action == "refund"
211
+ response["error"].nil?
212
+ else
213
+ ["active", "approved", "authorized", "cancelled", "in_process"].include?(response["status"])
214
+ end
215
+ end
216
+
217
+ def message_from(response)
218
+ (response["status_detail"]) || (response["message"])
219
+ end
220
+
221
+ def authorization_from(response, params)
222
+ [response["id"], params[:transaction_amount]].join("|")
223
+ end
224
+
225
+ def post_data(parameters = {})
226
+ parameters.clone.tap { |p| p.delete(:device_id) }.to_json
227
+ end
228
+
229
+ def error_code_from(action, response)
230
+ unless success_from(action, response)
231
+ if cause = response["cause"]
232
+ cause.empty? ? nil : cause.first["code"]
233
+ else
234
+ response["status"]
235
+ end
236
+ end
237
+ end
238
+
239
+ def url(action)
240
+ full_url = (test? ? test_url : live_url)
241
+ full_url + "/#{action}?access_token=#{CGI.escape(@options[:access_token])}"
242
+ end
243
+
244
+ def headers(options = {})
245
+ headers = {
246
+ "Content-Type" => "application/json"
247
+ }
248
+ headers['X-Device-Session-ID'] = options[:device_id] if options[:device_id]
249
+ headers
250
+ end
251
+
252
+ def handle_response(response)
253
+ case response.code.to_i
254
+ when 200..499
255
+ response.body
256
+ else
257
+ raise ResponseError.new(response)
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -94,6 +94,17 @@ module ActiveMerchant #:nodoc:
94
94
  commit('V', nil, options.merge(post))
95
95
  end
96
96
 
97
+ def supports_scrubbing?
98
+ true
99
+ end
100
+
101
+ def scrub(transcript)
102
+ transcript.
103
+ gsub(%r((&?profile_key=)\w*(&?)), '\1[FILTERED]\2').
104
+ gsub(%r((&?card_number=)\d*(&?)), '\1[FILTERED]\2').
105
+ gsub(%r((&?cvv2=)\d*(&?)), '\1[FILTERED]\2')
106
+ end
107
+
97
108
  private
98
109
 
99
110
  def add_address(post, options)
@@ -68,6 +68,18 @@ module ActiveMerchant #:nodoc:
68
68
  commit('addCard', post)
69
69
  end
70
70
 
71
+ def supports_scrubbing?
72
+ true
73
+ end
74
+
75
+ def scrub(transcript)
76
+ transcript.
77
+ gsub(%r((&?paymentCardNumber=)[^&]*)i, '\1[FILTERED]').
78
+ gsub(%r((CardNumber=)[^&]*)i, '\1[FILTERED]').
79
+ gsub(%r((&?paymentCardCSC=)[^&]*)i, '\1[FILTERED]').
80
+ gsub(%r((&?apiKey=)[^&]*)i, '\1[FILTERED]')
81
+ end
82
+
71
83
  private
72
84
 
73
85
  def add_transaction(post, identification)
@@ -79,13 +91,13 @@ module ActiveMerchant #:nodoc:
79
91
 
80
92
  post['customerName'] = scrub_name(address[:name])
81
93
  post['customerCountry'] = address[:country]
82
- post['customerState'] = address[:state]
94
+ post['customerState'] = address[:state] || 'N/A'
83
95
  post['customerCity'] = address[:city]
84
96
  post['customerAddress'] = address[:address1]
85
97
  post['customerPostCode'] = address[:zip]
86
- post['customerIP'] = address[:ip]
87
- post['customerPhone'] = address[:phone]
88
- post['customerEmail'] = address[:email]
98
+ post['customerIP'] = address[:ip]
99
+ post['customerPhone'] = address[:phone]
100
+ post['customerEmail'] = address[:email]
89
101
  end
90
102
 
91
103
  def add_order_id(post, options)
@@ -81,6 +81,19 @@ module ActiveMerchant #:nodoc:
81
81
  commit('CardLookup', request)
82
82
  end
83
83
 
84
+ def supports_scrubbing?
85
+ true
86
+ end
87
+
88
+ def scrub(transcript)
89
+ transcript.
90
+ gsub(%r(&lt;), "<").
91
+ gsub(%r(&gt;), ">").
92
+ gsub(%r((<pw>).*(</pw>))i, '\1[FILTERED]\2').
93
+ gsub(%r((<AcctNo>)(\d|x)*(</AcctNo>))i, '\1[FILTERED]\3').
94
+ gsub(%r((<CVVData>)\d*(</CVVData>))i, '\1[FILTERED]\2')
95
+ end
96
+
84
97
  private
85
98
 
86
99
  def build_non_authorized_request(action, money, credit_card, options)
@@ -126,7 +139,7 @@ module ActiveMerchant #:nodoc:
126
139
  xml.tag! 'TranInfo' do
127
140
  xml.tag! "AuthCode", auth_code
128
141
  xml.tag! "AcqRefData", acq_ref_data
129
- xml.tag! "ProcessData", process_data
142
+ xml.tag! "ProcessData", process_data
130
143
  end
131
144
  end
132
145
  end
@@ -1,7 +1,5 @@
1
1
  require 'active_merchant/billing/gateways/migs/migs_codes'
2
2
 
3
- require 'digest/md5' # Used in add_secure_hash
4
-
5
3
  module ActiveMerchant #:nodoc:
6
4
  module Billing #:nodoc:
7
5
  class MigsGateway < Gateway
@@ -121,6 +119,13 @@ module ActiveMerchant #:nodoc:
121
119
  refund(money, authorization, options)
122
120
  end
123
121
 
122
+ def verify(credit_card, options={})
123
+ MultiResponse.run do |r|
124
+ r.process { authorize(100, credit_card, options) }
125
+ r.process(:ignore_result) { void(r.authorization, options) }
126
+ end
127
+ end
128
+
124
129
  # Checks the status of a previous transaction
125
130
  # This can be useful when a response is not received due to network issues
126
131
  #
@@ -187,7 +192,7 @@ module ActiveMerchant #:nodoc:
187
192
 
188
193
  response_hash = parse(data)
189
194
 
190
- expected_secure_hash = calculate_secure_hash(response_hash.reject{|k, v| k == :SecureHash}, @options[:secure_hash])
195
+ expected_secure_hash = calculate_secure_hash(response_hash, @options[:secure_hash])
191
196
  unless response_hash[:SecureHash] == expected_secure_hash
192
197
  raise SecurityError, "Secure Hash mismatch, response may be tampered with"
193
198
  end
@@ -199,6 +204,18 @@ module ActiveMerchant #:nodoc:
199
204
  @options[:login].start_with?('TEST')
200
205
  end
201
206
 
207
+ def supports_scrubbing?
208
+ true
209
+ end
210
+
211
+ def scrub(transcript)
212
+ transcript.
213
+ gsub(%r((&?CardNum=)\d*(&?)), '\1[FILTERED]\2').
214
+ gsub(%r((&?CardSecurityCode=)\d*(&?)), '\1[FILTERED]\2').
215
+ gsub(%r((&?AccessCode=)[^&]*(&?)), '\1[FILTERED]\2').
216
+ gsub(%r((&?Password=)[^&]*(&?)), '\1[FILTERED]\2')
217
+ end
218
+
202
219
  private
203
220
 
204
221
  def add_amount(post, money, options)
@@ -245,6 +262,7 @@ module ActiveMerchant #:nodoc:
245
262
  end
246
263
 
247
264
  def commit(post)
265
+ add_secure_hash(post) if @options[:secure_hash]
248
266
  data = ssl_post self.merchant_hosted_url, post_data(post)
249
267
  response_hash = parse(data)
250
268
  response_object(response_hash)
@@ -290,12 +308,16 @@ module ActiveMerchant #:nodoc:
290
308
 
291
309
  def add_secure_hash(post)
292
310
  post[:SecureHash] = calculate_secure_hash(post, @options[:secure_hash])
311
+ post[:SecureHashType] = 'SHA256'
293
312
  end
294
313
 
295
314
  def calculate_secure_hash(post, secure_hash)
296
- sorted_values = post.sort_by(&:to_s).map(&:last)
297
- input = secure_hash + sorted_values.join
298
- Digest::MD5.hexdigest(input).upcase
315
+ input = post
316
+ .reject { |k| %i[SecureHash SecureHashType].include?(k) }
317
+ .sort
318
+ .map { |(k, v)| "vpc_#{k}=#{v}" }
319
+ .join('&')
320
+ OpenSSL::HMAC.hexdigest('SHA256', [secure_hash].pack('H*'), input).upcase
299
321
  end
300
322
  end
301
323
  end