activemerchant 1.121.0 → 1.123.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +86 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing/check.rb +13 -16
- data/lib/active_merchant/billing/credit_card.rb +3 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +21 -12
- data/lib/active_merchant/billing/gateways/adyen.rb +15 -19
- data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_pay.rb +29 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +2 -2
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -3
- data/lib/active_merchant/billing/gateways/credorax.rb +2 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +30 -3
- data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +60 -28
- data/lib/active_merchant/billing/gateways/element.rb +2 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +19 -10
- data/lib/active_merchant/billing/gateways/kushki.rb +23 -0
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -2
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -0
- data/lib/active_merchant/billing/gateways/moka.rb +277 -0
- data/lib/active_merchant/billing/gateways/monei.rb +228 -144
- data/lib/active_merchant/billing/gateways/mundipagg.rb +14 -5
- data/lib/active_merchant/billing/gateways/nmi.rb +14 -9
- data/lib/active_merchant/billing/gateways/orbital.rb +28 -6
- data/lib/active_merchant/billing/gateways/pay_arc.rb +390 -0
- data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
- data/lib/active_merchant/billing/gateways/payeezy.rb +4 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +9 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/paymentez.rb +5 -0
- data/lib/active_merchant/billing/gateways/paysafe.rb +291 -0
- data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -3
- data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
- data/lib/active_merchant/billing/gateways/safe_charge.rb +2 -0
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +19 -1
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -1
- data/lib/active_merchant/billing/gateways/vpos.rb +49 -6
- data/lib/active_merchant/billing/gateways/worldpay.rb +39 -7
- data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
- data/lib/active_merchant/billing.rb +1 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +8 -3
@@ -386,7 +386,7 @@ module ActiveMerchant
|
|
386
386
|
|
387
387
|
def parse(response)
|
388
388
|
return bad_authentication_response if response.code.to_i == 401
|
389
|
-
return
|
389
|
+
return generic_error_response(response.body) if [403, 429].include?(response.code.to_i)
|
390
390
|
|
391
391
|
parsed = {}
|
392
392
|
doc = Nokogiri::XML(response.body)
|
@@ -564,7 +564,7 @@ module ActiveMerchant
|
|
564
564
|
{ 'description' => 'Unable to authenticate. Please check your credentials.' }
|
565
565
|
end
|
566
566
|
|
567
|
-
def
|
567
|
+
def generic_error_response(body)
|
568
568
|
{ 'description' => body }
|
569
569
|
end
|
570
570
|
end
|
@@ -135,8 +135,8 @@ module ActiveMerchant #:nodoc:
|
|
135
135
|
result = @braintree_gateway.verification.create(payload)
|
136
136
|
response = Response.new(result.success?, message_from_transaction_result(result), response_options(result))
|
137
137
|
response.cvv_result['message'] = ''
|
138
|
-
response.cvv_result['code'] = response.params['cvv_result']
|
139
|
-
response.avs_result['code'] = response.params['avs_result'][:code]
|
138
|
+
response.cvv_result['code'] = response.params['cvv_result'] if response.params['cvv_result']
|
139
|
+
response.avs_result['code'] = response.params['avs_result'][:code] if response.params.dig('avs_result', :code)
|
140
140
|
response
|
141
141
|
end
|
142
142
|
|
@@ -588,7 +588,8 @@ module ActiveMerchant #:nodoc:
|
|
588
588
|
'merchant_account_id' => transaction.merchant_account_id,
|
589
589
|
'risk_data' => risk_data,
|
590
590
|
'network_transaction_id' => transaction.network_transaction_id || nil,
|
591
|
-
'processor_response_code' => response_code_from_result(result)
|
591
|
+
'processor_response_code' => response_code_from_result(result),
|
592
|
+
'recurring' => transaction.recurring
|
592
593
|
}
|
593
594
|
end
|
594
595
|
|
@@ -770,6 +771,8 @@ module ActiveMerchant #:nodoc:
|
|
770
771
|
else
|
771
772
|
parameters[:transaction_source] = stored_credential[:reason_type]
|
772
773
|
end
|
774
|
+
elsif %w(recurring_first moto).include?(stored_credential[:reason_type])
|
775
|
+
parameters[:transaction_source] = stored_credential[:reason_type]
|
773
776
|
else
|
774
777
|
parameters[:transaction_source] = ''
|
775
778
|
end
|
@@ -20,8 +20,9 @@ module ActiveMerchant #:nodoc:
|
|
20
20
|
self.live_url = 'https://assigned-subdomain.credorax.net/crax_gate/service/gateway'
|
21
21
|
|
22
22
|
self.supported_countries = %w(AD AT BE BG HR CY CZ DK EE FR DE GI GR GG HU IS IE IM IT JE LV LI LT LU MT MC NO PL PT RO SM SK ES SE CH GB)
|
23
|
+
|
23
24
|
self.default_currency = 'EUR'
|
24
|
-
self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW PYG RWF VND VUV XAF XOF XPF)
|
25
|
+
self.currencies_without_fractions = %w(BIF CLP DJF GNF ISK JPY KMF KRW PYG RWF VND VUV XAF XOF XPF)
|
25
26
|
self.currencies_with_three_decimal_places = %w(BHD IQD JOD KWD LYD OMR TND)
|
26
27
|
|
27
28
|
self.money_format = :cents
|
@@ -153,6 +153,10 @@ module ActiveMerchant #:nodoc:
|
|
153
153
|
commit(build_refund_request(money, identification, options), :refund, money, options)
|
154
154
|
end
|
155
155
|
|
156
|
+
def adjust(money, authorization, options = {})
|
157
|
+
commit(build_adjust_request(money, authorization, options), :adjust, money, options)
|
158
|
+
end
|
159
|
+
|
156
160
|
def verify(payment, options = {})
|
157
161
|
MultiResponse.run(:use_first_response) do |r|
|
158
162
|
r.process { authorize(100, payment, options) }
|
@@ -285,6 +289,7 @@ module ActiveMerchant #:nodoc:
|
|
285
289
|
|
286
290
|
def build_auth_request(money, creditcard_or_reference, options)
|
287
291
|
xml = Builder::XmlMarkup.new indent: 2
|
292
|
+
add_customer_id(xml, options)
|
288
293
|
add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
|
289
294
|
add_threeds_2_ucaf_data(xml, creditcard_or_reference, options)
|
290
295
|
add_decision_manager_fields(xml, options)
|
@@ -300,7 +305,15 @@ module ActiveMerchant #:nodoc:
|
|
300
305
|
add_merchant_description(xml, options)
|
301
306
|
add_sales_slip_number(xml, options)
|
302
307
|
add_airline_data(xml, options)
|
308
|
+
xml.target!
|
309
|
+
end
|
303
310
|
|
311
|
+
def build_adjust_request(money, authorization, options)
|
312
|
+
_, request_id = authorization.split(';')
|
313
|
+
|
314
|
+
xml = Builder::XmlMarkup.new indent: 2
|
315
|
+
add_purchase_data(xml, money, true, options)
|
316
|
+
add_incremental_auth_service(xml, request_id, options)
|
304
317
|
xml.target!
|
305
318
|
end
|
306
319
|
|
@@ -334,6 +347,7 @@ module ActiveMerchant #:nodoc:
|
|
334
347
|
|
335
348
|
def build_purchase_request(money, payment_method_or_reference, options)
|
336
349
|
xml = Builder::XmlMarkup.new indent: 2
|
350
|
+
add_customer_id(xml, options)
|
337
351
|
add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
|
338
352
|
add_threeds_2_ucaf_data(xml, payment_method_or_reference, options)
|
339
353
|
add_decision_manager_fields(xml, options)
|
@@ -472,8 +486,8 @@ module ActiveMerchant #:nodoc:
|
|
472
486
|
|
473
487
|
unless network_tokenization?(payment_method)
|
474
488
|
xml.tag! 'businessRules' do
|
475
|
-
xml.tag!('ignoreAVSResult', 'true') if extract_option(prioritized_options, :ignore_avs)
|
476
|
-
xml.tag!('ignoreCVResult', 'true') if extract_option(prioritized_options, :ignore_cvv)
|
489
|
+
xml.tag!('ignoreAVSResult', 'true') if extract_option(prioritized_options, :ignore_avs).to_s == 'true'
|
490
|
+
xml.tag!('ignoreCVResult', 'true') if extract_option(prioritized_options, :ignore_cvv).to_s == 'true'
|
477
491
|
end
|
478
492
|
end
|
479
493
|
end
|
@@ -515,6 +529,12 @@ module ActiveMerchant #:nodoc:
|
|
515
529
|
end
|
516
530
|
end
|
517
531
|
|
532
|
+
def add_customer_id(xml, options)
|
533
|
+
return unless options[:customer_id]
|
534
|
+
|
535
|
+
xml.tag! 'customerID', options[:customer_id]
|
536
|
+
end
|
537
|
+
|
518
538
|
def add_merchant_description(xml, options)
|
519
539
|
return unless options[:merchant_descriptor_name] || options[:merchant_descriptor_address1] || options[:merchant_descriptor_locality]
|
520
540
|
|
@@ -585,7 +605,7 @@ module ActiveMerchant #:nodoc:
|
|
585
605
|
xml.tag! 'accountNumber', creditcard.number
|
586
606
|
xml.tag! 'expirationMonth', format(creditcard.month, :two_digits)
|
587
607
|
xml.tag! 'expirationYear', format(creditcard.year, :four_digits)
|
588
|
-
xml.tag!('cvNumber', creditcard.verification_value) unless @options[:ignore_cvv] || creditcard.verification_value.blank?
|
608
|
+
xml.tag!('cvNumber', creditcard.verification_value) unless @options[:ignore_cvv].to_s == 'true' || creditcard.verification_value.blank?
|
589
609
|
xml.tag! 'cardType', @@credit_card_codes[card_brand(creditcard).to_sym]
|
590
610
|
end
|
591
611
|
end
|
@@ -658,6 +678,13 @@ module ActiveMerchant #:nodoc:
|
|
658
678
|
end
|
659
679
|
end
|
660
680
|
|
681
|
+
def add_incremental_auth_service(xml, authorization, options)
|
682
|
+
xml.tag! 'ccIncrementalAuthService', { 'run' => 'true' } do
|
683
|
+
xml.tag! 'authRequestID', authorization
|
684
|
+
end
|
685
|
+
xml.tag! 'subsequentAuthReason', options[:auth_reason]
|
686
|
+
end
|
687
|
+
|
661
688
|
def add_normalized_threeds_2_data(xml, payment_method, options)
|
662
689
|
threeds_2_options = options[:three_d_secure]
|
663
690
|
cc_brand = card_brand(payment_method).to_sym
|
@@ -282,7 +282,13 @@ module ActiveMerchant #:nodoc:
|
|
282
282
|
if error = response.dig('status_details', 'error')
|
283
283
|
message = "#{error.dig('reason', 'description')} | #{error['type']}"
|
284
284
|
elsif response['error_type']
|
285
|
-
|
285
|
+
if response['validation_errors'].is_a?(Array)
|
286
|
+
message = response['validation_errors'].map { |errors| "#{errors['code']}: #{errors['param']}" }.join(', ')
|
287
|
+
elsif response['validation_errors'].is_a?(Hash)
|
288
|
+
errors = response['validation_errors'].map { |k, v| "#{k}: #{v}" }.join(', ')
|
289
|
+
message = "#{response['error_type']} - #{errors}"
|
290
|
+
end
|
291
|
+
|
286
292
|
message ||= response['error_type']
|
287
293
|
end
|
288
294
|
|
@@ -201,8 +201,8 @@ module ActiveMerchant #:nodoc:
|
|
201
201
|
private
|
202
202
|
|
203
203
|
def add_invoice(xml, options)
|
204
|
-
xml.ssl_invoice_number
|
205
|
-
xml.ssl_description
|
204
|
+
xml.ssl_invoice_number url_encode_truncate((options[:order_id] || options[:invoice]), 25)
|
205
|
+
xml.ssl_description url_encode_truncate(options[:description], 255)
|
206
206
|
end
|
207
207
|
|
208
208
|
def add_approval_code(xml, authorization)
|
@@ -219,8 +219,8 @@ module ActiveMerchant #:nodoc:
|
|
219
219
|
|
220
220
|
add_verification_value(xml, creditcard) if creditcard.verification_value?
|
221
221
|
|
222
|
-
xml.ssl_first_name
|
223
|
-
xml.ssl_last_name
|
222
|
+
xml.ssl_first_name url_encode_truncate(creditcard.first_name, 20)
|
223
|
+
xml.ssl_last_name url_encode_truncate(creditcard.last_name, 30)
|
224
224
|
end
|
225
225
|
|
226
226
|
def add_currency(xml, money, options)
|
@@ -240,7 +240,7 @@ module ActiveMerchant #:nodoc:
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def add_customer_email(xml, options)
|
243
|
-
xml.ssl_email
|
243
|
+
xml.ssl_email url_encode_truncate(options[:email], 100) unless empty?(options[:email])
|
244
244
|
end
|
245
245
|
|
246
246
|
def add_salestax(xml, options)
|
@@ -253,27 +253,27 @@ module ActiveMerchant #:nodoc:
|
|
253
253
|
billing_address = options[:billing_address] || options[:address]
|
254
254
|
|
255
255
|
if billing_address
|
256
|
-
xml.ssl_avs_address
|
257
|
-
xml.ssl_address2
|
258
|
-
xml.ssl_avs_zip
|
259
|
-
xml.ssl_city
|
260
|
-
xml.ssl_state
|
261
|
-
xml.ssl_company
|
262
|
-
xml.ssl_phone
|
263
|
-
xml.ssl_country
|
256
|
+
xml.ssl_avs_address url_encode_truncate(billing_address[:address1], 30)
|
257
|
+
xml.ssl_address2 url_encode_truncate(billing_address[:address2], 30)
|
258
|
+
xml.ssl_avs_zip url_encode_truncate(billing_address[:zip].to_s.gsub(/[^a-zA-Z0-9]/, ''), 9)
|
259
|
+
xml.ssl_city url_encode_truncate(billing_address[:city], 30)
|
260
|
+
xml.ssl_state url_encode_truncate(billing_address[:state], 10)
|
261
|
+
xml.ssl_company url_encode_truncate(billing_address[:company], 50)
|
262
|
+
xml.ssl_phone url_encode_truncate(billing_address[:phone], 20)
|
263
|
+
xml.ssl_country url_encode_truncate(billing_address[:country], 50)
|
264
264
|
end
|
265
265
|
|
266
266
|
if shipping_address = options[:shipping_address]
|
267
|
-
xml.ssl_ship_to_address1
|
268
|
-
xml.ssl_ship_to_address2
|
269
|
-
xml.ssl_ship_to_city
|
270
|
-
xml.ssl_ship_to_company
|
271
|
-
xml.ssl_ship_to_country
|
272
|
-
xml.ssl_ship_to_first_name
|
273
|
-
xml.ssl_ship_to_last_name
|
274
|
-
xml.ssl_ship_to_phone
|
275
|
-
xml.ssl_ship_to_state
|
276
|
-
xml.ssl_ship_to_zip
|
267
|
+
xml.ssl_ship_to_address1 url_encode_truncate(shipping_address[:address1], 30)
|
268
|
+
xml.ssl_ship_to_address2 url_encode_truncate(shipping_address[:address2], 30)
|
269
|
+
xml.ssl_ship_to_city url_encode_truncate(shipping_address[:city], 30)
|
270
|
+
xml.ssl_ship_to_company url_encode_truncate(shipping_address[:company], 50)
|
271
|
+
xml.ssl_ship_to_country url_encode_truncate(shipping_address[:country], 50)
|
272
|
+
xml.ssl_ship_to_first_name url_encode_truncate(shipping_address[:first_name], 20)
|
273
|
+
xml.ssl_ship_to_last_name url_encode_truncate(shipping_address[:last_name], 30)
|
274
|
+
xml.ssl_ship_to_phone url_encode_truncate(shipping_address[:phone], 10)
|
275
|
+
xml.ssl_ship_to_state url_encode_truncate(shipping_address[:state], 2)
|
276
|
+
xml.ssl_ship_to_zip url_encode_truncate(shipping_address[:zip], 10)
|
277
277
|
end
|
278
278
|
end
|
279
279
|
|
@@ -293,9 +293,12 @@ module ActiveMerchant #:nodoc:
|
|
293
293
|
xml.ssl_cardholder_ip options[:ip] if options.has_key?(:ip)
|
294
294
|
end
|
295
295
|
|
296
|
+
# add_recurring_token is a field that can be sent in to obtain a token from Elavon for use with their tokenization program
|
296
297
|
def add_auth_purchase_params(xml, options)
|
297
298
|
xml.ssl_dynamic_dba options[:dba] if options.has_key?(:dba)
|
298
299
|
xml.ssl_merchant_initiated_unscheduled merchant_initiated_unscheduled(options) if merchant_initiated_unscheduled(options)
|
300
|
+
xml.ssl_add_token options[:add_recurring_token] if options.has_key?(:add_recurring_token)
|
301
|
+
xml.ssl_token options[:ssl_token] if options.has_key?(:ssl_token)
|
299
302
|
xml.ssl_customer_code options[:customer] if options.has_key?(:customer)
|
300
303
|
xml.ssl_customer_number options[:customer_number] if options.has_key?(:customer_number)
|
301
304
|
xml.ssl_entry_mode entry_mode(options) if entry_mode(options)
|
@@ -367,7 +370,7 @@ module ActiveMerchant #:nodoc:
|
|
367
370
|
|
368
371
|
def merchant_initiated_unscheduled(options)
|
369
372
|
return options[:merchant_initiated_unscheduled] if options[:merchant_initiated_unscheduled]
|
370
|
-
return 'Y' if options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
|
373
|
+
return 'Y' if options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled' || options.dig(:stored_credential, :reason_type) == 'recurring'
|
371
374
|
end
|
372
375
|
|
373
376
|
def entry_mode(options)
|
@@ -392,6 +395,7 @@ module ActiveMerchant #:nodoc:
|
|
392
395
|
request = "xmldata=#{request}".delete('&')
|
393
396
|
|
394
397
|
response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers))
|
398
|
+
response = hash_html_decode(response)
|
395
399
|
|
396
400
|
Response.new(
|
397
401
|
response[:result] == '0',
|
@@ -413,7 +417,7 @@ module ActiveMerchant #:nodoc:
|
|
413
417
|
def headers
|
414
418
|
{
|
415
419
|
'Accept' => 'application/xml',
|
416
|
-
'Content-type' => 'application/x-www-form-urlencoded'
|
420
|
+
'Content-type' => 'application/x-www-form-urlencoded;charset=utf8'
|
417
421
|
}
|
418
422
|
end
|
419
423
|
|
@@ -428,12 +432,40 @@ module ActiveMerchant #:nodoc:
|
|
428
432
|
[response[:approval_code], response[:txn_id]].join(';')
|
429
433
|
end
|
430
434
|
|
431
|
-
def
|
435
|
+
def url_encode_truncate(value, size)
|
432
436
|
return nil unless value
|
433
437
|
|
434
|
-
|
438
|
+
encoded = url_encode(value)
|
435
439
|
|
436
|
-
|
440
|
+
while encoded.length > size
|
441
|
+
value.chop!
|
442
|
+
encoded = url_encode(value)
|
443
|
+
end
|
444
|
+
encoded
|
445
|
+
end
|
446
|
+
|
447
|
+
def url_encode(value)
|
448
|
+
if value.is_a?(String)
|
449
|
+
encoded = CGI.escape(value)
|
450
|
+
encoded = encoded.tr('+', ' ') # don't encode spaces
|
451
|
+
encoded = encoded.gsub('%26', '%26amp;') # account for Elavon's weird '&' handling
|
452
|
+
encoded
|
453
|
+
else
|
454
|
+
value.to_s
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def hash_html_decode(hash)
|
459
|
+
hash.each do |k, v|
|
460
|
+
if v.is_a?(String)
|
461
|
+
# decode all string params
|
462
|
+
v = v.gsub('&', '&') # account for Elavon's weird '&' handling
|
463
|
+
hash[k] = CGI.unescape_html(v)
|
464
|
+
elsif v.is_a?(Hash)
|
465
|
+
hash_html_decode(v)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
hash
|
437
469
|
end
|
438
470
|
end
|
439
471
|
end
|
@@ -192,6 +192,8 @@ module ActiveMerchant #:nodoc:
|
|
192
192
|
xml.PaymentType options[:payment_type] if options[:payment_type]
|
193
193
|
xml.SubmissionType options[:submission_type] if options[:submission_type]
|
194
194
|
xml.DuplicateCheckDisableFlag options[:duplicate_check_disable_flag].to_s == 'true' ? 'True' : 'False' unless options[:duplicate_check_disable_flag].nil?
|
195
|
+
xml.DuplicateOverrideFlag options[:duplicate_override_flag].to_s == 'true' ? 'True' : 'False' unless options[:duplicate_override_flag].nil?
|
196
|
+
xml.MerchantDescriptor options[:merchant_descriptor] if options[:merchant_descriptor]
|
195
197
|
end
|
196
198
|
end
|
197
199
|
|
@@ -33,7 +33,7 @@ module ActiveMerchant #:nodoc:
|
|
33
33
|
add_creator_info(post, options)
|
34
34
|
add_fraud_fields(post, options)
|
35
35
|
add_external_cardholder_authentication_data(post, options)
|
36
|
-
commit(:authorize, post)
|
36
|
+
commit(:authorize, post, options: options)
|
37
37
|
end
|
38
38
|
|
39
39
|
def capture(money, authorization, options = {})
|
@@ -41,7 +41,7 @@ module ActiveMerchant #:nodoc:
|
|
41
41
|
add_order(post, money, options, capture: true)
|
42
42
|
add_customer_data(post, options)
|
43
43
|
add_creator_info(post, options)
|
44
|
-
commit(:capture, post, authorization)
|
44
|
+
commit(:capture, post, authorization: authorization)
|
45
45
|
end
|
46
46
|
|
47
47
|
def refund(money, authorization, options = {})
|
@@ -49,13 +49,13 @@ module ActiveMerchant #:nodoc:
|
|
49
49
|
add_amount(post, money, options)
|
50
50
|
add_refund_customer_data(post, options)
|
51
51
|
add_creator_info(post, options)
|
52
|
-
commit(:refund, post, authorization)
|
52
|
+
commit(:refund, post, authorization: authorization)
|
53
53
|
end
|
54
54
|
|
55
55
|
def void(authorization, options = {})
|
56
56
|
post = nestable_hash
|
57
57
|
add_creator_info(post, options)
|
58
|
-
commit(:void, post, authorization)
|
58
|
+
commit(:void, post, authorization: authorization)
|
59
59
|
end
|
60
60
|
|
61
61
|
def verify(payment, options = {})
|
@@ -277,9 +277,13 @@ module ActiveMerchant #:nodoc:
|
|
277
277
|
end
|
278
278
|
end
|
279
279
|
|
280
|
-
def
|
280
|
+
def idempotency_key_for_signature(options)
|
281
|
+
"x-gcs-idempotence-key:#{options[:idempotency_key]}" if options[:idempotency_key]
|
282
|
+
end
|
283
|
+
|
284
|
+
def commit(action, post, authorization: nil, options: {})
|
281
285
|
begin
|
282
|
-
raw_response = ssl_post(url(action, authorization), post.to_json, headers(action, post, authorization))
|
286
|
+
raw_response = ssl_post(url(action, authorization), post.to_json, headers(action, post, authorization, options))
|
283
287
|
response = parse(raw_response)
|
284
288
|
rescue ResponseError => e
|
285
289
|
response = parse(e.response.body) if e.response.code.to_i >= 400
|
@@ -306,21 +310,26 @@ module ActiveMerchant #:nodoc:
|
|
306
310
|
}
|
307
311
|
end
|
308
312
|
|
309
|
-
def headers(action, post, authorization = nil)
|
310
|
-
{
|
313
|
+
def headers(action, post, authorization = nil, options = {})
|
314
|
+
headers = {
|
311
315
|
'Content-Type' => content_type,
|
312
|
-
'Authorization' => auth_digest(action, post, authorization),
|
316
|
+
'Authorization' => auth_digest(action, post, authorization, options),
|
313
317
|
'Date' => date
|
314
318
|
}
|
319
|
+
|
320
|
+
headers['X-GCS-Idempotence-Key'] = options[:idempotency_key] if options[:idempotency_key]
|
321
|
+
headers
|
315
322
|
end
|
316
323
|
|
317
|
-
def auth_digest(action, post, authorization = nil)
|
324
|
+
def auth_digest(action, post, authorization = nil, options = {})
|
318
325
|
data = <<~REQUEST
|
319
326
|
POST
|
320
327
|
#{content_type}
|
321
328
|
#{date}
|
329
|
+
#{idempotency_key_for_signature(options)}
|
322
330
|
#{uri(action, authorization)}
|
323
331
|
REQUEST
|
332
|
+
data = data.each_line.reject { |line| line.strip == '' }.join
|
324
333
|
digest = OpenSSL::Digest.new('sha256')
|
325
334
|
key = @options[:secret_api_key]
|
326
335
|
"GCS v1HMAC:#{@options[:api_key_id]}:#{Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data))}"
|
@@ -37,6 +37,7 @@ module ActiveMerchant #:nodoc:
|
|
37
37
|
post = {}
|
38
38
|
post[:ticketNumber] = authorization
|
39
39
|
add_invoice(action, post, amount, options)
|
40
|
+
add_full_response(post, options)
|
40
41
|
|
41
42
|
commit(action, post)
|
42
43
|
end
|
@@ -46,6 +47,7 @@ module ActiveMerchant #:nodoc:
|
|
46
47
|
|
47
48
|
post = {}
|
48
49
|
post[:ticketNumber] = authorization
|
50
|
+
add_full_response(post, options)
|
49
51
|
|
50
52
|
commit(action, post)
|
51
53
|
end
|
@@ -55,6 +57,7 @@ module ActiveMerchant #:nodoc:
|
|
55
57
|
|
56
58
|
post = {}
|
57
59
|
post[:ticketNumber] = authorization
|
60
|
+
add_full_response(post, options)
|
58
61
|
|
59
62
|
commit(action, post)
|
60
63
|
end
|
@@ -78,6 +81,7 @@ module ActiveMerchant #:nodoc:
|
|
78
81
|
post = {}
|
79
82
|
add_invoice(action, post, amount, options)
|
80
83
|
add_payment_method(post, payment_method, options)
|
84
|
+
add_full_response(post, options)
|
81
85
|
|
82
86
|
commit(action, post)
|
83
87
|
end
|
@@ -88,6 +92,8 @@ module ActiveMerchant #:nodoc:
|
|
88
92
|
post = {}
|
89
93
|
add_reference(post, authorization, options)
|
90
94
|
add_invoice(action, post, amount, options)
|
95
|
+
add_contact_details(post, options[:contact_details]) if options[:contact_details]
|
96
|
+
add_full_response(post, options)
|
91
97
|
|
92
98
|
commit(action, post)
|
93
99
|
end
|
@@ -98,6 +104,7 @@ module ActiveMerchant #:nodoc:
|
|
98
104
|
post = {}
|
99
105
|
add_reference(post, authorization, options)
|
100
106
|
add_invoice(action, post, amount, options)
|
107
|
+
add_full_response(post, options)
|
101
108
|
|
102
109
|
commit(action, post)
|
103
110
|
end
|
@@ -154,6 +161,22 @@ module ActiveMerchant #:nodoc:
|
|
154
161
|
post[:token] = authorization
|
155
162
|
end
|
156
163
|
|
164
|
+
def add_contact_details(post, contact_details_options)
|
165
|
+
contact_details = {}
|
166
|
+
contact_details[:documentType] = contact_details_options[:document_type] if contact_details_options[:document_type]
|
167
|
+
contact_details[:documentNumber] = contact_details_options[:document_number] if contact_details_options[:document_number]
|
168
|
+
contact_details[:email] = contact_details_options[:email] if contact_details_options[:email]
|
169
|
+
contact_details[:firstName] = contact_details_options[:first_name] if contact_details_options[:first_name]
|
170
|
+
contact_details[:lastName] = contact_details_options[:last_name] if contact_details_options[:last_name]
|
171
|
+
contact_details[:secondLastName] = contact_details_options[:second_last_name] if contact_details_options[:second_last_name]
|
172
|
+
contact_details[:phoneNumber] = contact_details_options[:phone_number] if contact_details_options[:phone_number]
|
173
|
+
post[:contactDetails] = contact_details
|
174
|
+
end
|
175
|
+
|
176
|
+
def add_full_response(post, options)
|
177
|
+
post[:fullResponse] = options[:full_response].to_s.casecmp('true').zero? if options[:full_response]
|
178
|
+
end
|
179
|
+
|
157
180
|
ENDPOINT = {
|
158
181
|
'tokenize' => 'tokens',
|
159
182
|
'charge' => 'charges',
|