activemerchant 1.60.0 → 1.61.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +64 -0
  3. data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
  4. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +12 -1
  5. data/lib/active_merchant/billing/gateways/blue_pay.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/blue_snap.rb +1 -1
  7. data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -0
  8. data/lib/active_merchant/billing/gateways/card_stream.rb +2 -0
  9. data/lib/active_merchant/billing/gateways/citrus_pay.rb +24 -0
  10. data/lib/active_merchant/billing/gateways/clearhaus.rb +12 -4
  11. data/lib/active_merchant/billing/gateways/conekta.rb +6 -1
  12. data/lib/active_merchant/billing/gateways/credorax.rb +234 -0
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +39 -52
  14. data/lib/active_merchant/billing/gateways/element.rb +13 -2
  15. data/lib/active_merchant/billing/gateways/fat_zebra.rb +12 -3
  16. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +5 -0
  17. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -1
  18. data/lib/active_merchant/billing/gateways/jetpay.rb +11 -3
  19. data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -0
  20. data/lib/active_merchant/billing/gateways/litle.rb +28 -12
  21. data/lib/active_merchant/billing/gateways/mastercard.rb +261 -0
  22. data/lib/active_merchant/billing/gateways/migs.rb +23 -1
  23. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/moneris.rb +13 -0
  25. data/lib/active_merchant/billing/gateways/netbanx.rb +245 -0
  26. data/lib/active_merchant/billing/gateways/nmi.rb +5 -0
  27. data/lib/active_merchant/billing/gateways/openpay.rb +7 -0
  28. data/lib/active_merchant/billing/gateways/opp.rb +362 -0
  29. data/lib/active_merchant/billing/gateways/orbital.rb +13 -0
  30. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +190 -0
  31. data/lib/active_merchant/billing/gateways/payflow.rb +6 -0
  32. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  33. data/lib/active_merchant/billing/gateways/paymill.rb +10 -0
  34. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/payu_latam.rb +386 -0
  36. data/lib/active_merchant/billing/gateways/pin.rb +1 -3
  37. data/lib/active_merchant/billing/gateways/redsys.rb +2 -0
  38. data/lib/active_merchant/billing/gateways/sage.rb +22 -0
  39. data/lib/active_merchant/billing/gateways/sage_pay.rb +12 -0
  40. data/lib/active_merchant/billing/gateways/securion_pay.rb +2 -2
  41. data/lib/active_merchant/billing/gateways/stripe.rb +29 -8
  42. data/lib/active_merchant/billing/gateways/telr.rb +275 -0
  43. data/lib/active_merchant/billing/gateways/tns.rb +12 -230
  44. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +1 -1
  45. data/lib/active_merchant/billing/gateways/vanco.rb +12 -8
  46. data/lib/active_merchant/billing/gateways/worldpay.rb +18 -0
  47. data/lib/active_merchant/country.rb +6 -2
  48. data/lib/active_merchant/version.rb +1 -1
  49. metadata +11 -3
@@ -48,6 +48,11 @@ module ActiveMerchant #:nodoc:
48
48
  authorize(0, payment, options)
49
49
  end
50
50
 
51
+ def verify_credentials
52
+ response = void("0")
53
+ response.params["result"] != "26"
54
+ end
55
+
51
56
  # Adds or modifies a recurring Payflow profile. See the Payflow Pro Recurring Billing Guide for more details:
52
57
  # https://www.paypal.com/en_US/pdf/PayflowPro_RecurringBilling_Guide.pdf
53
58
  #
@@ -88,6 +93,7 @@ module ActiveMerchant #:nodoc:
88
93
  @express ||= PayflowExpressGateway.new(@options)
89
94
  end
90
95
 
96
+
91
97
  private
92
98
  def build_sale_or_authorization_request(action, money, funding_source, options)
93
99
  if funding_source.is_a?(String)
@@ -10,7 +10,7 @@ module ActiveMerchant #:nodoc:
10
10
  # Set the default partner to PayPal
11
11
  base.partner = 'PayPal'
12
12
 
