activemerchant 1.125.0 → 1.126.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.
- checksums.yaml +4 -4
- data/CHANGELOG +75 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +12 -0
- data/lib/active_merchant/billing/gateway.rb +2 -1
- data/lib/active_merchant/billing/gateways/adyen.rb +7 -4
- data/lib/active_merchant/billing/gateways/airwallex.rb +341 -0
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +2 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/blue_snap.rb +31 -21
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +6 -1
- data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +87 -15
- data/lib/active_merchant/billing/gateways/card_connect.rb +1 -1
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +1 -1
- data/lib/active_merchant/billing/gateways/credorax.rb +10 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +13 -33
- data/lib/active_merchant/billing/gateways/d_local.rb +49 -0
- data/lib/active_merchant/billing/gateways/decidir.rb +17 -1
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +185 -14
- data/lib/active_merchant/billing/gateways/ebanx.rb +3 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +26 -16
- data/lib/active_merchant/billing/gateways/ipg.rb +1 -2
- data/lib/active_merchant/billing/gateways/litle.rb +93 -1
- data/lib/active_merchant/billing/gateways/moneris.rb +35 -8
- data/lib/active_merchant/billing/gateways/nmi.rb +12 -7
- data/lib/active_merchant/billing/gateways/orbital.rb +349 -327
- data/lib/active_merchant/billing/gateways/payflow.rb +62 -0
- data/lib/active_merchant/billing/gateways/paymentez.rb +26 -7
- data/lib/active_merchant/billing/gateways/paysafe.rb +15 -15
- data/lib/active_merchant/billing/gateways/payu_latam.rb +25 -15
- data/lib/active_merchant/billing/gateways/priority.rb +158 -136
- data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
- data/lib/active_merchant/billing/gateways/safe_charge.rb +1 -4
- data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +4 -2
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +93 -48
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +6 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +6 -2
@@ -50,69 +50,75 @@ module ActiveMerchant #:nodoc:
|
|
50
50
|
|
51
51
|
def purchase(amount, credit_card, options = {})
|
52
52
|
params = {}
|
53
|
-
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
54
53
|
params['authOnly'] = false
|
54
|
+
params['isSettleFunds'] = true
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
add_merchant_id(params)
|
57
|
+
add_amount(params, amount, options)
|
58
|
+
add_auth_purchase_params(params, credit_card, options)
|
59
|
+
|
60
|
+
commit('purchase', params: params)
|
59
61
|
end
|
60
62
|
|
61
63
|
def authorize(amount, credit_card, options = {})
|
62
64
|
params = {}
|
63
|
-
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
64
65
|
params['authOnly'] = true
|
66
|
+
params['isSettleFunds'] = false
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
add_merchant_id(params)
|
69
|
+
add_amount(params, amount, options)
|
70
|
+
add_auth_purchase_params(params, credit_card, options)
|
71
|
+
|
72
|
+
commit('purchase', params: params)
|
69
73
|
end
|
70
74
|
|
71
75
|
def refund(amount, authorization, options = {})
|
72
76
|
params = {}
|
73
|
-
params
|
74
|
-
params['paymentToken'] =
|
77
|
+
add_merchant_id(params)
|
78
|
+
params['paymentToken'] = payment_token(authorization) || options[:payment_token]
|
79
|
+
|
75
80
|
# refund amounts must be negative
|
76
81
|
params['amount'] = ('-' + localized_amount(amount.to_f, options[:currency])).to_f
|
77
|
-
|
82
|
+
|
83
|
+
commit('refund', params: params)
|
78
84
|
end
|
79
85
|
|
80
86
|
def capture(amount, authorization, options = {})
|
81
87
|
params = {}
|
82
|
-
params
|
83
|
-
params
|
84
|
-
params['
|
85
|
-
params['
|
86
|
-
params['shouldGetCreditCardLevel'] = true
|
87
|
-
params['source'] = options[:source]
|
88
|
-
params['tenderType'] = 'Card'
|
88
|
+
add_merchant_id(params)
|
89
|
+
add_amount(params, amount, options)
|
90
|
+
params['paymentToken'] = payment_token(authorization) || options[:payment_token]
|
91
|
+
params['tenderType'] = options[:tender_type].present? ? options[:tender_type] : 'Card'
|
89
92
|
|
90
|
-
commit('capture', params: params
|
93
|
+
commit('capture', params: params)
|
91
94
|
end
|
92
95
|
|
93
96
|
def void(authorization, options = {})
|
94
|
-
|
97
|
+
params = {}
|
98
|
+
|
99
|
+
commit('void', params: params, iid: payment_id(authorization))
|
95
100
|
end
|
96
101
|
|
97
|
-
def verify(credit_card,
|
98
|
-
jwt =
|
102
|
+
def verify(credit_card, _options = {})
|
103
|
+
jwt = create_jwt.params['jwtToken']
|
104
|
+
|
99
105
|
commit('verify', card_number: credit_card.number, jwt: jwt)
|
100
106
|
end
|
101
107
|
|
102
|
-
def
|
103
|
-
|
108
|
+
def get_payment_status(batch_id)
|
109
|
+
commit('get_payment_status', params: batch_id)
|
104
110
|
end
|
105
111
|
|
106
|
-
def
|
107
|
-
commit('
|
112
|
+
def close_batch(batch_id)
|
113
|
+
commit('close_batch', params: batch_id)
|
108
114
|
end
|
109
115
|
|
110
|
-
def
|
111
|
-
commit('
|
116
|
+
def create_jwt
|
117
|
+
commit('create_jwt', params: @options[:merchant_id])
|
112
118
|
end
|
113
119
|
|
114
|
-
def
|
115
|
-
|
120
|
+
def supports_scrubbing?
|
121
|
+
true
|
116
122
|
end
|
117
123
|
|
118
124
|
def scrub(transcript)
|
@@ -122,11 +128,33 @@ module ActiveMerchant #:nodoc:
|
|
122
128
|
gsub(%r((cvv\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
|
123
129
|
end
|
124
130
|
|
131
|
+
private
|
132
|
+
|
133
|
+
def add_amount(params, amount, options)
|
134
|
+
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_merchant_id(params)
|
138
|
+
params['merchantId'] = @options[:merchant_id]
|
139
|
+
end
|
140
|
+
|
141
|
+
def add_auth_purchase_params(params, credit_card, options)
|
142
|
+
add_replay_id(params, options)
|
143
|
+
add_credit_card(params, credit_card, 'purchase', options)
|
144
|
+
add_purchases_data(params, options)
|
145
|
+
add_shipping_data(params, options)
|
146
|
+
add_pos_data(params, options)
|
147
|
+
add_additional_data(params, options)
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_replay_id(params, options)
|
151
|
+
params['replayId'] = options[:replay_id] if options[:replay_id]
|
152
|
+
end
|
153
|
+
|
125
154
|
def add_credit_card(params, credit_card, action, options)
|
126
155
|
return unless credit_card&.is_a?(CreditCard)
|
127
156
|
|
128
157
|
card_details = {}
|
129
|
-
|
130
158
|
card_details['expiryMonth'] = format(credit_card.month, :two_digits).to_s
|
131
159
|
card_details['expiryYear'] = format(credit_card.year, :two_digits).to_s
|
132
160
|
card_details['expiryDate'] = exp_date(credit_card)
|
@@ -134,23 +162,8 @@ module ActiveMerchant #:nodoc:
|
|
134
162
|
card_details['last4'] = credit_card.last_digits
|
135
163
|
card_details['cvv'] = credit_card.verification_value
|
136
164
|
card_details['number'] = credit_card.number
|
137
|
-
|
138
|
-
card_details['
|
139
|
-
|
140
|
-
case action
|
141
|
-
when 'purchase'
|
142
|
-
card_details['avsStreet'] = options[:billing_address][:address1] if options[:billing_address]
|
143
|
-
card_details['avsZip'] = options[:billing_address][:zip] if options[:billing_address]
|
144
|
-
when 'refund'
|
145
|
-
card_details['cardId'] = options[:card_id]
|
146
|
-
card_details['cardPresent'] = options[:card_present]
|
147
|
-
card_details['hasContract'] = options[:has_contract]
|
148
|
-
card_details['isCorp'] = options[:is_corp]
|
149
|
-
card_details['isDebit'] = options[:is_debit]
|
150
|
-
card_details['token'] = options[:token]
|
151
|
-
else
|
152
|
-
card_details
|
153
|
-
end
|
165
|
+
card_details['avsStreet'] = options[:billing_address][:address1] if options[:billing_address]
|
166
|
+
card_details['avsZip'] = options[:billing_address][:zip] if options[:billing_address]
|
154
167
|
|
155
168
|
params['cardAccount'] = card_details
|
156
169
|
end
|
@@ -159,29 +172,86 @@ module ActiveMerchant #:nodoc:
|
|
159
172
|
"#{format(credit_card.month, :two_digits)}/#{format(credit_card.year, :two_digits)}"
|
160
173
|
end
|
161
174
|
|
162
|
-
def
|
163
|
-
[
|
175
|
+
def add_additional_data(params, options)
|
176
|
+
params['isAuth'] = options[:is_auth].present? ? options[:is_auth] : 'true'
|
177
|
+
params['paymentType'] = options[:payment_type].present? ? options[:payment_type] : 'Sale'
|
178
|
+
params['tenderType'] = options[:tender_type].present? ? options[:tender_type] : 'Card'
|
179
|
+
params['taxExempt'] = options[:tax_exempt].present? ? options[:tax_exempt] : 'false'
|
180
|
+
params['taxAmount'] = options[:tax_amount] if options[:tax_amount]
|
181
|
+
params['shouldGetCreditCardLevel'] = options[:should_get_credit_card_level] if options[:should_get_credit_card_level]
|
182
|
+
params['source'] = options[:source] if options[:source]
|
183
|
+
params['invoice'] = options[:invoice] if options[:invoice]
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_pos_data(params, options)
|
187
|
+
pos_data = {}
|
188
|
+
|
189
|
+
pos_data['cardholderPresence'] = options.dig(:pos_data, :cardholder_presence) || 'Ecom'
|
190
|
+
pos_data['deviceAttendance'] = options.dig(:pos_data, :device_attendance) || 'HomePc'
|
191
|
+
pos_data['deviceInputCapability'] = options.dig(:pos_data, :device_input_capability) || 'Unknown'
|
192
|
+
pos_data['deviceLocation'] = options.dig(:pos_data, :device_location) || 'HomePc'
|
193
|
+
pos_data['panCaptureMethod'] = options.dig(:pos_data, :pan_capture_method) || 'Manual'
|
194
|
+
pos_data['partialApprovalSupport'] = options.dig(:pos_data, :partial_approval_support) || 'NotSupported'
|
195
|
+
pos_data['pinCaptureCapability'] = options.dig(:pos_data, :pin_capture_capability) || 'Incapable'
|
196
|
+
|
197
|
+
params['posData'] = pos_data
|
198
|
+
end
|
199
|
+
|
200
|
+
def add_purchases_data(params, options)
|
201
|
+
return unless options[:purchases]
|
202
|
+
|
203
|
+
params['purchases'] = []
|
204
|
+
|
205
|
+
options[:purchases].each do |purchase|
|
206
|
+
purchase_object = {}
|
207
|
+
|
208
|
+
purchase_object['name'] = purchase[:name] if purchase[:name]
|
209
|
+
purchase_object['description'] = purchase[:description] if purchase[:description]
|
210
|
+
purchase_object['code'] = purchase[:code] if purchase[:code]
|
211
|
+
purchase_object['unitOfMeasure'] = purchase[:unit_of_measure] if purchase[:unit_of_measure]
|
212
|
+
purchase_object['unitPrice'] = purchase[:unit_price] if purchase[:unit_price]
|
213
|
+
purchase_object['quantity'] = purchase[:quantity] if purchase[:quantity]
|
214
|
+
purchase_object['taxRate'] = purchase[:tax_rate] if purchase[:tax_rate]
|
215
|
+
purchase_object['taxAmount'] = purchase[:tax_amount] if purchase[:tax_amount]
|
216
|
+
purchase_object['discountRate'] = purchase[:discount_rate] if purchase[:discount_rate]
|
217
|
+
purchase_object['discountAmount'] = purchase[:discount_amount] if purchase[:discount_amount]
|
218
|
+
purchase_object['extendedAmount'] = purchase[:extended_amount] if purchase[:extended_amount]
|
219
|
+
purchase_object['lineItemId'] = purchase[:line_item_id] if purchase[:line_item_id]
|
220
|
+
|
221
|
+
params['purchases'].append(purchase_object)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def add_shipping_data(params, options)
|
226
|
+
params['shipAmount'] = options[:ship_amount] if options[:ship_amount]
|
227
|
+
|
228
|
+
shipping_country = shipping_country_from(options)
|
229
|
+
params['shipToCountry'] = shipping_country if shipping_country
|
230
|
+
|
231
|
+
shipping_zip = shipping_zip_from(options)
|
232
|
+
params['shipToZip'] = shipping_zip if shipping_zip
|
233
|
+
end
|
234
|
+
|
235
|
+
def shipping_country_from(options)
|
236
|
+
options[:ship_to_country] || options.dig(:shipping_address, :country) || options.dig(:billing_address, :country)
|
237
|
+
end
|
238
|
+
|
239
|
+
def shipping_zip_from(options)
|
240
|
+
options[:ship_to_zip] || options.dig(:shipping_addres, :zip) || options.dig(:billing_address, :zip)
|
164
241
|
end
|
165
242
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
169
|
-
params['isAuth'] = true
|
170
|
-
params['isSettleFunds'] = is_settle_funds
|
171
|
-
params['isTicket'] = false
|
243
|
+
def payment_token(authorization)
|
244
|
+
return unless authorization
|
245
|
+
return authorization unless authorization.include?('|')
|
172
246
|
|
173
|
-
|
174
|
-
|
175
|
-
params['paymentType'] = 'Sale'
|
247
|
+
authorization.split('|').last
|
248
|
+
end
|
176
249
|
|
177
|
-
|
250
|
+
def payment_id(authorization)
|
251
|
+
return unless authorization
|
252
|
+
return authorization unless authorization.include?('|')
|
178
253
|
|
179
|
-
|
180
|
-
params['shouldVaultCard'] = true
|
181
|
-
params['source'] = options[:source]
|
182
|
-
params['sourceZip'] = options[:billing_address][:zip] if options[:billing_address]
|
183
|
-
params['taxExempt'] = false
|
184
|
-
params['tenderType'] = 'Card'
|
254
|
+
authorization.split('|').first
|
185
255
|
end
|
186
256
|
|
187
257
|
def commit(action, params: '', iid: '', card_number: nil, jwt: '')
|
@@ -200,10 +270,12 @@ module ActiveMerchant #:nodoc:
|
|
200
270
|
parse(ssl_post(url(action, params), post_data(params), request_headers))
|
201
271
|
end
|
202
272
|
rescue ResponseError => e
|
203
|
-
|
273
|
+
# currently Priority returns a 404 with no body on certain calls. In those cases we will substitute the response status from response.message
|
274
|
+
gateway_response = e.response.body.presence || e.response.message
|
275
|
+
parse(gateway_response)
|
204
276
|
end
|
277
|
+
|
205
278
|
success = success_from(response, action)
|
206
|
-
response = { 'code' => '204' } if response == ''
|
207
279
|
Response.new(
|
208
280
|
success,
|
209
281
|
message_from(response),
|
@@ -214,16 +286,6 @@ module ActiveMerchant #:nodoc:
|
|
214
286
|
)
|
215
287
|
end
|
216
288
|
|
217
|
-
def handle_response(response)
|
218
|
-
if response.code != '204' && (200...300).cover?(response.code.to_i)
|
219
|
-
response.body
|
220
|
-
elsif response.code == '204' || response == ''
|
221
|
-
response.body = { 'code' => '204' }
|
222
|
-
else
|
223
|
-
raise ResponseError.new(response)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
289
|
def url(action, params, ref_number: '', credit_card_number: nil)
|
228
290
|
case action
|
229
291
|
when 'void'
|
@@ -255,10 +317,22 @@ module ActiveMerchant #:nodoc:
|
|
255
317
|
test? ? self.test_url_batch : self.live_url_batch
|
256
318
|
end
|
257
319
|
|
320
|
+
def handle_response(response)
|
321
|
+
case response.code.to_i
|
322
|
+
when 204
|
323
|
+
{ status: 'Success' }.to_json
|
324
|
+
when 200...300
|
325
|
+
response.body
|
326
|
+
else
|
327
|
+
raise ResponseError.new(response)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
258
331
|
def parse(body)
|
259
|
-
return
|
332
|
+
return {} if body.blank?
|
260
333
|
|
261
|
-
JSON.parse(body)
|
334
|
+
parsed_response = JSON.parse(body)
|
335
|
+
parsed_response.is_a?(String) ? { 'message' => parsed_response } : parsed_response
|
262
336
|
rescue JSON::ParserError
|
263
337
|
message = 'Invalid JSON response received from Priority Gateway. Please contact Priority Gateway if you continue to receive this message.'
|
264
338
|
message += " (The raw response returned by the API was #{body.inspect})"
|
@@ -268,10 +342,9 @@ module ActiveMerchant #:nodoc:
|
|
268
342
|
end
|
269
343
|
|
270
344
|
def success_from(response, action)
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
success
|
345
|
+
return !response['bank'].empty? if action == 'verify' && response['bank']
|
346
|
+
|
347
|
+
%w[Approved Open Success Settled Voided].include?(response['status'])
|
275
348
|
end
|
276
349
|
|
277
350
|
def message_from(response)
|
@@ -281,10 +354,7 @@ module ActiveMerchant #:nodoc:
|
|
281
354
|
end
|
282
355
|
|
283
356
|
def authorization_from(response)
|
284
|
-
|
285
|
-
'payment_token' => response['paymentToken'],
|
286
|
-
'id' => response['id']
|
287
|
-
}
|
357
|
+
[response['id'], response['paymentToken']].join('|')
|
288
358
|
end
|
289
359
|
|
290
360
|
def error_from(response)
|
@@ -294,54 +364,6 @@ module ActiveMerchant #:nodoc:
|
|
294
364
|
def post_data(params)
|
295
365
|
params.to_json
|
296
366
|
end
|
297
|
-
|
298
|
-
def add_pos_data(options)
|
299
|
-
pos_options = {}
|
300
|
-
pos_options['panCaptureMethod'] = options[:pan_capture_method]
|
301
|
-
|
302
|
-
pos_options
|
303
|
-
end
|
304
|
-
|
305
|
-
def add_purchases_data(options)
|
306
|
-
purchases = {}
|
307
|
-
|
308
|
-
purchases['dateCreated'] = options[:date_created]
|
309
|
-
purchases['iId'] = options[:i_id]
|
310
|
-
purchases['transactionIId'] = options[:transaction_i_id]
|
311
|
-
purchases['transactionId'] = options[:transaction_id]
|
312
|
-
purchases['name'] = options[:name]
|
313
|
-
purchases['description'] = options[:description]
|
314
|
-
purchases['code'] = options[:code]
|
315
|
-
purchases['unitOfMeasure'] = options[:unit_of_measure]
|
316
|
-
purchases['unitPrice'] = options[:unit_price]
|
317
|
-
purchases['quantity'] = options[:quantity]
|
318
|
-
purchases['taxRate'] = options[:tax_rate]
|
319
|
-
purchases['taxAmount'] = options[:tax_amount]
|
320
|
-
purchases['discountRate'] = options[:discount_rate]
|
321
|
-
purchases['discountAmount'] = options[:discount_amt]
|
322
|
-
purchases['extendedAmount'] = options[:extended_amt]
|
323
|
-
purchases['lineItemId'] = options[:line_item_id]
|
324
|
-
|
325
|
-
purchase_arr = []
|
326
|
-
purchase_arr[0] = purchases
|
327
|
-
purchase_arr
|
328
|
-
end
|
329
|
-
|
330
|
-
def add_risk_data(options)
|
331
|
-
risk = {}
|
332
|
-
risk['cvvResponseCode'] = options[:cvv_response_code]
|
333
|
-
risk['cvvResponse'] = options[:cvv_response]
|
334
|
-
risk['cvvMatch'] = options[:cvv_match]
|
335
|
-
risk['avsResponse'] = options[:avs_response]
|
336
|
-
risk['avsAddressMatch'] = options[:avs_address_match]
|
337
|
-
risk['avsZipMatch'] = options[:avs_zip_match]
|
338
|
-
|
339
|
-
risk
|
340
|
-
end
|
341
|
-
|
342
|
-
def get_hash(string)
|
343
|
-
JSON.parse(string.gsub('=>', ':'))
|
344
|
-
end
|
345
367
|
end
|
346
368
|
end
|
347
369
|
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class RapydGateway < Gateway
|
4
|
+
self.test_url = 'https://sandboxapi.rapyd.net/v1/'
|
5
|
+
self.live_url = 'https://api.rapyd.net/v1/'
|
6
|
+
|
7
|
+
self.supported_countries = %w(US BR CA CL CO DO SV MX PE PT VI AU HK IN ID JP MY NZ PH SG KR TW TH VN AD AT BE BA BG HR CY CZ DK EE FI FR GE DE GI GR GL HU IS IE IL IT LV LI LT LU MK MT MD MC ME NL GB NO PL RO RU SM SK SI ZA ES SE CH TR VA)
|
8
|
+
self.default_currency = 'USD'
|
9
|
+
self.supported_cardtypes = %i[visa master american_express discover]
|
10
|
+
|
11
|
+
self.homepage_url = 'https://www.rapyd.net/'
|
12
|
+
self.display_name = 'Rapyd Gateway'
|
13
|
+
|
14
|
+
STANDARD_ERROR_CODE_MAPPING = {}
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
requires!(options, :secret_key, :access_key)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def purchase(money, payment, options = {})
|
22
|
+
post = {}
|
23
|
+
add_invoice(post, money, options)
|
24
|
+
add_payment(post, payment, options)
|
25
|
+
add_address(post, payment, options)
|
26
|
+
add_metadata(post, options)
|
27
|
+
add_ewallet(post, options)
|
28
|
+
post[:capture] = true if payment_is_card?(options)
|
29
|
+
|
30
|
+
if payment_is_ach?(options)
|
31
|
+
MultiResponse.run do |r|
|
32
|
+
r.process { commit(:post, 'payments', post) }
|
33
|
+
post = {}
|
34
|
+
post[:token] = r.authorization
|
35
|
+
post[:param2] = r.params.dig('data', 'original_amount').to_s
|
36
|
+
r.process { commit(:post, 'payments/completePayment', post) }
|
37
|
+
end
|
38
|
+
else
|
39
|
+
commit(:post, 'payments', post)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def authorize(money, payment, options = {})
|
44
|
+
post = {}
|
45
|
+
add_invoice(post, money, options)
|
46
|
+
add_payment(post, payment, options)
|
47
|
+
add_address(post, payment, options)
|
48
|
+
add_metadata(post, options)
|
49
|
+
add_ewallet(post, options)
|
50
|
+
post[:capture] = false
|
51
|
+
commit(:post, 'payments', post)
|
52
|
+
end
|
53
|
+
|
54
|
+
def capture(money, authorization, options = {})
|
55
|
+
post = {}
|
56
|
+
commit(:post, "payments/#{authorization}/capture", post)
|
57
|
+
end
|
58
|
+
|
59
|
+
def refund(money, authorization, options = {})
|
60
|
+
post = {}
|
61
|
+
post[:payment] = authorization
|
62
|
+
add_invoice(post, money, options)
|
63
|
+
add_metadata(post, options)
|
64
|
+
commit(:post, 'refunds', post)
|
65
|
+
end
|
66
|
+
|
67
|
+
def void(authorization, options = {})
|
68
|
+
post = {}
|
69
|
+
commit(:delete, "payments/#{authorization}", post)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gateway returns an error if trying to run a $0 auth as invalid payment amount
|
73
|
+
# Gateway does not support void on a card transaction and refunds can only be done on completed transactions
|
74
|
+
# (such as a purchase). Authorize transactions are considered 'active' and not 'complete' until they are captured.
|
75
|
+
def verify(credit_card, options = {})
|
76
|
+
MultiResponse.run do |r|
|
77
|
+
r.process { purchase(100, credit_card, options) }
|
78
|
+
r.process { refund(100, r.authorization, options) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def supports_scrubbing?
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
def scrub(transcript)
|
87
|
+
transcript.
|
88
|
+
gsub(%r((Access_key: )\w+), '\1[FILTERED]').
|
89
|
+
gsub(%r(("number\\?":\\?")\d+), '\1[FILTERED]').
|
90
|
+
gsub(%r(("cvv\\?":\\?")\d+), '\1[FILTERED]')
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def payment_is_ach?(options)
|
96
|
+
return unless options[:pm_type]
|
97
|
+
|
98
|
+
return true if options[:pm_type].include?('_bank')
|
99
|
+
end
|
100
|
+
|
101
|
+
def payment_is_card?(options)
|
102
|
+
return unless options[:pm_type]
|
103
|
+
|
104
|
+
return true if options[:pm_type].include?('_card')
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_address(post, creditcard, options)
|
108
|
+
return unless address = options[:address]
|
109
|
+
|
110
|
+
post[:address] = {}
|
111
|
+
# name and line_1 are required at the gateway
|
112
|
+
post[:address][:name] = address[:name] if address[:name]
|
113
|
+
post[:address][:line_1] = address[:address1] if address[:address1]
|
114
|
+
post[:address][:line_2] = address[:address2] if address[:address2]
|
115
|
+
post[:address][:city] = address[:city] if address[:city]
|
116
|
+
post[:address][:state] = address[:state] if address[:state]
|
117
|
+
post[:address][:country] = address[:country] if address[:country]
|
118
|
+
post[:address][:zip] = address[:zip] if address[:zip]
|
119
|
+
post[:address][:phone_number] = address[:phone] if address[:phone]
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_invoice(post, money, options)
|
123
|
+
post[:amount] = amount(money).to_f.to_s
|
124
|
+
post[:currency] = (options[:currency] || currency(money))
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_payment(post, payment, options)
|
128
|
+
if payment_is_card?(options)
|
129
|
+
add_creditcard(post, payment, options)
|
130
|
+
elsif payment_is_ach?(options)
|
131
|
+
add_ach(post, payment, options)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_creditcard(post, payment, options)
|
136
|
+
post[:payment_method] = {}
|
137
|
+
post[:payment_method][:fields] = {}
|
138
|
+
pm_fields = post[:payment_method][:fields]
|
139
|
+
|
140
|
+
post[:payment_method][:type] = options[:pm_type]
|
141
|
+
pm_fields[:number] = payment.number
|
142
|
+
pm_fields[:expiration_month] = payment.month.to_s
|
143
|
+
pm_fields[:expiration_year] = payment.year.to_s
|
144
|
+
pm_fields[:cvv] = payment.verification_value.to_s
|
145
|
+
pm_fields[:name] = "#{payment.first_name} #{payment.last_name}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_ach(post, payment, options)
|
149
|
+
post[:payment_method] = {}
|
150
|
+
post[:payment_method][:fields] = {}
|
151
|
+
|
152
|
+
post[:payment_method][:type] = options[:pm_type]
|
153
|
+
post[:payment_method][:fields][:proof_of_authorization] = options[:proof_of_authorization]
|
154
|
+
post[:payment_method][:fields][:first_name] = payment.first_name if payment.first_name
|
155
|
+
post[:payment_method][:fields][:last_name] = payment.last_name if payment.last_name
|
156
|
+
post[:payment_method][:fields][:routing_number] = payment.routing_number
|
157
|
+
post[:payment_method][:fields][:account_number] = payment.account_number
|
158
|
+
post[:payment_method][:fields][:payment_purpose] = options[:payment_purpose] if options[:payment_purpose]
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_metadata(post, options)
|
162
|
+
post[:metadata] = options[:metadata] if options[:metadata]
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_ewallet(post, options)
|
166
|
+
post[:ewallet_id] = options[:ewallet_id] if options[:ewallet_id]
|
167
|
+
end
|
168
|
+
|
169
|
+
def parse(body)
|
170
|
+
return {} if body.empty? || body.nil?
|
171
|
+
|
172
|
+
JSON.parse(body)
|
173
|
+
end
|
174
|
+
|
175
|
+
def commit(method, action, parameters)
|
176
|
+
url = (test? ? test_url : live_url) + action.to_s
|
177
|
+
rel_path = "#{method}/v1/#{action}"
|
178
|
+
response = api_request(method, url, rel_path, parameters)
|
179
|
+
|
180
|
+
Response.new(
|
181
|
+
success_from(response),
|
182
|
+
message_from(response),
|
183
|
+
response,
|
184
|
+
authorization: authorization_from(response),
|
185
|
+
avs_result: avs_result(response),
|
186
|
+
cvv_result: cvv_result(response),
|
187
|
+
test: test?,
|
188
|
+
error_code: error_code_from(response)
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
def api_request(method, url, rel_path, params)
|
193
|
+
params == {} ? body = '' : body = params.to_json
|
194
|
+
parse(ssl_request(method, url, body, headers(rel_path, body)))
|
195
|
+
end
|
196
|
+
|
197
|
+
def headers(rel_path, payload)
|
198
|
+
salt = SecureRandom.base64(12)
|
199
|
+
timestamp = Time.new.to_i.to_s
|
200
|
+
{
|
201
|
+
'Content-Type' => 'application/json',
|
202
|
+
'access_key' => @options[:access_key],
|
203
|
+
'salt' => salt,
|
204
|
+
'timestamp' => timestamp,
|
205
|
+
'signature' => generate_hmac(rel_path, salt, timestamp, payload)
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
def generate_hmac(rel_path, salt, timestamp, payload)
|
210
|
+
signature = "#{rel_path}#{salt}#{timestamp}#{@options[:access_key]}#{@options[:secret_key]}#{payload}"
|
211
|
+
hash = Base64.urlsafe_encode64(OpenSSL::HMAC.hexdigest('sha256', @options[:secret_key], signature))
|
212
|
+
hash
|
213
|
+
end
|
214
|
+
|
215
|
+
def avs_result(response)
|
216
|
+
return nil unless (code = response.dig('data', 'payment_method_data', 'acs_check'))
|
217
|
+
|
218
|
+
AVSResult.new(code: code)
|
219
|
+
end
|
220
|
+
|
221
|
+
def cvv_result(response)
|
222
|
+
return nil unless (code = response.dig('data', 'payment_method_data', 'cvv_check'))
|
223
|
+
|
224
|
+
CVVResult.new(code)
|
225
|
+
end
|
226
|
+
|
227
|
+
def success_from(response)
|
228
|
+
response.dig('status', 'status') == 'SUCCESS' && response.dig('status', 'error') != 'ERR'
|
229
|
+
end
|
230
|
+
|
231
|
+
def message_from(response)
|
232
|
+
case response.dig('status', 'status')
|
233
|
+
when 'ERROR'
|
234
|
+
response.dig('status', 'message') == '' ? response.dig('status', 'error_code') : response.dig('status', 'message')
|
235
|
+
else
|
236
|
+
response.dig('status', 'status')
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def authorization_from(response)
|
241
|
+
response.dig('data') ? response.dig('data', 'id') : response.dig('status', 'operation_id')
|
242
|
+
end
|
243
|
+
|
244
|
+
def error_code_from(response)
|
245
|
+
response.dig('status', 'error_code') unless success_from(response)
|
246
|
+
end
|
247
|
+
|
248
|
+
def handle_response(response)
|
249
|
+
case response.code.to_i
|
250
|
+
when 200...300, 400, 401, 404
|
251
|
+
response.body
|
252
|
+
else
|
253
|
+
raise ResponseError.new(response)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -107,10 +107,7 @@ module ActiveMerchant #:nodoc:
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def verify(credit_card, options = {})
|
110
|
-
|
111
|
-
r.process { authorize(100, credit_card, options) }
|
112
|
-
r.process(:ignore_result) { void(r.authorization, options) }
|
113
|
-
end
|
110
|
+
authorize(0, credit_card, options)
|
114
111
|
end
|
115
112
|
|
116
113
|
def supports_scrubbing?
|