activemerchant 1.126.0 → 1.129.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +241 -0
  3. data/lib/active_merchant/billing/check.rb +40 -8
  4. data/lib/active_merchant/billing/credit_card.rb +28 -1
  5. data/lib/active_merchant/billing/credit_card_methods.rb +79 -23
  6. data/lib/active_merchant/billing/gateways/adyen.rb +67 -8
  7. data/lib/active_merchant/billing/gateways/airwallex.rb +40 -11
  8. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -4
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +18 -0
  11. data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -1
  12. data/lib/active_merchant/billing/gateways/bogus.rb +4 -0
  13. data/lib/active_merchant/billing/gateways/borgun.rb +56 -16
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +64 -17
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +27 -9
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +23 -0
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +228 -57
  18. data/lib/active_merchant/billing/gateways/commerce_hub.rb +361 -0
  19. data/lib/active_merchant/billing/gateways/credorax.rb +47 -27
  20. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  21. data/lib/active_merchant/billing/gateways/cyber_source.rb +100 -26
  22. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +456 -0
  23. data/lib/active_merchant/billing/gateways/d_local.rb +44 -5
  24. data/lib/active_merchant/billing/gateways/decidir.rb +15 -4
  25. data/lib/active_merchant/billing/gateways/ebanx.rb +36 -24
  26. data/lib/active_merchant/billing/gateways/element.rb +21 -1
  27. data/lib/active_merchant/billing/gateways/global_collect.rb +73 -22
  28. data/lib/active_merchant/billing/gateways/ipg.rb +13 -8
  29. data/lib/active_merchant/billing/gateways/iveri.rb +39 -3
  30. data/lib/active_merchant/billing/gateways/kushki.rb +21 -1
  31. data/lib/active_merchant/billing/gateways/litle.rb +25 -5
  32. data/lib/active_merchant/billing/gateways/mastercard.rb +1 -8
  33. data/lib/active_merchant/billing/gateways/mercado_pago.rb +17 -0
  34. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +44 -10
  35. data/lib/active_merchant/billing/gateways/monei.rb +2 -0
  36. data/lib/active_merchant/billing/gateways/moneris.rb +20 -5
  37. data/lib/active_merchant/billing/gateways/mundipagg.rb +3 -0
  38. data/lib/active_merchant/billing/gateways/ogone.rb +35 -7
  39. data/lib/active_merchant/billing/gateways/openpay.rb +20 -3
  40. data/lib/active_merchant/billing/gateways/orbital.rb +43 -22
  41. data/lib/active_merchant/billing/gateways/pay_trace.rb +64 -18
  42. data/lib/active_merchant/billing/gateways/payeezy.rb +59 -4
  43. data/lib/active_merchant/billing/gateways/paymentez.rb +18 -6
  44. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  45. data/lib/active_merchant/billing/gateways/paysafe.rb +22 -14
  46. data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -0
  47. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  48. data/lib/active_merchant/billing/gateways/priority.rb +29 -6
  49. data/lib/active_merchant/billing/gateways/rapyd.rb +110 -49
  50. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  51. data/lib/active_merchant/billing/gateways/redsys.rb +9 -5
  52. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -1
  53. data/lib/active_merchant/billing/gateways/securion_pay.rb +40 -0
  54. data/lib/active_merchant/billing/gateways/shift4.rb +342 -0
  55. data/lib/active_merchant/billing/gateways/simetrik.rb +28 -22
  56. data/lib/active_merchant/billing/gateways/stripe.rb +21 -1
  57. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +62 -22
  58. data/lib/active_merchant/billing/gateways/tns.rb +2 -5
  59. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +1 -1
  60. data/lib/active_merchant/billing/gateways/trust_commerce.rb +14 -3
  61. data/lib/active_merchant/billing/gateways/vanco.rb +12 -3
  62. data/lib/active_merchant/billing/gateways/visanet_peru.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/vpos.rb +7 -4
  64. data/lib/active_merchant/billing/gateways/wompi.rb +8 -4
  65. data/lib/active_merchant/billing/gateways/worldpay.rb +117 -9
  66. data/lib/active_merchant/billing/response.rb +15 -1
  67. data/lib/active_merchant/connection.rb +0 -2
  68. data/lib/active_merchant/country.rb +1 -0
  69. data/lib/active_merchant/errors.rb +4 -1
  70. data/lib/active_merchant/version.rb +1 -1
  71. metadata +24 -3
