activemerchant 1.78.0 → 1.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +49 -0
  3. data/lib/active_merchant.rb +2 -5
  4. data/lib/active_merchant/billing/credit_card_methods.rb +3 -1
  5. data/lib/active_merchant/billing/gateways/adyen.rb +17 -2
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +16 -11
  7. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +1 -0
  8. data/lib/active_merchant/billing/gateways/borgun.rb +0 -1
  9. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +1 -0
  10. data/lib/active_merchant/billing/gateways/braintree_blue.rb +17 -4
  11. data/lib/active_merchant/billing/gateways/checkout_v2.rb +7 -0
  12. data/lib/active_merchant/billing/gateways/clearhaus.rb +0 -2
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +11 -2
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +3 -3
  15. data/lib/active_merchant/billing/gateways/elavon.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/first_pay.rb +10 -9
  17. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +11 -0
  18. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +12 -0
  19. data/lib/active_merchant/billing/gateways/migs.rb +0 -2
  20. data/lib/active_merchant/billing/gateways/mundipagg.rb +291 -0
  21. data/lib/active_merchant/billing/gateways/nab_transact.rb +4 -4
  22. data/lib/active_merchant/billing/gateways/paymentez.rb +6 -13
  23. data/lib/active_merchant/billing/gateways/paypal.rb +0 -12
  24. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +14 -0
  25. data/lib/active_merchant/billing/gateways/paystation.rb +10 -0
  26. data/lib/active_merchant/billing/gateways/psigate.rb +11 -0
  27. data/lib/active_merchant/billing/gateways/qbms.rb +11 -0
  28. data/lib/active_merchant/billing/gateways/realex.rb +14 -1
  29. data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -4
  31. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/spreedly_core.rb +41 -6
  33. data/lib/active_merchant/billing/gateways/stripe.rb +14 -4
  34. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -1
  35. data/lib/active_merchant/billing/gateways/worldpay.rb +45 -14
  36. data/lib/active_merchant/connection.rb +38 -9
  37. data/lib/active_merchant/net_http_ssl_connection.rb +9 -0
  38. data/lib/active_merchant/network_connection_retries.rb +2 -0
  39. data/lib/active_merchant/posts_data.rb +10 -0
  40. data/lib/active_merchant/version.rb +1 -1
  41. data/lib/support/ssl_version.rb +87 -0
  42. metadata +7 -4
@@ -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)
@@ -1,7 +1,5 @@
1
1
  require 'active_merchant/billing/gateways/migs/migs_codes'
2
2
 
3
- require 'openssl' # Used in add_secure_hash
4
-
5
3
  module ActiveMerchant #:nodoc:
6
4
  module Billing #:nodoc:
7
5
  class MigsGateway < Gateway
