activemerchant 1.123.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 +206 -0
- data/lib/active_merchant/billing/check.rb +5 -8
- data/lib/active_merchant/billing/credit_card.rb +10 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +18 -3
- data/lib/active_merchant/billing/gateway.rb +3 -2
- data/lib/active_merchant/billing/gateways/adyen.rb +66 -11
- 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/card_stream.rb +17 -13
- data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +34 -5
- data/lib/active_merchant/billing/gateways/credorax.rb +10 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +24 -36
- data/lib/active_merchant/billing/gateways/d_local.rb +61 -6
- data/lib/active_merchant/billing/gateways/decidir.rb +17 -1
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
- data/lib/active_merchant/billing/gateways/ebanx.rb +19 -3
- data/lib/active_merchant/billing/gateways/elavon.rb +6 -3
- data/lib/active_merchant/billing/gateways/element.rb +20 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +137 -32
- data/lib/active_merchant/billing/gateways/ipg.rb +415 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +7 -0
- data/lib/active_merchant/billing/gateways/litle.rb +93 -1
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -1
- data/lib/active_merchant/billing/gateways/mit.rb +260 -0
- data/lib/active_merchant/billing/gateways/moka.rb +24 -11
- data/lib/active_merchant/billing/gateways/moneris.rb +35 -8
- data/lib/active_merchant/billing/gateways/mundipagg.rb +8 -6
- data/lib/active_merchant/billing/gateways/nmi.rb +27 -8
- data/lib/active_merchant/billing/gateways/orbital.rb +357 -319
- data/lib/active_merchant/billing/gateways/pay_arc.rb +9 -7
- data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
- data/lib/active_merchant/billing/gateways/pay_trace.rb +1 -1
- data/lib/active_merchant/billing/gateways/payflow.rb +76 -6
- data/lib/active_merchant/billing/gateways/paymentez.rb +35 -9
- data/lib/active_merchant/billing/gateways/paysafe.rb +155 -34
- data/lib/active_merchant/billing/gateways/payu_latam.rb +31 -16
- data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
- data/lib/active_merchant/billing/gateways/pin.rb +31 -4
- data/lib/active_merchant/billing/gateways/priority.rb +369 -0
- data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
- data/lib/active_merchant/billing/gateways/realex.rb +18 -0
- data/lib/active_merchant/billing/gateways/safe_charge.rb +7 -6
- data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +30 -8
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +175 -72
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +20 -6
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +6 -2
- data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +196 -64
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
- data/lib/active_merchant/billing/response.rb +4 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +11 -2
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
|
|
4
4
|
self.test_url = 'https://sandbox.dlocal.com'
|
5
5
|
self.live_url = 'https://api.dlocal.com'
|
6
6
|
|
7
|
-
self.supported_countries = %w[AR BR CL CO MX PE UY
|
7
|
+
self.supported_countries = %w[AR BD BO BR CL CM CN CO CR DO EC EG GH IN ID KE MY MX MA NG PA PY PE PH SN ZA TR UY VN]
|
8
8
|
self.default_currency = 'USD'
|
9
9
|
self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro naranja cabal elo alia carnet]
|
10
10
|
|
@@ -19,6 +19,7 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
def purchase(money, payment, options = {})
|
20
20
|
post = {}
|
21
21
|
add_auth_purchase_params(post, money, payment, 'purchase', options)
|
22
|
+
add_three_ds(post, options)
|
22
23
|
|
23
24
|
commit('purchase', post, options)
|
24
25
|
end
|
@@ -26,6 +27,8 @@ module ActiveMerchant #:nodoc:
|
|
26
27
|
def authorize(money, payment, options = {})
|
27
28
|
post = {}
|
28
29
|
add_auth_purchase_params(post, money, payment, 'authorize', options)
|
30
|
+
add_three_ds(post, options)
|
31
|
+
post[:card][:verify] = true if options[:verify].to_s == 'true'
|
29
32
|
|
30
33
|
commit('authorize', post, options)
|
31
34
|
end
|
@@ -52,10 +55,7 @@ module ActiveMerchant #:nodoc:
|
|
52
55
|
end
|
53
56
|
|
54
57
|
def verify(credit_card, options = {})
|
55
|
-
|
56
|
-
r.process { authorize(100, credit_card, options) }
|
57
|
-
r.process(:ignore_result) { void(r.authorization, options) }
|
58
|
-
end
|
58
|
+
authorize(0, credit_card, options.merge(verify: 'true'))
|
59
59
|
end
|
60
60
|
|
61
61
|
def supports_scrubbing?
|
@@ -78,6 +78,7 @@ module ActiveMerchant #:nodoc:
|
|
78
78
|
add_country(post, card, options)
|
79
79
|
add_payer(post, card, options)
|
80
80
|
add_card(post, card, action, options)
|
81
|
+
add_additional_data(post, options)
|
81
82
|
post[:order_id] = options[:order_id] || generate_unique_id
|
82
83
|
post[:description] = options[:description] if options[:description]
|
83
84
|
end
|
@@ -87,6 +88,10 @@ module ActiveMerchant #:nodoc:
|
|
87
88
|
post[:currency] = (options[:currency] || currency(money))
|
88
89
|
end
|
89
90
|
|
91
|
+
def add_additional_data(post, options)
|
92
|
+
post[:additional_risk_data] = options[:additional_data]
|
93
|
+
end
|
94
|
+
|
90
95
|
def add_country(post, card, options)
|
91
96
|
return unless address = options[:billing_address] || options[:address]
|
92
97
|
|
@@ -109,6 +114,8 @@ module ActiveMerchant #:nodoc:
|
|
109
114
|
post[:payer][:document] = options[:document] if options[:document]
|
110
115
|
post[:payer][:document2] = options[:document2] if options[:document2]
|
111
116
|
post[:payer][:user_reference] = options[:user_reference] if options[:user_reference]
|
117
|
+
post[:payer][:event_uuid] = options[:device_id] if options[:device_id]
|
118
|
+
post[:payer][:onboarding_ip_address] = options[:ip] if options[:ip]
|
112
119
|
post[:payer][:address] = add_address(post, card, options)
|
113
120
|
end
|
114
121
|
|
@@ -149,6 +156,7 @@ module ActiveMerchant #:nodoc:
|
|
149
156
|
post[:card][:capture] = (action == 'purchase')
|
150
157
|
post[:card][:installments] = options[:installments] if options[:installments]
|
151
158
|
post[:card][:installments_id] = options[:installments_id] if options[:installments_id]
|
159
|
+
post[:card][:force_type] = options[:force_type].to_s.upcase if options[:force_type]
|
152
160
|
end
|
153
161
|
|
154
162
|
def parse(body)
|
@@ -156,6 +164,9 @@ module ActiveMerchant #:nodoc:
|
|
156
164
|
end
|
157
165
|
|
158
166
|
def commit(action, parameters, options = {})
|
167
|
+
three_ds_errors = validate_three_ds_params(parameters[:three_dsecure]) if parameters[:three_dsecure].present?
|
168
|
+
return three_ds_errors if three_ds_errors
|
169
|
+
|
159
170
|
url = url(action, parameters, options)
|
160
171
|
post = post_data(action, parameters)
|
161
172
|
begin
|
@@ -184,7 +195,7 @@ module ActiveMerchant #:nodoc:
|
|
184
195
|
def success_from(action, response)
|
185
196
|
return false unless response['status_code']
|
186
197
|
|
187
|
-
%w[100 200 400 600].include? response['status_code'].to_s
|
198
|
+
%w[100 200 400 600 700].include? response['status_code'].to_s
|
188
199
|
end
|
189
200
|
|
190
201
|
def message_from(action, response)
|
@@ -228,6 +239,7 @@ module ActiveMerchant #:nodoc:
|
|
228
239
|
'X-Date' => timestamp,
|
229
240
|
'X-Login' => @options[:login],
|
230
241
|
'X-Trans-Key' => @options[:trans_key],
|
242
|
+
'X-Version' => '2.1',
|
231
243
|
'Authorization' => signature(post, timestamp)
|
232
244
|
}
|
233
245
|
headers.merge('X-Idempotency-Key' => options[:idempotency_key]) if options[:idempotency_key]
|
@@ -243,6 +255,49 @@ module ActiveMerchant #:nodoc:
|
|
243
255
|
def post_data(action, parameters = {})
|
244
256
|
parameters.to_json
|
245
257
|
end
|
258
|
+
|
259
|
+
def xid_or_ds_trans_id(three_d_secure)
|
260
|
+
if three_d_secure[:version].to_f >= 2
|
261
|
+
{ ds_transaction_id: three_d_secure[:ds_transaction_id] }
|
262
|
+
else
|
263
|
+
{ xid: three_d_secure[:xid] }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def add_three_ds(post, options)
|
268
|
+
return unless three_d_secure = options[:three_d_secure]
|
269
|
+
|
270
|
+
post[:three_dsecure] = {
|
271
|
+
mpi: true,
|
272
|
+
three_dsecure_version: three_d_secure[:version],
|
273
|
+
cavv: three_d_secure[:cavv],
|
274
|
+
eci: three_d_secure[:eci],
|
275
|
+
enrollment_response: formatted_enrollment(three_d_secure[:enrolled]),
|
276
|
+
authentication_response: three_d_secure[:authentication_response_status]
|
277
|
+
}.merge(xid_or_ds_trans_id(three_d_secure))
|
278
|
+
end
|
279
|
+
|
280
|
+
def validate_three_ds_params(three_ds)
|
281
|
+
errors = {}
|
282
|
+
supported_version = %w{1.0 2.0 2.1.0 2.2.0}.include?(three_ds[:three_dsecure_version])
|
283
|
+
supported_enrollment = ['Y', 'N', 'U', nil].include?(three_ds[:enrollment_response])
|
284
|
+
supported_auth_response = ['Y', 'N', 'U', nil].include?(three_ds[:authentication_response])
|
285
|
+
|
286
|
+
errors[:three_ds_version] = 'ThreeDs version not supported' unless supported_version
|
287
|
+
errors[:enrollment] = 'Enrollment value not supported' unless supported_enrollment
|
288
|
+
errors[:auth_response] = 'Authentication response value not supported' unless supported_auth_response
|
289
|
+
errors.compact!
|
290
|
+
|
291
|
+
errors.present? ? Response.new(false, 'ThreeDs data is invalid', errors) : nil
|
292
|
+
end
|
293
|
+
|
294
|
+
def formatted_enrollment(val)
|
295
|
+
case val
|
296
|
+
when 'Y', 'N', 'U' then val
|
297
|
+
when true, 'true' then 'Y'
|
298
|
+
when false, 'false' then 'N'
|
299
|
+
end
|
300
|
+
end
|
246
301
|
end
|
247
302
|
end
|
248
303
|
end
|
@@ -117,11 +117,11 @@ module ActiveMerchant #:nodoc:
|
|
117
117
|
post[:establishment_name] = options[:establishment_name] if options[:establishment_name]
|
118
118
|
post[:fraud_detection] = add_fraud_detection(options[:fraud_detection]) if options[:fraud_detection].present?
|
119
119
|
post[:site_id] = options[:site_id] if options[:site_id]
|
120
|
-
post[:sub_payments] = []
|
121
120
|
|
122
121
|
add_invoice(post, money, options)
|
123
122
|
add_payment(post, credit_card, options)
|
124
123
|
add_aggregate_data(post, options) if options[:aggregate_data]
|
124
|
+
add_sub_payments(post, options)
|
125
125
|
end
|
126
126
|
|
127
127
|
def add_payment_method_id(credit_card, options)
|
@@ -210,6 +210,22 @@ module ActiveMerchant #:nodoc:
|
|
210
210
|
post[:aggregate_data] = aggregate_data
|
211
211
|
end
|
212
212
|
|
213
|
+
def add_sub_payments(post, options)
|
214
|
+
# sub_payments field is required for purchase transactions, even if empty
|
215
|
+
post[:sub_payments] = []
|
216
|
+
|
217
|
+
return unless sub_payments = options[:sub_payments]
|
218
|
+
|
219
|
+
sub_payments.each do |sub_payment|
|
220
|
+
sub_payment_hash = {
|
221
|
+
site_id: sub_payment[:site_id],
|
222
|
+
installments: sub_payment[:installments].to_i,
|
223
|
+
amount: sub_payment[:amount].to_i
|
224
|
+
}
|
225
|
+
post[:sub_payments] << sub_payment_hash
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
213
229
|
def add_fraud_detection(options = {})
|
214
230
|
{}.tap do |hsh|
|
215
231
|
hsh[:send_to_cs] = options[:send_to_cs] if valid_fraud_detection_option?(options[:send_to_cs]) # true/false
|
@@ -0,0 +1,344 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class DecidirPlusGateway < Gateway
|
4
|
+
self.test_url = 'https://developers.decidir.com/api/v2'
|
5
|
+
self.live_url = 'https://live.decidir.com/api/v2'
|
6
|
+
|
7
|
+
self.supported_countries = ['AR']
|
8
|
+
self.default_currency = 'ARS'
|
9
|
+
self.supported_cardtypes = %i[visa master american_express discover diners_club naranja cabal]
|
10
|
+
|
11
|
+
self.homepage_url = 'http://decidir.com.ar/home'
|
12
|
+
self.display_name = 'Decidir Plus'
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
requires!(options, :public_key, :private_key)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def purchase(money, payment, options = {})
|
20
|
+
post = {}
|
21
|
+
build_purchase_authorize_request(post, money, payment, options)
|
22
|
+
|
23
|
+
commit(:post, 'payments', post)
|
24
|
+
end
|
25
|
+
|
26
|
+
def authorize(money, payment, options = {})
|
27
|
+
post = {}
|
28
|
+
build_purchase_authorize_request(post, money, payment, options)
|
29
|
+
|
30
|
+
commit(:post, 'payments', post)
|
31
|
+
end
|
32
|
+
|
33
|
+
def capture(money, authorization, options = {})
|
34
|
+
post = {}
|
35
|
+
post[:amount] = money
|
36
|
+
|
37
|
+
commit(:put, "payments/#{add_reference(authorization)}", post)
|
38
|
+
end
|
39
|
+
|
40
|
+
def refund(money, authorization, options = {})
|
41
|
+
post = {}
|
42
|
+
post[:amount] = money
|
43
|
+
|
44
|
+
commit(:post, "payments/#{add_reference(authorization)}/refunds", post)
|
45
|
+
end
|
46
|
+
|
47
|
+
def void(authorization, options = {})
|
48
|
+
commit(:post, "payments/#{add_reference(authorization)}/refunds")
|
49
|
+
end
|
50
|
+
|
51
|
+
def verify(credit_card, options = {})
|
52
|
+
MultiResponse.run(:use_first_response) do |r|
|
53
|
+
r.process { store(credit_card, options) }
|
54
|
+
r.process { authorize(100, r.authorization, options) }
|
55
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def store(payment, options = {})
|
60
|
+
post = {}
|
61
|
+
add_payment(post, payment, options)
|
62
|
+
|
63
|
+
commit(:post, 'tokens', post)
|
64
|
+
end
|
65
|
+
|
66
|
+
def unstore(customer_token)
|
67
|
+
commit(:delete, "cardtokens/#{customer_token}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def supports_scrubbing?
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def scrub(transcript)
|
75
|
+
transcript.
|
76
|
+
gsub(%r((Apikey: )\w+), '\1[FILTERED]').
|
77
|
+
gsub(%r(("card_number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
|
78
|
+
gsub(%r(("security_code\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def build_purchase_authorize_request(post, money, payment, options)
|
84
|
+
add_customer_data(post, options)
|
85
|
+
add_payment(post, payment, options)
|
86
|
+
add_purchase_data(post, money, payment, options)
|
87
|
+
add_fraud_detection(post, options)
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_reference(authorization)
|
91
|
+
return unless authorization
|
92
|
+
|
93
|
+
authorization.split('|')[0]
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_payment(post, payment, options = {})
|
97
|
+
if payment.is_a?(String)
|
98
|
+
token, bin = payment.split('|')
|
99
|
+
post[:token] = token
|
100
|
+
post[:bin] = bin
|
101
|
+
else
|
102
|
+
post[:card_number] = payment.number
|
103
|
+
post[:card_expiration_month] = format(payment.month, :two_digits)
|
104
|
+
post[:card_expiration_year] = format(payment.year, :two_digits)
|
105
|
+
post[:security_code] = payment.verification_value.to_s
|
106
|
+
post[:card_holder_name] = payment.name.empty? ? options[:name_override] : payment.name
|
107
|
+
post[:card_holder_identification] = {}
|
108
|
+
post[:card_holder_identification][:type] = options[:card_holder_identification_type] if options[:card_holder_identification_type]
|
109
|
+
post[:card_holder_identification][:number] = options[:card_holder_identification_number] if options[:card_holder_identification_number]
|
110
|
+
|
111
|
+
# additional data used for Visa transactions
|
112
|
+
post[:card_holder_door_number] = options[:card_holder_door_number].to_i if options[:card_holder_door_number]
|
113
|
+
post[:card_holder_birthday] = options[:card_holder_birthday] if options[:card_holder_birthday]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_customer_data(post, options = {})
|
118
|
+
return unless customer = options[:customer]
|
119
|
+
|
120
|
+
post[:customer] = {}
|
121
|
+
post[:customer][:id] = customer[:id] if customer[:id]
|
122
|
+
post[:customer][:email] = customer[:email] if customer[:email]
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_purchase_data(post, money, payment, options = {})
|
126
|
+
post[:site_transaction_id] = options[:site_transaction_id] || SecureRandom.hex
|
127
|
+
post[:payment_method_id] = add_payment_method_id(options)
|
128
|
+
post[:amount] = money
|
129
|
+
post[:currency] = options[:currency] || self.default_currency
|
130
|
+
post[:installments] = options[:installments] || 1
|
131
|
+
post[:payment_type] = options[:payment_type] || 'single'
|
132
|
+
post[:establishment_name] = options[:establishment_name] if options[:establishment_name]
|
133
|
+
|
134
|
+
add_aggregate_data(post, options) if options[:aggregate_data]
|
135
|
+
add_sub_payments(post, options)
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_aggregate_data(post, options)
|
139
|
+
aggregate_data = {}
|
140
|
+
data = options[:aggregate_data]
|
141
|
+
aggregate_data[:indicator] = data[:indicator] if data[:indicator]
|
142
|
+
aggregate_data[:identification_number] = data[:identification_number] if data[:identification_number]
|
143
|
+
aggregate_data[:bill_to_pay] = data[:bill_to_pay] if data[:bill_to_pay]
|
144
|
+
aggregate_data[:bill_to_refund] = data[:bill_to_refund] if data[:bill_to_refund]
|
145
|
+
aggregate_data[:merchant_name] = data[:merchant_name] if data[:merchant_name]
|
146
|
+
aggregate_data[:street] = data[:street] if data[:street]
|
147
|
+
aggregate_data[:number] = data[:number] if data[:number]
|
148
|
+
aggregate_data[:postal_code] = data[:postal_code] if data[:postal_code]
|
149
|
+
aggregate_data[:category] = data[:category] if data[:category]
|
150
|
+
aggregate_data[:channel] = data[:channel] if data[:channel]
|
151
|
+
aggregate_data[:geographic_code] = data[:geographic_code] if data[:geographic_code]
|
152
|
+
aggregate_data[:city] = data[:city] if data[:city]
|
153
|
+
aggregate_data[:merchant_id] = data[:merchant_id] if data[:merchant_id]
|
154
|
+
aggregate_data[:province] = data[:province] if data[:province]
|
155
|
+
aggregate_data[:country] = data[:country] if data[:country]
|
156
|
+
aggregate_data[:merchant_email] = data[:merchant_email] if data[:merchant_email]
|
157
|
+
aggregate_data[:merchant_phone] = data[:merchant_phone] if data[:merchant_phone]
|
158
|
+
post[:aggregate_data] = aggregate_data
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_sub_payments(post, options)
|
162
|
+
# sub_payments field is required for purchase transactions, even if empty
|
163
|
+
post[:sub_payments] = []
|
164
|
+
|
165
|
+
return unless sub_payments = options[:sub_payments]
|
166
|
+
|
167
|
+
sub_payments.each do |sub_payment|
|
168
|
+
sub_payment_hash = {
|
169
|
+
site_id: sub_payment[:site_id],
|
170
|
+
installments: sub_payment[:installments].to_i,
|
171
|
+
amount: sub_payment[:amount].to_i
|
172
|
+
}
|
173
|
+
post[:sub_payments] << sub_payment_hash
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def add_payment_method_id(options)
|
178
|
+
return options[:payment_method_id].to_i if options[:payment_method_id]
|
179
|
+
|
180
|
+
if options[:debit]
|
181
|
+
case options[:card_brand]
|
182
|
+
when 'visa'
|
183
|
+
31
|
184
|
+
when 'master'
|
185
|
+
105
|
186
|
+
when 'maestro'
|
187
|
+
106
|
188
|
+
when 'cabal'
|
189
|
+
108
|
190
|
+
else
|
191
|
+
31
|
192
|
+
end
|
193
|
+
else
|
194
|
+
case options[:card_brand]
|
195
|
+
when 'visa'
|
196
|
+
1
|
197
|
+
when 'master'
|
198
|
+
104
|
199
|
+
when 'american_express'
|
200
|
+
65
|
201
|
+
when 'american_express_prisma'
|
202
|
+
111
|
203
|
+
when 'cabal'
|
204
|
+
63
|
205
|
+
when 'diners_club'
|
206
|
+
8
|
207
|
+
else
|
208
|
+
1
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def add_fraud_detection(post, options)
|
214
|
+
return unless fraud_detection = options[:fraud_detection]
|
215
|
+
|
216
|
+
{}.tap do |hsh|
|
217
|
+
hsh[:send_to_cs] = fraud_detection[:send_to_cs] == 'true' # true/false
|
218
|
+
hsh[:channel] = fraud_detection[:channel] if fraud_detection[:channel]
|
219
|
+
hsh[:dispatch_method] = fraud_detection[:dispatch_method] if fraud_detection[:dispatch_method]
|
220
|
+
add_csmdds(hsh, fraud_detection)
|
221
|
+
|
222
|
+
post[:fraud_detection] = hsh
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def add_csmdds(hsh, fraud_detection)
|
227
|
+
return unless fraud_detection[:csmdds]
|
228
|
+
|
229
|
+
csmdds_arr = []
|
230
|
+
fraud_detection[:csmdds].each do |csmdds|
|
231
|
+
csmdds_hsh = {}
|
232
|
+
csmdds_hsh[:code] = csmdds[:code].to_i
|
233
|
+
csmdds_hsh[:description] = csmdds[:description]
|
234
|
+
csmdds_arr.append(csmdds_hsh)
|
235
|
+
end
|
236
|
+
hsh[:csmdds] = csmdds_arr unless csmdds_arr.empty?
|
237
|
+
end
|
238
|
+
|
239
|
+
def parse(body)
|
240
|
+
return {} if body.nil?
|
241
|
+
|
242
|
+
JSON.parse(body)
|
243
|
+
end
|
244
|
+
|
245
|
+
def commit(method, endpoint, parameters = {}, options = {})
|
246
|
+
begin
|
247
|
+
raw_response = ssl_request(method, url(endpoint), post_data(parameters), headers(endpoint))
|
248
|
+
response = parse(raw_response)
|
249
|
+
rescue ResponseError => e
|
250
|
+
raw_response = e.response.body
|
251
|
+
response = parse(raw_response)
|
252
|
+
end
|
253
|
+
|
254
|
+
Response.new(
|
255
|
+
success_from(response),
|
256
|
+
message_from(response),
|
257
|
+
response,
|
258
|
+
authorization: authorization_from(response),
|
259
|
+
avs_result: AVSResult.new(code: response['some_avs_response_key']),
|
260
|
+
cvv_result: CVVResult.new(response['some_cvv_response_key']),
|
261
|
+
test: test?,
|
262
|
+
error_code: error_code_from(response)
|
263
|
+
)
|
264
|
+
end
|
265
|
+
|
266
|
+
def headers(endpoint)
|
267
|
+
{
|
268
|
+
'Content-Type' => 'application/json',
|
269
|
+
'apikey' => endpoint == 'tokens' ? @options[:public_key] : @options[:private_key]
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
def url(action, options = {})
|
274
|
+
base_url = (test? ? test_url : live_url)
|
275
|
+
|
276
|
+
return "#{base_url}/#{action}"
|
277
|
+
end
|
278
|
+
|
279
|
+
def success_from(response)
|
280
|
+
response.dig('status') == 'approved' || response.dig('status') == 'active' || response.dig('status') == 'pre_approved' || response.empty?
|
281
|
+
end
|
282
|
+
|
283
|
+
def message_from(response)
|
284
|
+
return '' if response.empty?
|
285
|
+
|
286
|
+
rejected?(response) ? message_from_status_details(response) : response.dig('status') || error_message(response) || response.dig('message')
|
287
|
+
end
|
288
|
+
|
289
|
+
def authorization_from(response)
|
290
|
+
return nil unless response.dig('id') || response.dig('bin')
|
291
|
+
|
292
|
+
"#{response.dig('id')}|#{response.dig('bin')}"
|
293
|
+
end
|
294
|
+
|
295
|
+
def post_data(parameters = {})
|
296
|
+
parameters.to_json
|
297
|
+
end
|
298
|
+
|
299
|
+
def error_code_from(response)
|
300
|
+
return if success_from(response)
|
301
|
+
|
302
|
+
error_code = nil
|
303
|
+
if error = response.dig('status_details', 'error')
|
304
|
+
error_code = error.dig('reason', 'id') || error['type']
|
305
|
+
elsif response['error_type']
|
306
|
+
error_code = response['error_type']
|
307
|
+
elsif response.dig('error', 'validation_errors')
|
308
|
+
error = response.dig('error')
|
309
|
+
validation_errors = error.dig('validation_errors', 0)
|
310
|
+
code = validation_errors['code'] if validation_errors && validation_errors['code']
|
311
|
+
param = validation_errors['param'] if validation_errors && validation_errors['param']
|
312
|
+
error_code = "#{error['error_type']} | #{code} | #{param}" if error['error_type']
|
313
|
+
elsif error = response.dig('error')
|
314
|
+
error_code = error.dig('reason', 'id')
|
315
|
+
end
|
316
|
+
|
317
|
+
error_code
|
318
|
+
end
|
319
|
+
|
320
|
+
def error_message(response)
|
321
|
+
return error_code_from(response) unless validation_errors = response.dig('validation_errors')
|
322
|
+
|
323
|
+
validation_errors = validation_errors[0]
|
324
|
+
|
325
|
+
"#{validation_errors.dig('code')}: #{validation_errors.dig('param')}"
|
326
|
+
end
|
327
|
+
|
328
|
+
def rejected?(response)
|
329
|
+
return response.dig('status') == 'rejected'
|
330
|
+
end
|
331
|
+
|
332
|
+
def message_from_status_details(response)
|
333
|
+
return unless error = response.dig('status_details', 'error')
|
334
|
+
return message_from_fraud_detection(response) if error.dig('type') == 'cybersource_error'
|
335
|
+
|
336
|
+
"#{error.dig('type')}: #{error.dig('reason', 'description')}"
|
337
|
+
end
|
338
|
+
|
339
|
+
def message_from_fraud_detection(response)
|
340
|
+
return error_message(response.dig('fraud_detection', 'status', 'details'))
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
@@ -42,8 +42,8 @@ module ActiveMerchant #:nodoc:
|
|
42
42
|
'ar' => 100,
|
43
43
|
'co' => 100,
|
44
44
|
'pe' => 300,
|
45
|
-
'mx' =>
|
46
|
-
'cl' =>
|
45
|
+
'mx' => 2000,
|
46
|
+
'cl' => 80000
|
47
47
|
}
|
48
48
|
|
49
49
|
def initialize(options = {})
|
@@ -183,6 +183,7 @@ module ActiveMerchant #:nodoc:
|
|
183
183
|
post[:payment][:currency_code] = (options[:currency] || currency(money))
|
184
184
|
post[:payment][:merchant_payment_code] = Digest::MD5.hexdigest(options[:order_id])
|
185
185
|
post[:payment][:instalments] = options[:instalments] || 1
|
186
|
+
post[:payment][:order_number] = options[:order_id][0..39] if options[:order_id]
|
186
187
|
end
|
187
188
|
|
188
189
|
def add_card_or_token(post, payment)
|
@@ -214,6 +215,7 @@ module ActiveMerchant #:nodoc:
|
|
214
215
|
post[:metadata] = options[:metadata] if options[:metadata]
|
215
216
|
post[:metadata] = {} if post[:metadata].nil?
|
216
217
|
post[:metadata][:merchant_payment_code] = options[:order_id] if options[:order_id]
|
218
|
+
post[:processing_type] = options[:processing_type] if options[:processing_type]
|
217
219
|
end
|
218
220
|
|
219
221
|
def parse(body)
|
@@ -222,7 +224,8 @@ module ActiveMerchant #:nodoc:
|
|
222
224
|
|
223
225
|
def commit(action, parameters)
|
224
226
|
url = url_for((test? ? test_url : live_url), action, parameters)
|
225
|
-
|
227
|
+
|
228
|
+
response = parse(ssl_request(HTTP_METHOD[action], url, post_data(action, parameters), headers(parameters)))
|
226
229
|
|
227
230
|
success = success_from(action, response)
|
228
231
|
|
@@ -236,6 +239,19 @@ module ActiveMerchant #:nodoc:
|
|
236
239
|
)
|
237
240
|
end
|
238
241
|
|
242
|
+
def headers(params)
|
243
|
+
processing_type = params[:processing_type]
|
244
|
+
commit_headers = { 'x-ebanx-client-user-agent': "ActiveMerchant/#{ActiveMerchant::VERSION}" }
|
245
|
+
|
246
|
+
add_processing_type_to_commit_headers(commit_headers, processing_type) if processing_type == 'local'
|
247
|
+
|
248
|
+
commit_headers
|
249
|
+
end
|
250
|
+
|
251
|
+
def add_processing_type_to_commit_headers(commit_headers, processing_type)
|
252
|
+
commit_headers['x-ebanx-api-processing-type'] = processing_type
|
253
|
+
end
|
254
|
+
|
239
255
|
def success_from(action, response)
|
240
256
|
if %i[purchase capture refund].include?(action)
|
241
257
|
response.try(:[], 'payment').try(:[], 'status') == 'CO'
|
@@ -298,7 +298,7 @@ module ActiveMerchant #:nodoc:
|
|
298
298
|
xml.ssl_dynamic_dba options[:dba] if options.has_key?(:dba)
|
299
299
|
xml.ssl_merchant_initiated_unscheduled merchant_initiated_unscheduled(options) if merchant_initiated_unscheduled(options)
|
300
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
|
301
|
+
xml.ssl_token options[:ssl_token] if options[:ssl_token]
|
302
302
|
xml.ssl_customer_code options[:customer] if options.has_key?(:customer)
|
303
303
|
xml.ssl_customer_number options[:customer_number] if options.has_key?(:customer_number)
|
304
304
|
xml.ssl_entry_mode entry_mode(options) if entry_mode(options)
|
@@ -393,6 +393,7 @@ module ActiveMerchant #:nodoc:
|
|
393
393
|
|
394
394
|
def commit(request)
|
395
395
|
request = "xmldata=#{request}".delete('&')
|
396
|
+
store_action = request.match?('CCGETTOKEN')
|
396
397
|
|
397
398
|
response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers))
|
398
399
|
response = hash_html_decode(response)
|
@@ -402,7 +403,7 @@ module ActiveMerchant #:nodoc:
|
|
402
403
|
response[:result_message] || response[:errorMessage],
|
403
404
|
response,
|
404
405
|
test: @options[:test] || test?,
|
405
|
-
authorization: authorization_from(response),
|
406
|
+
authorization: authorization_from(response, store_action),
|
406
407
|
error_code: response[:errorCode],
|
407
408
|
avs_result: { code: response[:avs_response] },
|
408
409
|
cvv_result: response[:cvv2_response],
|
@@ -428,7 +429,9 @@ module ActiveMerchant #:nodoc:
|
|
428
429
|
response.deep_transform_keys { |key| key.gsub('ssl_', '').to_sym }
|
429
430
|
end
|
430
431
|
|
431
|
-
def authorization_from(response)
|
432
|
+
def authorization_from(response, store_action)
|
433
|
+
return response[:token] if store_action
|
434
|
+
|
432
435
|
[response[:approval_code], response[:txn_id]].join(';')
|
433
436
|
end
|
434
437
|
|
@@ -82,6 +82,19 @@ module ActiveMerchant #:nodoc:
|
|
82
82
|
commit('CreditCardReturn', request, money)
|
83
83
|
end
|
84
84
|
|
85
|
+
def credit(money, payment, options = {})
|
86
|
+
request = build_soap_request do |xml|
|
87
|
+
xml.CreditCardCredit(xmlns: 'https://transaction.elementexpress.com') do
|
88
|
+
add_credentials(xml)
|
89
|
+
add_payment_method(xml, payment)
|
90
|
+
add_transaction(xml, money, options)
|
91
|
+
add_terminal(xml, options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
commit('CreditCardCredit', request, money)
|
96
|
+
end
|
97
|
+
|
85
98
|
def void(authorization, options = {})
|
86
99
|
trans_id, trans_amount = split_authorization(authorization)
|
87
100
|
options.merge!({ trans_id: trans_id, trans_amount: trans_amount, reversal_type: 'Full' })
|
@@ -186,9 +199,10 @@ module ActiveMerchant #:nodoc:
|
|
186
199
|
xml.ReversalType options[:reversal_type] if options[:reversal_type]
|
187
200
|
xml.TransactionID options[:trans_id] if options[:trans_id]
|
188
201
|
xml.TransactionAmount amount(money.to_i) if money
|
189
|
-
xml.MarketCode
|
202
|
+
xml.MarketCode market_code(money, options) if options[:market_code] || money
|
190
203
|
xml.ReferenceNumber options[:order_id] || SecureRandom.hex(20)
|
191
|
-
|
204
|
+
xml.TicketNumber options[:ticket_number] if options[:ticket_number]
|
205
|
+
xml.MerchantSuppliedTransactionId options[:merchant_supplied_transaction_id] if options[:merchant_supplied_transaction_id]
|
192
206
|
xml.PaymentType options[:payment_type] if options[:payment_type]
|
193
207
|
xml.SubmissionType options[:submission_type] if options[:submission_type]
|
194
208
|
xml.DuplicateCheckDisableFlag options[:duplicate_check_disable_flag].to_s == 'true' ? 'True' : 'False' unless options[:duplicate_check_disable_flag].nil?
|
@@ -197,6 +211,10 @@ module ActiveMerchant #:nodoc:
|
|
197
211
|
end
|
198
212
|
end
|
199
213
|
|
214
|
+
def market_code(money, options)
|
215
|
+
options[:market_code] || 'Default'
|
216
|
+
end
|
217
|
+
|
200
218
|
def add_terminal(xml, options)
|
201
219
|
xml.terminal do
|
202
220
|
xml.TerminalID options[:terminal_id] || '01'
|