@@ -0,0 +1,342 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class Shift4Gateway < Gateway
4
+ self.test_url = 'https://utgapi.shift4test.com/api/rest/v1/'
5
+ self.live_url = 'https://utg.shift4api.net/api/rest/v1/'
6
+
7
+ self.supported_countries = %w(US CA CU HT DO PR JM TT GP MQ BS BB LC CW AW VC VI GD AG DM KY KN SX TC MF VG BQ AI BL MS)
8
+ self.default_currency = 'USD'
9
+ self.supported_cardtypes = %i[visa master american_express discover]
10
+
11
+ self.homepage_url = 'https://shift4.com'
12
+ self.display_name = 'Shift4'
13
+
14
+ RECURRING_TYPE_TRANSACTIONS = %w(recurring installment)
15
+ TRANSACTIONS_WITHOUT_RESPONSE_CODE = %w(accesstoken add)
16
+ SUCCESS_TRANSACTION_STATUS = %w(A)
17
+ DISALLOWED_ENTRY_MODE_ACTIONS = %w(capture refund add verify)
18
+ URL_POSTFIX_MAPPING = {
19
+ 'accesstoken' => 'credentials',
20
+ 'add' => 'tokens',
21
+ 'verify' => 'cards'
22
+ }
23
+ STANDARD_ERROR_CODE_MAPPING = {
24
+ 'incorrect_number' => STANDARD_ERROR_CODE[:incorrect_number],
25
+ 'invalid_number' => STANDARD_ERROR_CODE[:invalid_number],
26
+ 'invalid_expiry_month' => STANDARD_ERROR_CODE[:invalid_expiry_date],
27
+ 'invalid_expiry_year' => STANDARD_ERROR_CODE[:invalid_expiry_date],
28
+ 'invalid_cvc' => STANDARD_ERROR_CODE[:invalid_cvc],
29
+ 'expired_card' => STANDARD_ERROR_CODE[:expired_card],
30
+ 'insufficient_funds' => STANDARD_ERROR_CODE[:card_declined],
31
+ 'incorrect_cvc' => STANDARD_ERROR_CODE[:incorrect_cvc],
32
+ 'incorrect_zip' => STANDARD_ERROR_CODE[:incorrect_zip],
33
+ 'card_declined' => STANDARD_ERROR_CODE[:card_declined],
34
+ 'processing_error' => STANDARD_ERROR_CODE[:processing_error],
35
+ 'lost_or_stolen' => STANDARD_ERROR_CODE[:card_declined],
36
+ 'suspected_fraud' => STANDARD_ERROR_CODE[:card_declined],
37
+ 'expired_token' => STANDARD_ERROR_CODE[:card_declined]
38
+ }
39
+
40
+ def initialize(options = {})
41
+ requires!(options, :client_guid, :auth_token)
42
+ @client_guid = options[:client_guid]
43
+ @auth_token = options[:auth_token]
44
+ @access_token = options[:access_token]
45
+ super
46
+ end
47
+
48
+ def purchase(money, payment_method, options = {})
49
+ post = {}
50
+ action = 'sale'
51
+
52
+ payment_method = get_card_token(payment_method) if payment_method.is_a?(String)
53
+ add_datetime(post, options)
54
+ add_invoice(post, money, options)
55
+ add_clerk(post, options)
56
+ add_transaction(post, options)
57
+ add_card(action, post, payment_method, options)
58
+ add_card_present(post, options)
59
+ add_customer(post, payment_method, options)
60
+
61
+ commit(action, post, options)
62
+ end
63
+
64
+ def authorize(money, payment_method, options = {})
65
+ post = {}
66
+ action = 'authorization'
67
+
68
+ payment_method = get_card_token(payment_method) if payment_method.is_a?(String)
69
+ add_datetime(post, options)
70
+ add_invoice(post, money, options)
71
+ add_clerk(post, options)
72
+ add_transaction(post, options)
73
+ add_card(action, post, payment_method, options)
74
+ add_card_present(post, options)
75
+ add_customer(post, payment_method, options)
76
+
77
+ commit(action, post, options)
78
+ end
79
+
80
+ def capture(money, authorization, options = {})
81
+ post = {}
82
+ action = 'capture'
83
+ options[:invoice] = get_invoice(authorization)
84
+
85
+ add_datetime(post, options)
86
+ add_invoice(post, money, options)
87
+ add_clerk(post, options)
88
+ add_transaction(post, options)
89
+ add_card(action, post, get_card_token(authorization), options)
90
+
91
+ commit(action, post, options)
92
+ end
93
+
94
+ def refund(money, authorization, options = {})
95
+ post = {}
96
+ action = 'refund'
97
+
98
+ add_datetime(post, options)
99
+ add_invoice(post, money, options)
100
+ add_clerk(post, options)
101
+ add_transaction(post, options)
102
+ add_card(action, post, get_card_token(authorization), options)
103
+ add_card_present(post, options)
104
+
105
+ commit(action, post, options)
106
+ end
107
+
108
+ def void(authorization, options = {})
109
+ options[:invoice] = get_invoice(authorization)
110
+ commit('invoice', {}, options)
111
+ end
112
+
113
+ def verify(credit_card, options = {})
114
+ post = {}
115
+ action = 'verify'
116
+ post[:transaction] = {}
117
+
118
+ add_datetime(post, options)
119
+ add_card(action, post, credit_card, options)
120
+ add_customer(post, credit_card, options)
121
+ add_card_on_file(post[:transaction], options)
122
+
123
+ commit(action, post, options)
124
+ end
125
+
126
+ def store(credit_card, options = {})
127
+ post = {}
128
+ action = 'add'
129
+
130
+ add_datetime(post, options)
131
+ add_card(action, post, credit_card, options)
132
+ add_customer(post, credit_card, options)
133
+
134
+ commit(action, post, options)
135
+ end
136
+
137
+ def supports_scrubbing?
138
+ true
139
+ end
140
+
141
+ def scrub(transcript)
142
+ transcript.
143
+ gsub(%r(("Number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
144
+ gsub(%r(("expirationDate\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
145
+ gsub(%r(("FirstName\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
146
+ gsub(%r(("LastName\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
147
+ gsub(%r(("securityCode\\?":{\\?"[\w]+\\?":[\d]+,\\?"value\\?":\\?")[\d]*)i, '\1[FILTERED]')
148
+ end
149
+
150
+ def setup_access_token
151
+ post = {}
152
+ add_credentials(post, options)
153
+ add_datetime(post, options)
154
+
155
+ response = commit('accesstoken', post, request_headers('accesstoken', options))
156
+ raise OAuthResponseError.new(response, response.params.fetch('result', [{}]).first.dig('error', 'longText')) unless response.success?
157
+
158
+ response.params['result'].first['credential']['accessToken']
159
+ end
160
+
161
+ private
162
+
163
+ def add_credentials(post, options)
164
+ post[:credential] = {}
165
+ post[:credential][:clientGuid] = @client_guid
166
+ post[:credential][:authToken] = @auth_token
167
+ end
168
+
169
+ def add_clerk(post, options)
170
+ post[:clerk] = {}
171
+ post[:clerk][:numericId] = options[:clerk_id] || '1'
172
+ end
173
+
174
+ def add_invoice(post, money, options)
175
+ post[:amount] = {}
176
+ post[:amount][:total] = amount(money.to_f)
177
+ post[:amount][:tax] = options[:tax].to_f || 0.0
178
+ end
179
+
180
+ def add_datetime(post, options)
181
+ post[:dateTime] = options[:date_time] || current_date_time(options)
182
+ end
183
+
184
+ def add_transaction(post, options)
185
+ post[:transaction] = {}
186
+ post[:transaction][:invoice] = options[:invoice] || Time.new.to_i.to_s[1..3] + rand.to_s[2..7]
187
+ post[:transaction][:notes] = options[:notes] if options[:notes].present?
188
+ post[:transaction][:vendorReference] = options[:order_id]
189
+
190
+ add_purchase_card(post[:transaction], options)
191
+ add_card_on_file(post[:transaction], options)
192
+ end
193
+
194
+ def add_card(action, post, payment_method, options)
195
+ post[:card] = {}
196
+ post[:card][:entryMode] = options[:entry_mode] || 'M' unless DISALLOWED_ENTRY_MODE_ACTIONS.include?(action)
197
+ if payment_method.is_a?(CreditCard)
198
+ post[:card][:expirationDate] = "#{format(payment_method.month, :two_digits)}#{format(payment_method.year, :two_digits)}"
199
+ post[:card][:number] = payment_method.number
200
+ post[:card][:securityCode] = {}
201
+ post[:card][:securityCode][:indicator] = 1
202
+ post[:card][:securityCode][:value] = payment_method.verification_value
203
+ else
204
+ post[:card] = {} if post[:card].nil?
205
+ post[:card][:token] = {}
206
+ post[:card][:token][:value] = payment_method
207
+ post[:card][:expirationDate] = options[:expiration_date] if options[:expiration_date]
208
+ end
209
+ end
210
+
211
+ def add_card_present(post, options)
212
+ post[:card] = {} unless post[:card].present?
213
+
214
+ post[:card][:present] = options[:card_present] || 'N'
215
+ end
216
+
217
+ def add_customer(post, card, options)
218
+ address = options[:billing_address] || {}
219
+
220
+ post[:customer] = {}
221
+ post[:customer][:addressLine1] = address[:address1] if address[:address1]
222
+ post[:customer][:postalCode] = address[:zip] if address[:zip] && !address[:zip]&.to_s&.empty?
223
+ post[:customer][:firstName] = card.first_name if card.is_a?(CreditCard) && card.first_name
224
+ post[:customer][:lastName] = card.last_name if card.is_a?(CreditCard) && card.last_name
225
+ post[:customer][:emailAddress] = options[:email] if options[:email]
226
+ post[:customer][:ipAddress] = options[:ip] if options[:ip]
227
+ end
228
+
229
+ def add_purchase_card(post, options)
230
+ return unless options[:customer_reference] || options[:destination_postal_code] || options[:product_descriptors]
231
+
232
+ post[:purchaseCard] = {}
233
+ post[:purchaseCard][:customerReference] = options[:customer_reference] if options[:customer_reference]
234
+ post[:purchaseCard][:destinationPostalCode] = options[:destination_postal_code] if options[:destination_postal_code]
235
+ post[:purchaseCard][:productDescriptors] = options[:product_descriptors] if options[:product_descriptors]
236
+ end
237
+
238
+ def add_card_on_file(post, options)
239
+ return unless options[:stored_credential] || options[:usage_indicator] || options[:indicator] || options[:scheduled_indicator] || options[:transaction_id]
240
+
241
+ stored_credential = options[:stored_credential] || {}
242
+ post[:cardOnFile] = {}
243
+ post[:cardOnFile][:usageIndicator] = options[:usage_indicator] || (stored_credential[:initial_transaction] ? '01' : '02')
244
+ post[:cardOnFile][:indicator] = options[:indicator] || '01'
245
+ post[:cardOnFile][:scheduledIndicator] = options[:scheduled_indicator] || (RECURRING_TYPE_TRANSACTIONS.include?(stored_credential[:reason_type]) ? '01' : '02')
246
+ post[:cardOnFile][:transactionId] = options[:transaction_id] || stored_credential[:network_transaction_id] if options[:transaction_id] || stored_credential[:network_transaction_id]
247
+ end
248
+
249
+ def commit(action, parameters, option)
250
+ url_postfix = URL_POSTFIX_MAPPING[action] || 'transactions'
251
+ url = (test? ? "#{test_url}#{url_postfix}/#{action}" : "#{live_url}#{url_postfix}/#{action}")
252
+ if action == 'invoice'
253
+ response = parse(ssl_request(:delete, url, parameters.to_json, request_headers(action, option)))
254
+ else
255
+ response = parse(ssl_post(url, parameters.to_json, request_headers(action, option)))
256
+ end
257
+
258
+ Response.new(
259
+ success_from(action, response),
260
+ message_from(action, response),
261
+ response,
262
+ authorization: authorization_from(action, response),
263
+ test: test?,
264
+ error_code: error_code_from(action, response)
265
+ )
266
+ end
267
+
268
+ def handle_response(response)
269
+ case response.code.to_i
270
+ when 200...300, 400, 401, 500
271
+ response.body
272
+ else
273
+ raise ResponseError.new(response)
274
+ end
275
+ end
276
+
277
+ def parse(body)
278
+ return {} if body == ''
279
+
280
+ JSON.parse(body)
281
+ end
282
+
283
+ def message_from(action, response)
284
+ success_from(action, response) ? 'Transaction successful' : (error(response)&.dig('longText') || 'Transaction declined')
285
+ end
286
+
287
+ def error_code_from(action, response)
288
+ return unless success_from(action, response)
289
+
290
+ STANDARD_ERROR_CODE_MAPPING[response['primaryCode']]
291
+ end
292
+
293
+ def authorization_from(action, response)
294
+ return unless success_from(action, response)
295
+
296
+ authorization = response.dig('result', 0, 'card', 'token', 'value').to_s
297
+ invoice = response.dig('result', 0, 'transaction', 'invoice')
298
+ authorization += "|#{invoice}" if invoice
299
+ authorization
300
+ end
301
+
302
+ def get_card_token(authorization)
303
+ authorization.is_a?(CreditCard) ? authorization : authorization.split('|')[0]
304
+ end
305
+
306
+ def get_invoice(authorization)
307
+ authorization.is_a?(CreditCard) ? authorization : authorization.split('|')[1]
308
+ end
309
+
310
+ def request_headers(action, options)
311
+ headers = {
312
+ 'Content-Type' => 'application/json'
313
+ }
314
+ headers['AccessToken'] = @access_token
315
+ headers['Invoice'] = options[:invoice] if action != 'capture' && options[:invoice].present?
316
+ headers['InterfaceVersion'] = '1'
317
+ headers['InterfaceName'] = 'Spreedly'
318
+ headers['CompanyName'] = 'Spreedly'
319
+ headers
320
+ end
321
+
322
+ def success_from(action, response)
323
+ success = error(response).nil?
324
+ success &&= SUCCESS_TRANSACTION_STATUS.include?(response['result'].first['transaction']['responseCode']) unless TRANSACTIONS_WITHOUT_RESPONSE_CODE.include?(action)
325
+ success
326
+ end
327
+
328
+ def error(response)
329
+ server_error = { 'longText' => response['error'] } if response['error']
330
+ server_error || response['result'].first['error']
331
+ end
332
+
333
+ def current_date_time(options = {})
334
+ time_zone = options[:merchant_time_zone] || 'Pacific Time (US & Canada)'
335
+ time = Time.now.in_time_zone(time_zone)
336
+ offset = Time.now.in_time_zone(time_zone).formatted_offset
337
+
338
+ time.strftime('%Y-%m-%dT%H:%M:%S.%3N') + offset
339
+ end
340
+ end
341
+ end
342
+ end
@@ -4,10 +4,13 @@ module ActiveMerchant #:nodoc:
4
4
  self.test_url = 'https://payments.sta.simetrik.com/v1'
5
5
  self.live_url = 'https://payments.simetrik.com/v1'
6
6
 
7
- class_attribute :test_auth_url, :live_auth_url
7
+ class_attribute :test_auth_url, :live_auth_url, :test_audience, :live_audience
8
8
  self.test_auth_url = 'https://tenant-payments-dev.us.auth0.com/oauth/token'
9
9
  self.live_auth_url = 'https://tenant-payments-prod.us.auth0.com/oauth/token'
10
10
 
11
+ self.test_audience = 'https://tenant-payments-dev.us.auth0.com/api/v2/'
12
+ self.live_audience = 'https://tenant-payments-prod.us.auth0.com/api/v2/'
13
+
11
14
  self.supported_countries = %w(PE AR)
12
15
  self.default_currency = 'USD'
13
16
  self.supported_cardtypes = %i[visa master american_express discover]
@@ -39,7 +42,7 @@ module ActiveMerchant #:nodoc:
39
42
  }
40
43
 
41
44
  def initialize(options = {})
42
- requires!(options, :client_id, :client_secret, :audience)
45
+ requires!(options, :client_id, :client_secret)
43
46
  super
44
47
  @access_token = {}
45
48
  sign_access_token()
@@ -52,7 +55,6 @@ module ActiveMerchant #:nodoc:
52
55
  add_forward_route(post, options)
53
56
  add_forward_payload(post, money, payment, options)
54
57
  add_stored_credential(post, options)
55
-
56
58
  commit('authorize', post, { token_acquirer: options[:token_acquirer] })
57
59
  end
58
60
 
@@ -70,7 +72,7 @@ module ActiveMerchant #:nodoc:
70
72
  acquire_extra_options: options[:acquire_extra_options] || {}
71
73
  }
72
74
  }
73
- post[:forward_payload][:amount][:vat] = options[:vat] if options[:vat]
75
+ post[:forward_payload][:amount][:vat] = options[:vat].to_f / 100 if options[:vat]
74
76
 
75
77
  add_forward_route(post, options)
76
78
  commit('capture', post, { token_acquirer: options[:token_acquirer] })
@@ -127,12 +129,10 @@ module ActiveMerchant #:nodoc:
127
129
 
128
130
  def scrub(transcript)
129
131
  transcript.
130
- gsub(%r((\"number\\\":\\\")\d+), '\1[FILTERED]').
131
- gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]').
132
- gsub(%r((\"exp_month\\\":\\\")\d+), '\1[FILTERED]').
133
- gsub(%r((\"exp_year\\\":\\\")\d+), '\1[FILTERED]').
134
- gsub(%r((\"holder_first_name\\\":\\\")"\w+"), '\1[FILTERED]').
135
- gsub(%r((\"holder_last_name\\\":\\\")"\w+"), '\1[FILTERED]')
132
+ gsub(%r((Authorization: Bearer ).+), '\1[FILTERED]').
133
+ gsub(%r(("client_secret\\?":\\?")\w+), '\1[FILTERED]').
134
+ gsub(%r(("number\\?":\\?")\d+), '\1[FILTERED]').
135
+ gsub(%r(("security_code\\?":\\?")\d+), '\1[FILTERED]')
136
136
  end
137
137
 
138
138
  private
@@ -148,7 +148,7 @@ module ActiveMerchant #:nodoc:
148
148
  def add_forward_payload(post, money, payment, options)
149
149
  forward_payload = {}
150
150
  add_user(forward_payload, options[:user]) if options[:user]
151
- add_order(forward_payload, money, options[:order]) if options[:order] || money
151
+ add_order(forward_payload, money, options)
152
152
  add_payment_method(forward_payload, payment, options[:payment_method]) if options[:payment_method] || payment
153
153
 
154
154
  forward_payload[:payment_method] = {} unless forward_payload[:payment_method]
@@ -230,29 +230,34 @@ module ActiveMerchant #:nodoc:
230
230
  post[:forward_payload][:authentication][:stored_credential] = options[:stored_credential] if check_initiator && check_reason_type
231
231
  end
232
232
 
233
- def add_order(post, money, order_options)
233
+ def add_order(post, money, options)
234
+ return unless options[:order] || money
235
+
234
236
  order = {}
235
- order[:id] = order_options[:id] if order_options[:id]
236
- order[:description] = order_options[:description] if order_options[:description]
237
- order[:installments] = order_options[:installments] if order_options[:installments]
237
+ order_options = options[:order] || {}
238
+ order[:id] = options[:order_id] if options[:order_id]
239
+ order[:description] = options[:description] if options[:description]
240
+ order[:installments] = order_options[:installments].to_i if order_options[:installments]
238
241
  order[:datetime_local_transaction] = order_options[:datetime_local_transaction] if order_options[:datetime_local_transaction]
239
242
 
240
- add_amount(order, money, order_options[:amount]) if order_options[:amount]
241
- add_address('shipping_address', order, order_options[:shipping_address]) if order_options[:shipping_address]
243
+ add_amount(order, money, options)
244
+ add_address('shipping_address', order, options)
242
245
 
243
246
  post[:order] = order
244
247
  end
245
248
 
246
- def add_amount(post, money, amount_options)
249
+ def add_amount(post, money, options)
247
250
  amount_obj = {}
248
251
  amount_obj[:total_amount] = amount(money).to_f
249
- amount_obj[:currency] = (amount_options[:currency] || currency(money))
250
- amount_obj[:vat] = amount_options[:vat] if amount_options[:vat]
252
+ amount_obj[:currency] = (options[:currency] || currency(money))
253
+ amount_obj[:vat] = options[:vat].to_f / 100 if options[:vat]
251
254
 
252
255
  post[:amount] = amount_obj
253
256
  end
254
257
 
255
- def add_address(tag, post, address_options)
258
+ def add_address(tag, post, options)
259
+ return unless address_options = options[:shipping_address]
260
+
256
261
  address = {}
257
262
  address[:name] = address_options[:name] if address_options[:name]
258
263
  address[:address1] = address_options[:address1] if address_options[:address1]
@@ -335,6 +340,7 @@ module ActiveMerchant #:nodoc:
335
340
  }
336
341
  end
337
342
 
343
+ # if this method is refactored, ensure that the client_secret is properly scrubbed
338
344
  def sign_access_token
339
345
  fetch_access_token() if Time.new.to_i > (@access_token[:expires_at] || 0) + 10
340
346
  @access_token[:access_token]
@@ -348,7 +354,7 @@ module ActiveMerchant #:nodoc:
348
354
  login_info = {}
349
355
  login_info[:client_id] = @options[:client_id]
350
356
  login_info[:client_secret] = @options[:client_secret]
351
- login_info[:audience] = @options[:audience]
357
+ login_info[:audience] = test? ? test_audience : live_audience
352
358
  login_info[:grant_type] = 'client_credentials'
353
359
  response = parse(ssl_post(auth_url(), login_info.to_json, {
354
360
  'content-Type' => 'application/json'
@@ -145,6 +145,7 @@ module ActiveMerchant #:nodoc:
145
145
 
146
146
  def void(identification, options = {})
147
147
  post = {}
148
+ post[:reverse_transfer] = options[:reverse_transfer] if options[:reverse_transfer]
148
149
  post[:metadata] = options[:metadata] if options[:metadata]
149
150
  post[:reason] = options[:reason] if options[:reason]
150
151
  post[:expand] = [:charge]
@@ -280,6 +281,7 @@ module ActiveMerchant #:nodoc:
280
281
  def scrub(transcript)
281
282
  transcript.
282
283
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
284
+ gsub(%r((Authorization: Bearer )\w+), '\1[FILTERED]').
283
285
  gsub(%r((&?three_d_secure\[cryptogram\]=)[\w=]*(&?)), '\1[FILTERED]\2').
284
286
  gsub(%r(((\[card\]|card)\[cryptogram\]=)[^&]+(&?)), '\1[FILTERED]\3').
285
287
  gsub(%r(((\[card\]|card)\[cvc\]=)\d+), '\1[FILTERED]').
@@ -301,7 +303,7 @@ module ActiveMerchant #:nodoc:
301
303
  def delete_latest_test_external_account(account)
302
304
  return unless test?
303
305
 
304
- auth_header = { 'Authorization': "Bearer #{options[:login]}" }
306
+ auth_header = { 'Authorization' => 'Basic ' + Base64.strict_encode64(options[:login].to_s + ':').strip }
305
307
  url = "#{live_url}accounts/#{CGI.escape(account)}/external_accounts"
306
308
  accounts_response = JSON.parse(ssl_get("#{url}?limit=100", auth_header))
307
309
  to_delete = accounts_response['data'].reject { |ac| ac['default_for_currency'] }
@@ -389,6 +391,7 @@ module ActiveMerchant #:nodoc:
389
391
  end
390
392
 
391
393
  add_metadata(post, options)
394
+ add_shipping_address(post, payment, options)
392
395
  add_application_fee(post, options)
393
396
  add_exchange_rate(post, options)
394
397
  add_destination(post, options)
@@ -555,6 +558,23 @@ module ActiveMerchant #:nodoc:
555
558
  post[:metadata][:card_read_method] = creditcard.read_method if creditcard.respond_to?(:read_method)
556
559
  end
557
560
 
561
+ def add_shipping_address(post, payment, options = {})
562
+ return unless shipping = options[:shipping_address]
563
+ return unless shipping_name = shipping[:name]
564
+
565
+ post[:shipping] = {}
566
+
567
+ post[:shipping][:name] = shipping_name
568
+ post[:shipping][:address] = {}
569
+ post[:shipping][:address][:line1] = shipping[:address1]
570
+ post[:shipping][:address][:line2] = shipping[:address2] if shipping[:address2]
571
+ post[:shipping][:address][:city] = shipping[:city] if shipping[:city]
572
+ post[:shipping][:address][:country] = shipping[:country] if shipping[:country]
573
+ post[:shipping][:address][:state] = shipping[:state] if shipping[:state]
574
+ post[:shipping][:address][:postal_code] = shipping[:zip] if shipping[:zip]
575
+ post[:shipping][:phone] = shipping[:phone_number] if shipping[:phone_number]
576
+ end
577
+
558
578
  def add_source_owner(post, creditcard, options)
559
579
  post[:owner] = {}
560
580
  post[:owner][:name] = creditcard.name if creditcard.name