@@ -0,0 +1,291 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class MundipaggGateway < Gateway
4
+ self.live_url = 'https://api.mundipagg.com/core/v1'
5
+
6
+ self.supported_countries = ['US']
7
+ self.default_currency = 'USD'
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
9
+
10
+ self.homepage_url = 'https://www.mundipagg.com/'
11
+ self.display_name = 'Mundipagg'
12
+
13
+ STANDARD_ERROR_CODE_MAPPING = {
14
+ '400' => STANDARD_ERROR_CODE[:processing_error],
15
+ '401' => STANDARD_ERROR_CODE[:config_error],
16
+ '404' => STANDARD_ERROR_CODE[:processing_error],
17
+ '412' => STANDARD_ERROR_CODE[:processing_error],
18
+ '422' => STANDARD_ERROR_CODE[:processing_error],
19
+ '500' => STANDARD_ERROR_CODE[:processing_error]
20
+ }
21
+
22
+ STANDARD_ERROR_MESSAGE_MAPPING = {
23
+ '400' => 'Invalid request;',
24
+ '401' => 'Invalid API key;',
25
+ '404' => 'The requested resource does not exist;',
26
+ '412' => 'Valid parameters but request failed;',
27
+ '422' => 'Invalid parameters;',
28
+ '500' => 'An internal error occurred;'
29
+ }
30
+
31
+ def initialize(options={})
32
+ requires!(options, :api_key)
33
+ super
34
+ end
35
+
36
+ def purchase(money, payment, options={})
37
+ post = {}
38
+ add_invoice(post, money, options)
39
+ add_customer_data(post, options) unless payment.is_a?(String)
40
+ add_shipping_address(post, options)
41
+ add_payment(post, payment, options)
42
+
43
+ commit('sale', post)
44
+ end
45
+
46
+ def authorize(money, payment, options={})
47
+ post = {}
48
+ add_invoice(post, money, options)
49
+ add_customer_data(post, options) unless payment.is_a?(String)
50
+ add_shipping_address(post, options)
51
+ add_payment(post, payment, options)
52
+ add_capture_flag(post, payment)
53
+ commit('authonly', post)
54
+ end
55
+
56
+ def capture(money, authorization, options={})
57
+ post = {}
58
+ post[:code] = authorization
59
+ add_invoice(post, money, options)
60
+ commit('capture', post, authorization)
61
+ end
62
+
63
+ def refund(money, authorization, options={})
64
+ add_invoice(post={}, money, options)
65
+ commit('refund', post, authorization)
66
+ end
67
+
68
+ def void(authorization, options={})
69
+ commit('void', post=nil, authorization)
70
+ end
71
+
72
+ def store(payment, options={})
73
+ post = {}
74
+ options.update(name: payment.name)
75
+ options = add_customer(options) unless options[:customer_id]
76
+ add_payment(post, payment, options)
77
+ commit('store', post, options[:customer_id])
78
+ end
79
+
80
+ def verify(credit_card, options={})
81
+ MultiResponse.run(:use_first_response) do |r|
82
+ r.process { authorize(100, credit_card, options) }
83
+ r.process(:ignore_result) { void(r.authorization, options) }
84
+ end
85
+ end
86
+
87
+ def supports_scrubbing?
88
+ true
89
+ end
90
+
91
+ def scrub(transcript)
92
+ transcript
93
+ .gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]')
94
+ .gsub(%r(("cvv\\":\\")\d*), '\1[FILTERED]')
95
+ .gsub(%r((card\\":{\\"number\\":\\")\d*), '\1[FILTERED]')
96
+ end
97
+
98
+ private
99
+
100
+ def add_customer(options)
101
+ post = {}
102
+ post[:name] = options[:name]
103
+ customer = commit('customer', post)
104
+ options.update(customer_id: customer.authorization)
105
+ end
106
+
107
+ def add_customer_data(post, options)
108
+ post[:customer] = {}
109
+ post[:customer][:email] = options[:email]
110
+ end
111
+
112
+ def add_billing_address(post, type, options)
113
+ if address = (options[:billing_address] || options[:address])
114
+ billing = {}
115
+ address = options[:billing_address] || options[:address]
116
+ billing[:street] = address[:address1].match(/\D+/)[0].strip if address[:address1]
117
+ billing[:number] = address[:address1].match(/\d+/)[0] if address[:address1]
118
+ billing[:compliment] = address[:address2] if address[:address2]
119
+ billing[:city] = address[:city] if address[:city]
120
+ billing[:state] = address[:state] if address[:state]
121
+ billing[:country] = address[:country] if address[:country]
122
+ billing[:zip_code] = address[:zip] if address[:zip]
123
+ billing[:neighborhood] = address[:neighborhood]
124
+ post[:payment][type.to_sym][:card][:billing_address] = billing
125
+ end
126
+ end
127
+
128
+ def add_shipping_address(post, options)
129
+ if address = options[:shipping_address]
130
+ post[:address] = {}
131
+ post[:address][:street] = address[:address1].match(/\D+/)[0].strip if address[:address1]
132
+ post[:address][:number] = address[:address1].match(/\d+/)[0] if address[:address1]
133
+ post[:address][:compliment] = address[:address2] if address[:address2]
134
+ post[:address][:city] = address[:city] if address[:city]
135
+ post[:address][:state] = address[:state] if address[:state]
136
+ post[:address][:country] = address[:country] if address[:country]
137
+ post[:address][:zip_code] = address[:zip] if address[:zip]
138
+ end
139
+ end
140
+
141
+ def add_invoice(post, money, options)
142
+ post[:amount] = money
143
+ post[:currency] = (options[:currency] || currency(money))
144
+ end
145
+
146
+ def add_capture_flag(post, payment)
147
+ if voucher?(payment)
148
+ post[:payment][:voucher][:capture] = false
149
+ else
150
+ post[:payment][:credit_card][:capture] = false
151
+ end
152
+ end
153
+
154
+ def add_payment(post, payment, options)
155
+ post[:customer][:name] = payment.name if post[:customer]
156
+ post[:customer_id] = parse_auth(payment)[0] if payment.is_a?(String)
157
+ post[:payment] = {}
158
+ post[:payment][:gateway_affiliation_id] = @options[:gateway_id] if @options[:gateway_id]
159
+ post[:payment][:metadata] = { mundipagg_payment_method_code: '1' } if test?
160
+ if voucher?(payment)
161
+ add_voucher(post, payment, options)
162
+ else
163
+ add_credit_card(post, payment, options)
164
+ end
165
+ end
166
+
167
+ def add_credit_card(post, payment, options)
168
+ post[:payment][:payment_method] = 'credit_card'
169
+ post[:payment][:credit_card] = {}
170
+ if payment.is_a?(String)
171
+ post[:payment][:credit_card][:card_id] = parse_auth(payment)[1]
172
+ else
173
+ post[:payment][:credit_card][:card] = {}
174
+ post[:payment][:credit_card][:card][:number] = payment.number
175
+ post[:payment][:credit_card][:card][:holder_name] = payment.name
176
+ post[:payment][:credit_card][:card][:exp_month] = payment.month
177
+ post[:payment][:credit_card][:card][:exp_year] = payment.year
178
+ post[:payment][:credit_card][:card][:cvv] = payment.verification_value
179
+ add_billing_address(post,'credit_card', options)
180
+ end
181
+ end
182
+
183
+ def add_voucher(post, payment, options)
184
+ post[:currency] = 'BRL'
185
+ post[:payment][:payment_method] = 'voucher'
186
+ post[:payment][:voucher] = {}
187
+ post[:payment][:voucher][:card] = {}
188
+ post[:payment][:voucher][:card][:number] = payment.number
189
+ post[:payment][:voucher][:card][:holder_name] = payment.name
190
+ post[:payment][:voucher][:card][:holder_document] = options[:holder_document]
191
+ post[:payment][:voucher][:card][:exp_month] = payment.month
192
+ post[:payment][:voucher][:card][:exp_year] = payment.year
193
+ post[:payment][:voucher][:card][:cvv] = payment.verification_value
194
+ add_billing_address(post, 'voucher', options)
195
+ end
196
+
197
+ def voucher?(payment)
198
+ return false if payment.is_a?(String)
199
+ %w[sodexo vr].include? card_brand(payment)
200
+ end
201
+
202
+ def headers
203
+ {
204
+ 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:api_key]}:"),
205
+ 'Content-Type' => 'application/json',
206
+ 'Accept' => 'application/json'
207
+ }
208
+ end
209
+
210
+ def parse(body)
211
+ JSON.parse(body)
212
+ end
213
+
214
+ def url_for(action, auth = nil)
215
+ url = live_url
216
+ case action
217
+ when 'store'
218
+ "#{url}/customers/#{auth}/cards/"
219
+ when 'customer'
220
+ "#{url}/customers/"
221
+ when 'refund', 'void'
222
+ "#{url}/charges/#{auth}/"
223
+ when 'capture'
224
+ "#{url}/charges/#{auth}/capture/"
225
+ else
226
+ "#{url}/charges/"
227
+ end
228
+ end
229
+
230
+ def commit(action, parameters, auth = nil)
231
+ url = url_for(action, auth)
232
+ parameters.merge!(parameters[:payment][:credit_card].delete(:card)).delete(:payment) if action == 'store'
233
+ response = if %w[refund void].include? action
234
+ parse(ssl_request(:delete, url, post_data(parameters), headers))
235
+ else
236
+ parse(ssl_post(url, post_data(parameters), headers))
237
+ end
238
+
239
+ Response.new(
240
+ success_from(response),
241
+ message_from(response),
242
+ response,
243
+ authorization: authorization_from(response, action),
244
+ avs_result: AVSResult.new(code: response['some_avs_response_key']),
245
+ cvv_result: CVVResult.new(response['some_cvv_response_key']),
246
+ test: test?,
247
+ error_code: error_code_from(response)
248
+ )
249
+ rescue ResponseError => e
250
+ message = get_error_message(e)
251
+ return Response.new(
252
+ false,
253
+ "#{STANDARD_ERROR_MESSAGE_MAPPING[e.response.code]} #{message}",
254
+ parse(e.response.body),
255
+ test: test?,
256
+ error_code: STANDARD_ERROR_CODE_MAPPING[e.response.code],
257
+ )
258
+ end
259
+
260
+ def success_from(response)
261
+ %w[pending paid processing canceled active].include? response['status']
262
+ end
263
+
264
+ def get_error_message(error)
265
+ JSON.parse(error.response.body)['message']
266
+ end
267
+
268
+ def message_from(response)
269
+ return response['message'] if response['message']
270
+ return response['last_transaction']['acquirer_message'] if response['last_transaction']
271
+ end
272
+
273
+ def authorization_from(response, action)
274
+ return "#{response['customer']['id']}|#{response['id']}" if action == 'store'
275
+ response['id']
276
+ end
277
+
278
+ def parse_auth(auth)
279
+ auth.split('|')
280
+ end
281
+
282
+ def post_data(parameters = {})
283
+ parameters.to_json
284
+ end
285
+
286
+ def error_code_from(response)
287
+ STANDARD_ERROR_CODE[:processing_error] unless success_from(response)
288
+ end
289
+ end
290
+ end
291
+ end
@@ -10,7 +10,7 @@ module ActiveMerchant #:nodoc:
10
10
 
11
11
  class_attribute :test_periodic_url, :live_periodic_url
12
12
 
13
- self.test_url = 'https://transact.nab.com.au/test/xmlapi/payment'
13
+ self.test_url = 'https://demo.transact.nab.com.au/xmlapi/payment'
14
14
  self.live_url = 'https://transact.nab.com.au/live/xmlapi/payment'
15
15
  self.test_periodic_url = 'https://transact.nab.com.au/xmlapidemo/periodic'
16
16
  self.live_periodic_url = 'https://transact.nab.com.au/xmlapi/periodic'
@@ -104,7 +104,7 @@ module ActiveMerchant #:nodoc:
104
104
 
105
105
  def build_purchase_request(money, credit_card, options)
106
106
  xml = Builder::XmlMarkup.new
107
- xml.tag! 'amount', amount(money)
107
+ xml.tag! 'amount', localized_amount(money, options[:currency] || currency(money))
108
108
  xml.tag! 'currency', options[:currency] || currency(money)
109
109
  xml.tag! 'purchaseOrderNo', options[:order_id].to_s.gsub(/[ ']/, '')
110
110
 
@@ -124,7 +124,7 @@ module ActiveMerchant #:nodoc:
124
124
 
125
125
  transaction_id, order_id, preauth_id, original_amount = reference.split('*')
126
126
 
127
- xml.tag! 'amount', (money ? amount(money) : original_amount)
127
+ xml.tag! 'amount', (money ? localized_amount(money, options[:currency] || currency(money)) : original_amount)
128
128
  xml.tag! 'currency', options[:currency] || currency(money)
129
129
  xml.tag! 'txnID', transaction_id
130
130
  xml.tag! 'purchaseOrderNo', order_id
@@ -205,7 +205,7 @@ module ActiveMerchant #:nodoc:
205
205
 
206
206
  xml.tag! 'crn', identification
207
207
  xml.tag! 'currency', options[:currency] || currency(money)
208
- xml.tag! 'amount', amount(money)
208
+ xml.tag! 'amount', localized_amount(money, options[:currency] || currency(money))
209
209
 
210
210
  xml.target!
211
211
  end
@@ -61,18 +61,10 @@ module ActiveMerchant #:nodoc:
61
61
  post = {}
62
62
 
63
63
  add_invoice(post, money, options)
64
+ add_payment(post, payment)
64
65
  add_customer_data(post, options)
65
66
 
66
- if payment.is_a?(String)
67
- post[:card] = { token: payment }
68
- commit_transaction('authorize', post)
69
- else
70
- MultiResponse.run do |r|
71
- r.process { store(payment, options) }
72
- post[:card] = { token: r.authorization }
73
- r.process { commit_transaction('authorize', post) }
74
- end
75
- end
67
+ commit_transaction('authorize', post)
76
68
  end
77
69
 
78
70
  def capture(_money, authorization, _options = {})
@@ -150,6 +142,7 @@ module ActiveMerchant #:nodoc:
150
142
  post[:order][:installments] = options[:installments] if options[:installments]
151
143
  post[:order][:installments_type] = options[:installments_type] if options[:installments_type]
152
144
  post[:order][:taxable_amount] = options[:taxable_amount] if options[:taxable_amount]
145
+ post[:order][:tax_percentage] = options[:tax_percentage] if options[:tax_percentage]
153
146
  end
154
147
 
155
148
  def add_payment(post, payment)
@@ -223,10 +216,10 @@ module ActiveMerchant #:nodoc:
223
216
  end
224
217
 
225
218
  def message_from(response)
226
- if success_from(response)
227
- response['transaction'] && response['transaction']['message']
228
- else
219
+ if !success_from(response) && response['error']
229
220
  response['error'] && response['error']['type']
221
+ else
222
+ response['transaction'] && response['transaction']['message']
230
223
  end
231
224
  end
232
225
 
@@ -38,18 +38,6 @@ module ActiveMerchant #:nodoc:
38
38
  @express ||= PaypalExpressGateway.new(@options)
39
39
  end
40
40
 
41
- def supports_scrubbing?
42
- true
43
- end
44
-
45
- def scrub(transcript)
46
- transcript.
47
- gsub(%r((<n1:Password>).+(</n1:Password>)), '\1[FILTERED]\2').
48
- gsub(%r((<n1:Username>).+(</n1:Username>)), '\1[FILTERED]\2').
49
- gsub(%r((<n2:CreditCardNumber>).+(</n2:CreditCardNumber)), '\1[FILTERED]\2').
50
- gsub(%r((<n2:CVV2>)\d+(</n2:CVV2)), '\1[FILTERED]\2')
51
- end
52
-
53
41
  private
54
42
 
55
43
  def define_transaction_type(transaction_arg)
@@ -269,7 +269,21 @@ module ActiveMerchant #:nodoc:
269
269
  commit 'ManagePendingTransactionStatus', build_manage_pending_transaction_status(transaction_id, action)
270
270
  end
271
271
 
272
+ def supports_scrubbing?
273
+ true
274
+ end
275
+
276
+ def scrub(transcript)
277
+ transcript.
278
+ gsub(%r((<n1:Password>).+(</n1:Password>)), '\1[FILTERED]\2').
279
+ gsub(%r((<n1:Username>).+(</n1:Username>)), '\1[FILTERED]\2').
280
+ gsub(%r((<n1:Signature>).+(</n1:Signature>)), '\1[FILTERED]\2').
281
+ gsub(%r((<n2:CreditCardNumber>).+(</n2:CreditCardNumber)), '\1[FILTERED]\2').
282
+ gsub(%r((<n2:CVV2>)\d+(</n2:CVV2)), '\1[FILTERED]\2')
283
+ end
284
+
272
285
  private
286
+
273
287
  def build_request_wrapper(action, options = {})
274
288
  xml = Builder::XmlMarkup.new :indent => 2
275
289
  xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do