13
- base.supported_countries = ['US', 'CA', 'SG', 'AU']
13
+ base.supported_countries = ['US', 'CA', 'NZ', 'AU']
14
14
 
15
15
  base.class_attribute :timeout
16
16
  base.timeout = 60
@@ -62,6 +62,16 @@ module ActiveMerchant #:nodoc:
62
62
  gsub(/(account.verification=)(\d*)/, '\1[FILTERED]')
63
63
  end
64
64
 
65
+ def verify_credentials
66
+ begin
67
+ ssl_get(live_url + "transactions/nonexistent", headers)
68
+ rescue ResponseError => e
69
+ return false if e.response.code.to_i == 401
70
+ end
71
+
72
+ true
73
+ end
74
+
65
75
  private
66
76
 
67
77
  def add_credit_card(post, credit_card)
@@ -620,7 +620,7 @@ module ActiveMerchant #:nodoc:
620
620
  add_optional_fields(xml,
621
621
  %w{n2:NoteText n2:PaymentAction
622
622
  n2:TransactionId n2:AllowedPaymentMethod
623
- n2:PaymentRequestID },
623
+ n2:PaymentRequestID n2:SoftDescriptor },
624
624
  options)
625
625
  end
626
626
 
@@ -0,0 +1,386 @@
1
+ require 'digest/md5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class PayuLatamGateway < Gateway
6
+ self.display_name = "PayU Latam"
7
+ self.homepage_url = "http://www.payulatam.com"
8
+
9
+ self.test_url = "https://sandbox.api.payulatam.com/payments-api/4.0/service.cgi"
10
+ self.live_url = "https://api.payulatam.com/payments-api/4.0/service.cgi"
11
+
12
+ self.supported_countries = ["AR", "BR", "CL", "CO", "MX", "PA", "PE"]
13
+ self.default_currency = "USD"
14
+ self.money_format = :dollars
15
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
16
+
17
+ BRAND_MAP = {
18
+ "visa" => "VISA",
19
+ "master" => "MASTERCARD",
20
+ "american_express" => "AMEX",
21
+ "diners_club" => "DINERS"
22
+ }
23
+
24
+ MINIMUMS = {
25
+ "ARS" => 1700,
26
+ "BRL" => 600,
27
+ "MXN" => 3900,
28
+ "PEN" => 500
29
+ }
30
+
31
+ def initialize(options={})
32
+ requires!(options, :merchant_id, :account_id, :api_login, :api_key)
33
+ super
34
+ end
35
+
36
+ def purchase(amount, payment_method, options={})
37
+ post = {}
38
+ auth_or_sale(post, 'AUTHORIZATION_AND_CAPTURE', amount, payment_method, options)
39
+ commit('purchase', post)
40
+ end
41
+
42
+ def authorize(amount, payment_method, options={})
43
+ post = {}
44
+ auth_or_sale(post, 'AUTHORIZATION', amount, payment_method, options)
45
+ commit('auth', post)
46
+ end
47
+
48
+ def capture(authorization, options={})
49
+ post = {}
50
+
51
+ add_credentials(post, 'SUBMIT_TRANSACTION')
52
+ add_transaction_type(post, 'CAPTURE')
53
+ add_reference(post, authorization)
54
+
55
+ commit('capture', post)
56
+ end
57
+
58
+ def void(authorization, options={})
59
+ post = {}
60
+
61
+ add_credentials(post, 'SUBMIT_TRANSACTION')
62
+ add_transaction_type(post, 'VOID')
63
+ add_reference(post, authorization)
64
+
65
+ commit('void', post)
66
+ end
67
+
68
+ def refund(authorization, options={})
69
+ post = {}
70
+
71
+ add_credentials(post, 'SUBMIT_TRANSACTION')
72
+ add_transaction_type(post, 'REFUND')
73
+ add_reference(post, authorization)
74
+
75
+ commit('refund', post)
76
+ end
77
+
78
+ def verify(credit_card, options={})
79
+ minimum = MINIMUMS[options[:currency].upcase] if options[:currency]
80
+ amount = minimum || 100
81
+
82
+ MultiResponse.run(:use_first_response) do |r|
83
+ r.process { authorize(amount, credit_card, options) }
84
+ r.process(:ignore_result) { void(r.authorization, options) }
85
+ end
86
+ end
87
+
88
+ def store(payment_method, options = {})
89
+ post = {}
90
+
91
+ add_credentials(post, 'CREATE_TOKEN')
92
+ add_payment_method_to_be_tokenized(post, payment_method)
93
+
94
+ commit('store', post)
95
+ end
96
+
97
+ def verify_credentials
98
+ post = {}
99
+ add_credentials(post, 'GET_PAYMENT_METHODS')
100
+ response = commit('verify_credentials', post)
101
+ response.success?
102
+ end
103
+
104
+ def supports_scrubbing?
105
+ true
106
+ end
107
+
108
+ def scrub(transcript)
109
+ transcript.
110
+ gsub(%r((\"creditCard\\\":{\\\"number\\\":\\\")\d+), '\1[FILTERED]').
111
+ gsub(%r((\"securityCode\\\":\\\")\d+), '\1[FILTERED]').
112
+ gsub(%r((\"apiKey\\\":\\\")\w+), '\1[FILTERED]')
113
+ end
114
+
115
+ private
116
+
117
+ def auth_or_sale(post, transaction_type, amount, payment_method, options)
118
+ add_credentials(post, 'SUBMIT_TRANSACTION')
119
+ add_transaction_type(post, transaction_type)
120
+ add_order(post, options)
121
+ add_buyer(post, options)
122
+ add_invoice(post, amount, options)
123
+ add_signature(post)
124
+ add_payment_method(post, payment_method, options)
125
+ add_payer(post, options)
126
+ add_extra_parameters(post, options)
127
+ end
128
+
129
+ def add_credentials(post, command)
130
+ post[:test] = test? unless command == 'CREATE_TOKEN'
131
+ post[:language] = 'en'
132
+ post[:command] = command
133
+ merchant = {}
134
+ merchant[:apiLogin] = @options[:api_login]
135
+ merchant[:apiKey] = @options[:api_key]
136
+ post[:merchant] = merchant
137
+ end
138
+
139
+ def add_transaction_type(post, type)
140
+ transaction = {}
141
+ transaction[:type] = type
142
+ post[:transaction] = transaction
143
+ end
144
+
145
+ def add_order(post, options)
146
+ order = {}
147
+ order[:accountId] = @options[:account_id]
148
+ order[:referenceCode] = options[:order_id] || generate_unique_id
149
+ order[:description] = options[:description] || 'unspecified'
150
+ order[:language] = 'en'
151
+ post[:transaction][:order] = order
152
+ end
153
+
154
+ def add_buyer(post, options)
155
+ if address = options[:shipping_address]
156
+ buyer = {}
157
+ buyer[:fullName] = address[:name]
158
+ shipping_address = {}
159
+ shipping_address[:street1] = address[:address1]
160
+ shipping_address[:street2] = address[:address2]
161
+ shipping_address[:city] = address[:city]
162
+ shipping_address[:state] = address[:state]
163
+ shipping_address[:country] = address[:country]
164
+ shipping_address[:postalCode] = address[:zip]
165
+ shipping_address[:phone] = address[:phone]
166
+ buyer[:shippingAddress] = shipping_address
167
+ post[:transaction][:order][:buyer] = buyer
168
+ end
169
+ end
170
+
171
+ def add_invoice(post, money, options)
172
+ tx_value = {}
173
+ tx_value[:value] = amount(money)
174
+ tx_value[:currency] = options[:currency] || currency(money)
175
+
176
+ additional_values = {}
177
+ additional_values[:TX_VALUE] = tx_value
178
+
179
+ post[:transaction][:order][:additionalValues] = additional_values
180
+ end
181
+
182
+ def add_signature(post)
183
+ post[:transaction][:order][:signature] = signature_from(post)
184
+ end
185
+
186
+ def signature_from(post)
187
+ signature_string = [
188
+ @options[:api_key],
189
+ @options[:merchant_id],
190
+ post[:transaction][:order][:referenceCode],
191
+ post[:transaction][:order][:additionalValues][:TX_VALUE][:value],
192
+ post[:transaction][:order][:additionalValues][:TX_VALUE][:currency]
193
+ ].compact.join("~")
194
+
195
+ Digest::MD5.hexdigest(signature_string)
196
+ end
197
+
198
+ def add_payment_method(post, payment_method, options)
199
+ if payment_method.is_a?(String)
200
+ brand, token = split_authorization(payment_method)
201
+ credit_card = {}
202
+ credit_card[:securityCode] = options[:cvv] if options[:cvv]
203
+ post[:transaction][:creditCard] = credit_card
204
+ post[:transaction][:creditCardTokenId] = token
205
+ post[:transaction][:paymentMethod] = brand.upcase
206
+ else
207
+ credit_card = {}
208
+ credit_card[:number] = payment_method.number
209
+ credit_card[:securityCode] = payment_method.verification_value
210
+ credit_card[:expirationDate] = format(payment_method.year, :four_digits).to_s + '/' + format(payment_method.month, :two_digits).to_s
211
+ credit_card[:name] = payment_method.name.strip
212
+ post[:transaction][:creditCard] = credit_card
213
+ post[:transaction][:paymentMethod] = BRAND_MAP[payment_method.brand.to_s]
214
+ end
215
+ end
216
+
217
+ def add_payer(post, options)
218
+ if address = options[:billing_address]
219
+ payer = {}
220
+ post[:transaction][:paymentCountry] = address[:country]
221
+ payer[:fullName] = address[:name]
222
+ payer[:contactPhone] = address[:phone]
223
+ billing_address = {}
224
+ billing_address[:street1] = address[:address1]
225
+ billing_address[:street2] = address[:address2]
226
+ billing_address[:city] = address[:city]
227
+ billing_address[:state] = address[:state]
228
+ billing_address[:country] = address[:country]
229
+ billing_address[:postalCode] = address[:zip]
230
+ billing_address[:phone] = address[:phone]
231
+ payer[:billingAddress] = billing_address
232
+ post[:transaction][:payer] = payer
233
+ end
234
+ end
235
+
236
+ def add_extra_parameters(post, options)
237
+ extra_parameters = {}
238
+ extra_parameters[:INSTALLMENTS_NUMBER] = options[:installments_number] || 1
239
+ post[:transaction][:extraParameters] = extra_parameters
240
+ end
241
+
242
+ def add_reference(post, authorization)
243
+ order_id, transaction_id = split_authorization(authorization)
244
+ order = {}
245
+ order[:id] = order_id
246
+ post[:transaction][:order] = order
247
+ post[:transaction][:parentTransactionId] = transaction_id
248
+ post[:transaction][:reason] = 'n/a'
249
+ end
250
+
251
+ def add_payment_method_to_be_tokenized(post, payment_method)
252
+ credit_card_token = {}
253
+ credit_card_token[:payerId] = generate_unique_id
254
+ credit_card_token[:name] = payment_method.name.strip
255
+ credit_card_token[:identificationNumber] = generate_unique_id
256
+ credit_card_token[:paymentMethod] = BRAND_MAP[payment_method.brand.to_s]
257
+ credit_card_token[:number] = payment_method.number
258
+ credit_card_token[:expirationDate] = format(payment_method.year, :four_digits).to_s + '/' + format(payment_method.month, :two_digits).to_s
259
+ credit_card_token[:securityCode] = payment_method.verification_value
260
+ post[:creditCardToken] = credit_card_token
261
+ end
262
+
263
+ def commit(action, params)
264
+ begin
265
+ raw_response = ssl_post(url, post_data(params), headers)
266
+ response = parse(raw_response)
267
+ rescue ResponseError => e
268
+ raw_response = e.response.body
269
+ response_error(raw_response)
270
+ rescue JSON::ParserError
271
+ unparsable_response(raw_response)
272
+ else
273
+ success = success_from(action, response)
274
+ Response.new(
275
+ success,
276
+ message_from(action, success, response),
277
+ response,
278
+ authorization: success ? authorization_from(action, response) : nil,
279
+ error_code: success ? nil : error_from(action, response),
280
+ test: test?
281
+ )
282
+ end
283
+ end
284
+
285
+ def headers
286
+ {
287
+ "Content-Type" => "application/json",
288
+ "Accept" => "application/json"
289
+ }
290
+ end
291
+
292
+ def post_data(params)
293
+ params.to_json
294
+ end
295
+
296
+ def url
297
+ test? ? test_url : live_url
298
+ end
299
+
300
+ def parse(body)
301
+ JSON.parse(body)
302
+ end
303
+
304
+ def success_from(action, response)
305
+ case action
306
+ when 'store'
307
+ response["code"] == "SUCCESS" && response["creditCardToken"] && response["creditCardToken"]["creditCardTokenId"].present?
308
+ when 'verify_credentials'
309
+ response["code"] == "SUCCESS"
310
+ else
311
+ response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "APPROVED")
312
+ end
313
+ end
314
+
315
+ def message_from(action, success, response)
316
+ case action
317
+ when 'store'
318
+ return response["code"] if success
319
+ error_description = response["creditCardToken"]["errorDescription"] if response["creditCardToken"]
320
+ response["error"] || error_description || "FAILED"
321
+ when 'verify_credentials'
322
+ return "VERIFIED" if success
323
+ "FAILED"
324
+ else
325
+ response_message = response["transactionResponse"]["responseMessage"] if response["transactionResponse"]
326
+ response_code = response["transactionResponse"]["responseCode"] if response["transactionResponse"]
327
+ return response_code if success
328
+ response["error"] || response_message || response_code || "FAILED"
329
+ end
330
+ end
331
+
332
+ def authorization_from(action, response)
333
+ case action
334
+ when 'store'
335
+ [
336
+ response["creditCardToken"]["paymentMethod"],
337
+ response["creditCardToken"]["creditCardTokenId"]
338
+ ].compact.join("|")
339
+ when 'verify_credentials'
340
+ nil
341
+ else
342
+ [
343
+ response["transactionResponse"]["orderId"],
344
+ response["transactionResponse"]["transactionId"]
345
+ ].compact.join("|")
346
+ end
347
+ end
348
+
349
+ def split_authorization(authorization)
350
+ authorization.split("|")
351
+ end
352
+
353
+ def error_from(action, response)
354
+ case action
355
+ when 'store'
356
+ response["creditCardToken"]["errorDescription"] if response["creditCardToken"]
357
+ when 'verify_credentials'
358
+ response["error"] || "FAILED"
359
+ else
360
+ response["transactionResponse"]["errorCode"] || response["transactionResponse"]["responseCode"] if response["transactionResponse"]
361
+ end
362
+ end
363
+
364
+ def response_error(raw_response)
365
+ begin
366
+ response = parse(raw_response)
367
+ rescue JSON::ParserError
368
+ unparsable_response(raw_response)
369
+ else
370
+ return Response.new(
371
+ false,
372
+ message_from('', false, response),
373
+ response,
374
+ :test => test?
375
+ )
376
+ end
377
+ end
378
+
379
+ def unparsable_response(raw_response)
380
+ message = "Invalid JSON response received from PayuLatamGateway. Please contact PayuLatamGateway if you continue to receive this message."
381
+ message += " (The raw response returned by the API was #{raw_response.inspect})"
382
+ return Response.new(false, message)
383
+ end
384
+ end
385
+ end
386
+ end
@@ -44,9 +44,7 @@ module ActiveMerchant #:nodoc:
44
44
  commit(:post, 'customers', post, options)
45
45
  end
46
46
 
47
- # Refund a transaction, note that the money attribute is ignored at the
48
- # moment as the API does not support partial refunds. The parameter is
49
- # kept for compatibility reasons
47
+ # Refund a transaction
50
48
  def refund(money, token, options = {})
51
49
  commit(:post, "charges/#{CGI.escape(token)}/refunds", { :amount => amount(money) }, options)
52
50
  end