activemerchant 1.123.0 → 1.125.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 +131 -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 +6 -3
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/adyen.rb +61 -9
- 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 +33 -4
- data/lib/active_merchant/billing/gateways/cyber_source.rb +11 -3
- data/lib/active_merchant/billing/gateways/d_local.rb +12 -6
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +173 -0
- data/lib/active_merchant/billing/gateways/ebanx.rb +16 -1
- 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 +111 -16
- data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +7 -0
- 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/mundipagg.rb +8 -6
- data/lib/active_merchant/billing/gateways/nmi.rb +15 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +19 -3
- 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 +14 -6
- data/lib/active_merchant/billing/gateways/paymentez.rb +9 -2
- data/lib/active_merchant/billing/gateways/paysafe.rb +144 -23
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -1
- 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 +347 -0
- data/lib/active_merchant/billing/gateways/realex.rb +18 -0
- data/lib/active_merchant/billing/gateways/safe_charge.rb +6 -2
- data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +96 -38
- 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/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 +7 -2
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'openssl'
|
3
|
+
require 'digest'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
module ActiveMerchant #:nodoc:
|
7
|
+
module Billing #:nodoc:
|
8
|
+
class MitGateway < Gateway
|
9
|
+
self.live_url = 'https://wpy.mitec.com.mx/ModuloUtilWS/activeCDP.htm'
|
10
|
+
|
11
|
+
self.supported_countries = ['MX']
|
12
|
+
self.default_currency = 'MXN'
|
13
|
+
self.supported_cardtypes = %i[visa master]
|
14
|
+
|
15
|
+
self.homepage_url = 'http://www.centrodepagos.com.mx/'
|
16
|
+
self.display_name = 'MIT Centro de pagos'
|
17
|
+
|
18
|
+
self.money_format = :dollars
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
requires!(options, :commerce_id, :user, :api_key, :key_session)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def purchase(money, payment, options = {})
|
26
|
+
MultiResponse.run do |r|
|
27
|
+
r.process { authorize(money, payment, options) }
|
28
|
+
r.process { capture(money, r.authorization, options) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def cipher_key
|
33
|
+
@options[:key_session]
|
34
|
+
end
|
35
|
+
|
36
|
+
def decrypt(val, keyinhex)
|
37
|
+
# Splits the first 16 bytes (the IV bytes) in array format
|
38
|
+
unpacked = val.unpack('m')
|
39
|
+
iv_base64 = unpacked[0].bytes.slice(0, 16)
|
40
|
+
# Splits the second bytes (the encrypted text bytes) these would be the
|
41
|
+
# original message
|
42
|
+
full_data = unpacked[0].bytes.slice(16, unpacked[0].bytes.length)
|
43
|
+
# Creates the engine
|
44
|
+
engine = OpenSSL::Cipher::AES128.new(:CBC)
|
45
|
+
# Set engine as decrypt mode
|
46
|
+
engine.decrypt
|
47
|
+
# Converts the key from hex to bytes
|
48
|
+
engine.key = [keyinhex].pack('H*')
|
49
|
+
# Converts the ivBase64 array into bytes
|
50
|
+
engine.iv = iv_base64.pack('c*')
|
51
|
+
# Decrypts the texts and returns the original string
|
52
|
+
engine.update(full_data.pack('c*')) + engine.final
|
53
|
+
end
|
54
|
+
|
55
|
+
def encrypt(val, keyinhex)
|
56
|
+
# Creates the engine motor
|
57
|
+
engine = OpenSSL::Cipher::AES128.new(:CBC)
|
58
|
+
# Set engine as encrypt mode
|
59
|
+
engine.encrypt
|
60
|
+
# Converts the key from hex to bytes
|
61
|
+
engine.key = [keyinhex].pack('H*')
|
62
|
+
# Generates a random iv with this settings
|
63
|
+
iv_rand = engine.random_iv
|
64
|
+
# Packs IV as a Base64 string
|
65
|
+
iv_base64 = [iv_rand].pack('m')
|
66
|
+
# Converts the packed key into bytes
|
67
|
+
unpacked = iv_base64.unpack('m')
|
68
|
+
iv = unpacked[0]
|
69
|
+
# Sets the IV into the engine
|
70
|
+
engine.iv = iv
|
71
|
+
# Encrypts the texts and stores the bytes
|
72
|
+
encrypted_bytes = engine.update(val) + engine.final
|
73
|
+
# Concatenates the (a) IV bytes and (b) the encrypted bytes then returns a
|
74
|
+
# base64 representation
|
75
|
+
[iv << encrypted_bytes].pack('m')
|
76
|
+
end
|
77
|
+
|
78
|
+
def authorize(money, payment, options = {})
|
79
|
+
post = {
|
80
|
+
operation: 'Authorize',
|
81
|
+
commerce_id: @options[:commerce_id],
|
82
|
+
user: @options[:user],
|
83
|
+
apikey: @options[:api_key],
|
84
|
+
testMode: (test? ? 'YES' : 'NO')
|
85
|
+
}
|
86
|
+
add_invoice(post, money, options)
|
87
|
+
# Payments contains the card information
|
88
|
+
add_payment(post, payment)
|
89
|
+
add_customer_data(post, options)
|
90
|
+
post[:key_session] = @options[:key_session]
|
91
|
+
|
92
|
+
post_to_json = post.to_json
|
93
|
+
post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
|
94
|
+
|
95
|
+
final_post = '<authorization>' + post_to_json_encrypt + '</authorization><dataID>' + @options[:user] + '</dataID>'
|
96
|
+
json_post = {}
|
97
|
+
json_post[:payload] = final_post
|
98
|
+
commit('sale', json_post)
|
99
|
+
end
|
100
|
+
|
101
|
+
def capture(money, authorization, options = {})
|
102
|
+
post = {
|
103
|
+
operation: 'Capture',
|
104
|
+
commerce_id: @options[:commerce_id],
|
105
|
+
user: @options[:user],
|
106
|
+
apikey: @options[:api_key],
|
107
|
+
testMode: (test? ? 'YES' : 'NO'),
|
108
|
+
transaction_id: authorization,
|
109
|
+
amount: amount(money)
|
110
|
+
}
|
111
|
+
post[:key_session] = @options[:key_session]
|
112
|
+
|
113
|
+
post_to_json = post.to_json
|
114
|
+
post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
|
115
|
+
|
116
|
+
final_post = '<capture>' + post_to_json_encrypt + '</capture><dataID>' + @options[:user] + '</dataID>'
|
117
|
+
json_post = {}
|
118
|
+
json_post[:payload] = final_post
|
119
|
+
commit('capture', json_post)
|
120
|
+
end
|
121
|
+
|
122
|
+
def refund(money, authorization, options = {})
|
123
|
+
post = {
|
124
|
+
operation: 'Refund',
|
125
|
+
commerce_id: @options[:commerce_id],
|
126
|
+
user: @options[:user],
|
127
|
+
apikey: @options[:api_key],
|
128
|
+
testMode: (test? ? 'YES' : 'NO'),
|
129
|
+
transaction_id: authorization,
|
130
|
+
auth: authorization,
|
131
|
+
amount: amount(money)
|
132
|
+
}
|
133
|
+
post[:key_session] = @options[:key_session]
|
134
|
+
|
135
|
+
post_to_json = post.to_json
|
136
|
+
post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
|
137
|
+
|
138
|
+
final_post = '<refund>' + post_to_json_encrypt + '</refund><dataID>' + @options[:user] + '</dataID>'
|
139
|
+
json_post = {}
|
140
|
+
json_post[:payload] = final_post
|
141
|
+
commit('refund', json_post)
|
142
|
+
end
|
143
|
+
|
144
|
+
def supports_scrubbing?
|
145
|
+
true
|
146
|
+
end
|
147
|
+
|
148
|
+
def scrub(transcript)
|
149
|
+
ret_transcript = transcript
|
150
|
+
auth_origin = ret_transcript[/<authorization>(.*?)<\/authorization>/, 1]
|
151
|
+
unless auth_origin.nil?
|
152
|
+
auth_decrypted = decrypt(auth_origin, @options[:key_session])
|
153
|
+
auth_json = JSON.parse(auth_decrypted)
|
154
|
+
auth_json['card'] = '[FILTERED]'
|
155
|
+
auth_json['cvv'] = '[FILTERED]'
|
156
|
+
auth_json['apikey'] = '[FILTERED]'
|
157
|
+
auth_json['key_session'] = '[FILTERED]'
|
158
|
+
auth_to_json = auth_json.to_json
|
159
|
+
auth_tagged = '<authorization>' + auth_to_json + '</authorization>'
|
160
|
+
ret_transcript = ret_transcript.gsub(/<authorization>(.*?)<\/authorization>/, auth_tagged)
|
161
|
+
end
|
162
|
+
|
163
|
+
cap_origin = ret_transcript[/<capture>(.*?)<\/capture>/, 1]
|
164
|
+
unless cap_origin.nil?
|
165
|
+
cap_decrypted = decrypt(cap_origin, @options[:key_session])
|
166
|
+
cap_json = JSON.parse(cap_decrypted)
|
167
|
+
cap_json['apikey'] = '[FILTERED]'
|
168
|
+
cap_json['key_session'] = '[FILTERED]'
|
169
|
+
cap_to_json = cap_json.to_json
|
170
|
+
cap_tagged = '<capture>' + cap_to_json + '</capture>'
|
171
|
+
ret_transcript = ret_transcript.gsub(/<capture>(.*?)<\/capture>/, cap_tagged)
|
172
|
+
end
|
173
|
+
|
174
|
+
ref_origin = ret_transcript[/<refund>(.*?)<\/refund>/, 1]
|
175
|
+
unless ref_origin.nil?
|
176
|
+
ref_decrypted = decrypt(ref_origin, @options[:key_session])
|
177
|
+
ref_json = JSON.parse(ref_decrypted)
|
178
|
+
ref_json['apikey'] = '[FILTERED]'
|
179
|
+
ref_json['key_session'] = '[FILTERED]'
|
180
|
+
ref_to_json = ref_json.to_json
|
181
|
+
ref_tagged = '<refund>' + ref_to_json + '</refund>'
|
182
|
+
ret_transcript = ret_transcript.gsub(/<refund>(.*?)<\/refund>/, ref_tagged)
|
183
|
+
end
|
184
|
+
|
185
|
+
res_origin = ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1]
|
186
|
+
loop do
|
187
|
+
break if res_origin.nil?
|
188
|
+
|
189
|
+
resp_origin = res_origin[/#{Regexp.escape('"')}(.*?)#{Regexp.escape('"')}/m, 1]
|
190
|
+
resp_decrypted = decrypt(resp_origin, @options[:key_session])
|
191
|
+
ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1] = resp_decrypted
|
192
|
+
ret_transcript = ret_transcript.sub('reading ', 'response: ')
|
193
|
+
res_origin = ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1]
|
194
|
+
end
|
195
|
+
|
196
|
+
ret_transcript
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def add_customer_data(post, options)
|
202
|
+
post[:email] = options[:email] || 'nadie@mit.test'
|
203
|
+
end
|
204
|
+
|
205
|
+
def add_invoice(post, money, options)
|
206
|
+
post[:amount] = amount(money)
|
207
|
+
post[:currency] = (options[:currency] || currency(money))
|
208
|
+
post[:reference] = options[:order_id]
|
209
|
+
post[:transaction_id] = options[:order_id]
|
210
|
+
end
|
211
|
+
|
212
|
+
def add_payment(post, payment)
|
213
|
+
post[:installments] = 1
|
214
|
+
post[:card] = payment.number
|
215
|
+
post[:expmonth] = payment.month
|
216
|
+
post[:expyear] = payment.year
|
217
|
+
post[:cvv] = payment.verification_value
|
218
|
+
post[:name_client] = [payment.first_name, payment.last_name].join(' ')
|
219
|
+
end
|
220
|
+
|
221
|
+
def commit(action, parameters)
|
222
|
+
json_str = JSON.generate(parameters)
|
223
|
+
cleaned_str = json_str.gsub('\n', '')
|
224
|
+
raw_response = ssl_post(live_url, cleaned_str, { 'Content-type' => 'application/json' })
|
225
|
+
response = JSON.parse(decrypt(raw_response, @options[:key_session]))
|
226
|
+
|
227
|
+
Response.new(
|
228
|
+
success_from(response),
|
229
|
+
message_from(response),
|
230
|
+
response,
|
231
|
+
authorization: authorization_from(response),
|
232
|
+
avs_result: AVSResult.new(code: response['some_avs_response_key']),
|
233
|
+
cvv_result: CVVResult.new(response['some_cvv_response_key']),
|
234
|
+
test: test?,
|
235
|
+
error_code: error_code_from(response)
|
236
|
+
)
|
237
|
+
end
|
238
|
+
|
239
|
+
def success_from(response)
|
240
|
+
response['response'] == 'approved'
|
241
|
+
end
|
242
|
+
|
243
|
+
def message_from(response)
|
244
|
+
response['response']
|
245
|
+
end
|
246
|
+
|
247
|
+
def authorization_from(response)
|
248
|
+
response['reference']
|
249
|
+
end
|
250
|
+
|
251
|
+
def post_data(action, parameters = {})
|
252
|
+
parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&')
|
253
|
+
end
|
254
|
+
|
255
|
+
def error_code_from(response)
|
256
|
+
response['message'].split(' -- ', 2)[0] unless success_from(response)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
3
|
class MokaGateway < Gateway
|
4
|
-
self.test_url = 'https://service.
|
4
|
+
self.test_url = 'https://service.refmoka.com'
|
5
5
|
self.live_url = 'https://service.moka.com'
|
6
6
|
|
7
7
|
self.supported_countries = %w[GB TR US]
|
@@ -55,8 +55,10 @@ module ActiveMerchant #:nodoc:
|
|
55
55
|
post[:PaymentDealerRequest] = {}
|
56
56
|
options[:pre_auth] = 0
|
57
57
|
add_auth_purchase(post, money, payment, options)
|
58
|
+
add_3ds_data(post, options) if options[:execute_threed]
|
58
59
|
|
59
|
-
|
60
|
+
action = options[:execute_threed] ? 'three_ds_purchase' : 'purchase'
|
61
|
+
commit(action, post)
|
60
62
|
end
|
61
63
|
|
62
64
|
def authorize(money, payment, options = {})
|
@@ -64,8 +66,10 @@ module ActiveMerchant #:nodoc:
|
|
64
66
|
post[:PaymentDealerRequest] = {}
|
65
67
|
options[:pre_auth] = 1
|
66
68
|
add_auth_purchase(post, money, payment, options)
|
69
|
+
add_3ds_data(post, options) if options[:execute_threed]
|
67
70
|
|
68
|
-
|
71
|
+
action = options[:execute_threed] ? 'three_ds_authorize' : 'authorize'
|
72
|
+
commit(action, post)
|
69
73
|
end
|
70
74
|
|
71
75
|
def capture(money, authorization, options = {})
|
@@ -73,7 +77,7 @@ module ActiveMerchant #:nodoc:
|
|
73
77
|
post[:PaymentDealerRequest] = {}
|
74
78
|
add_payment_dealer_authentication(post)
|
75
79
|
add_transaction_reference(post, authorization)
|
76
|
-
|
80
|
+
add_invoice(post, money, options)
|
77
81
|
|
78
82
|
commit('capture', post)
|
79
83
|
end
|
@@ -83,7 +87,6 @@ module ActiveMerchant #:nodoc:
|
|
83
87
|
post[:PaymentDealerRequest] = {}
|
84
88
|
add_payment_dealer_authentication(post)
|
85
89
|
add_transaction_reference(post, authorization)
|
86
|
-
add_additional_transaction_data(post, options)
|
87
90
|
add_void_refund_reason(post)
|
88
91
|
add_amount(post, money)
|
89
92
|
|
@@ -95,7 +98,6 @@ module ActiveMerchant #:nodoc:
|
|
95
98
|
post[:PaymentDealerRequest] = {}
|
96
99
|
add_payment_dealer_authentication(post)
|
97
100
|
add_transaction_reference(post, authorization)
|
98
|
-
add_additional_transaction_data(post, options)
|
99
101
|
add_void_refund_reason(post)
|
100
102
|
|
101
103
|
commit('void', post)
|
@@ -134,6 +136,12 @@ module ActiveMerchant #:nodoc:
|
|
134
136
|
add_basket_product(post, options[:basket_product]) if options[:basket_product]
|
135
137
|
end
|
136
138
|
|
139
|
+
def add_3ds_data(post, options)
|
140
|
+
post[:PaymentDealerRequest][:ReturnHash] = 1
|
141
|
+
post[:PaymentDealerRequest][:RedirectUrl] = options[:redirect_url] || ''
|
142
|
+
post[:PaymentDealerRequest][:RedirectType] = options[:redirect_type] || 0
|
143
|
+
end
|
144
|
+
|
137
145
|
def add_payment_dealer_authentication(post)
|
138
146
|
post[:PaymentDealerAuthentication] = {
|
139
147
|
DealerCode: @options[:dealer_code],
|
@@ -156,18 +164,19 @@ module ActiveMerchant #:nodoc:
|
|
156
164
|
def add_payment(post, card)
|
157
165
|
post[:PaymentDealerRequest][:CardHolderFullName] = card.name
|
158
166
|
post[:PaymentDealerRequest][:CardNumber] = card.number
|
159
|
-
post[:PaymentDealerRequest][:ExpMonth] = card.month
|
167
|
+
post[:PaymentDealerRequest][:ExpMonth] = card.month.to_s.rjust(2, '0')
|
160
168
|
post[:PaymentDealerRequest][:ExpYear] = card.year
|
161
|
-
post[:PaymentDealerRequest][:CvcNumber] = card.verification_value
|
169
|
+
post[:PaymentDealerRequest][:CvcNumber] = card.verification_value || ''
|
162
170
|
end
|
163
171
|
|
164
172
|
def add_amount(post, money)
|
165
|
-
post[:PaymentDealerRequest][:Amount] = money || 0
|
173
|
+
post[:PaymentDealerRequest][:Amount] = amount(money) || 0
|
166
174
|
end
|
167
175
|
|
168
176
|
def add_additional_auth_purchase_data(post, options)
|
169
177
|
post[:PaymentDealerRequest][:IsPreAuth] = options[:pre_auth]
|
170
|
-
post[:PaymentDealerRequest][:Description] = options[:
|
178
|
+
post[:PaymentDealerRequest][:Description] = options[:description] if options[:description]
|
179
|
+
post[:PaymentDealerRequest][:InstallmentNumber] = options[:installment_number].to_i if options[:installment_number]
|
171
180
|
post[:SubMerchantName] = options[:sub_merchant_name] if options[:sub_merchant_name]
|
172
181
|
post[:IsPoolPayment] = options[:is_pool_payment] || 0
|
173
182
|
end
|
@@ -232,6 +241,8 @@ module ActiveMerchant #:nodoc:
|
|
232
241
|
|
233
242
|
def endpoint(action)
|
234
243
|
case action
|
244
|
+
when 'three_ds_authorize', 'three_ds_purchase'
|
245
|
+
'DoDirectPaymentThreeD'
|
235
246
|
when 'purchase', 'authorize'
|
236
247
|
'DoDirectPayment'
|
237
248
|
when 'capture'
|
@@ -256,7 +267,9 @@ module ActiveMerchant #:nodoc:
|
|
256
267
|
end
|
257
268
|
|
258
269
|
def success_from(response)
|
259
|
-
response.dig('Data', 'IsSuccessful')
|
270
|
+
return response.dig('Data', 'IsSuccessful') if response.dig('Data', 'IsSuccessful').to_s.present?
|
271
|
+
|
272
|
+
response['ResultCode']&.casecmp('success') == 0
|
260
273
|
end
|
261
274
|
|
262
275
|
def message_from(response)
|
@@ -276,14 +276,14 @@ module ActiveMerchant #:nodoc:
|
|
276
276
|
end
|
277
277
|
|
278
278
|
Response.new(
|
279
|
-
success_from(response),
|
279
|
+
success_from(response, action),
|
280
280
|
message_from(response),
|
281
281
|
response,
|
282
282
|
authorization: authorization_from(response, action),
|
283
283
|
avs_result: AVSResult.new(code: response['some_avs_response_key']),
|
284
284
|
cvv_result: CVVResult.new(response['some_cvv_response_key']),
|
285
285
|
test: test?,
|
286
|
-
error_code: error_code_from(response)
|
286
|
+
error_code: error_code_from(response, action)
|
287
287
|
)
|
288
288
|
rescue ResponseError => e
|
289
289
|
message = get_error_messages(e)
|
@@ -297,8 +297,10 @@ module ActiveMerchant #:nodoc:
|
|
297
297
|
)
|
298
298
|
end
|
299
299
|
|
300
|
-
def success_from(response)
|
301
|
-
|
300
|
+
def success_from(response, action)
|
301
|
+
success = response.try(:[], 'last_transaction').try(:[], 'success') unless action == 'store'
|
302
|
+
success = !response.try(:[], 'id').nil? if action == 'store'
|
303
|
+
success
|
302
304
|
end
|
303
305
|
|
304
306
|
def message_from(response)
|
@@ -350,8 +352,8 @@ module ActiveMerchant #:nodoc:
|
|
350
352
|
parameters.to_json
|
351
353
|
end
|
352
354
|
|
353
|
-
def error_code_from(response)
|
354
|
-
return if success_from(response)
|
355
|
+
def error_code_from(response, action)
|
356
|
+
return if success_from(response, action)
|
355
357
|
return response['last_transaction']['acquirer_return_code'] if response['last_transaction']
|
356
358
|
|
357
359
|
STANDARD_ERROR_CODE[:processing_error]
|
@@ -206,7 +206,8 @@ module ActiveMerchant #:nodoc:
|
|
206
206
|
post[:stored_credential_indicator] = 'stored'
|
207
207
|
else
|
208
208
|
post[:stored_credential_indicator] = 'used'
|
209
|
-
|
209
|
+
# should only send :initial_transaction_id if it is a MIT
|
210
|
+
post[:initial_transaction_id] = stored_credential[:network_transaction_id] if post[:initiated_by] == 'merchant'
|
210
211
|
end
|
211
212
|
end
|
212
213
|
|
@@ -236,6 +237,19 @@ module ActiveMerchant #:nodoc:
|
|
236
237
|
post[:shipping_zip] = shipping_address[:zip]
|
237
238
|
post[:shipping_phone] = shipping_address[:phone]
|
238
239
|
end
|
240
|
+
|
241
|
+
if (descriptor = options[:descriptors])
|
242
|
+
post[:descriptor] = descriptor[:descriptor]
|
243
|
+
post[:descriptor_phone] = descriptor[:descriptor_phone]
|
244
|
+
post[:descriptor_address] = descriptor[:descriptor_address]
|
245
|
+
post[:descriptor_city] = descriptor[:descriptor_city]
|
246
|
+
post[:descriptor_state] = descriptor[:descriptor_state]
|
247
|
+
post[:descriptor_postal] = descriptor[:descriptor_postal]
|
248
|
+
post[:descriptor_country] = descriptor[:descriptor_country]
|
249
|
+
post[:descriptor_mcc] = descriptor[:descriptor_mcc]
|
250
|
+
post[:descriptor_merchant_id] = descriptor[:descriptor_merchant_id]
|
251
|
+
post[:descriptor_url] = descriptor[:descriptor_url]
|
252
|
+
end
|
239
253
|
end
|
240
254
|
|
241
255
|
def add_vendor_data(post, options)
|
@@ -220,8 +220,9 @@ module ActiveMerchant #:nodoc:
|
|
220
220
|
end
|
221
221
|
|
222
222
|
def verify(creditcard, options = {})
|
223
|
+
amount = allow_0_auth?(creditcard) ? 0 : 100
|
223
224
|
MultiResponse.run(:use_first_response) do |r|
|
224
|
-
r.process { authorize(
|
225
|
+
r.process { authorize(amount, creditcard, options) }
|
225
226
|
r.process(:ignore_result) { void(r.authorization) }
|
226
227
|
end
|
227
228
|
end
|
@@ -276,6 +277,11 @@ module ActiveMerchant #:nodoc:
|
|
276
277
|
commit(order, :void, options[:retry_logic], options[:trace_number])
|
277
278
|
end
|
278
279
|
|
280
|
+
def allow_0_auth?(credit_card)
|
281
|
+
# Discover does not support a $0.00 authorization instead use $1.00
|
282
|
+
%w(visa master american_express diners_club jcb).include?(credit_card.brand)
|
283
|
+
end
|
284
|
+
|
279
285
|
# ==== Customer Profiles
|
280
286
|
# :customer_ref_num should be set unless you're happy with Orbital providing one
|
281
287
|
#
|
@@ -337,7 +343,8 @@ module ActiveMerchant #:nodoc:
|
|
337
343
|
gsub(%r((<CustomerMerchantID>).+(</CustomerMerchantID>)), '\1[FILTERED]\2').
|
338
344
|
gsub(%r((<CustomerProfileMessage>).+(</CustomerProfileMessage>)), '\1[FILTERED]\2').
|
339
345
|
gsub(%r((<CheckDDA>).+(</CheckDDA>)), '\1[FILTERED]\2').
|
340
|
-
gsub(%r((<BCRtNum>).+(</BCRtNum>)), '\1[FILTERED]\2')
|
346
|
+
gsub(%r((<BCRtNum>).+(</BCRtNum>)), '\1[FILTERED]\2').
|
347
|
+
gsub(%r((<DigitalTokenCryptogram>).+(</DigitalTokenCryptogram>)), '\1[FILTERED]\2')
|
341
348
|
end
|
342
349
|
|
343
350
|
private
|
@@ -569,7 +576,7 @@ module ActiveMerchant #:nodoc:
|
|
569
576
|
# - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
|
570
577
|
unless creditcard.nil?
|
571
578
|
if creditcard.verification_value?
|
572
|
-
xml.tag! :CardSecValInd, '1' if %w(visa discover).include?(creditcard.brand)
|
579
|
+
xml.tag! :CardSecValInd, '1' if %w(visa master discover).include?(creditcard.brand)
|
573
580
|
xml.tag! :CardSecVal, creditcard.verification_value
|
574
581
|
end
|
575
582
|
end
|
@@ -631,6 +638,14 @@ module ActiveMerchant #:nodoc:
|
|
631
638
|
xml.tag!(:SCARecurringPayment, parameters[:sca_recurring]) if valid_eci
|
632
639
|
end
|
633
640
|
|
641
|
+
def add_mc_sca_merchant_initiated(xml, creditcard, parameters, three_d_secure)
|
642
|
+
return unless parameters && parameters[:sca_merchant_initiated] && creditcard.brand == 'master'
|
643
|
+
|
644
|
+
valid_eci = three_d_secure && three_d_secure[:eci] && three_d_secure[:eci] == '7'
|
645
|
+
|
646
|
+
xml.tag!(:SCAMerchantInitiatedTransaction, parameters[:sca_merchant_initiated]) if valid_eci
|
647
|
+
end
|
648
|
+
|
634
649
|
def add_dpanind(xml, creditcard)
|
635
650
|
return unless creditcard.is_a?(NetworkTokenizationCreditCard)
|
636
651
|
|
@@ -899,6 +914,7 @@ module ActiveMerchant #:nodoc:
|
|
899
914
|
add_card_indicators(xml, parameters)
|
900
915
|
add_stored_credentials(xml, parameters)
|
901
916
|
add_pymt_brand_program_code(xml, payment_source, three_d_secure)
|
917
|
+
add_mc_sca_merchant_initiated(xml, payment_source, parameters, three_d_secure)
|
902
918
|
add_mc_scarecurring(xml, payment_source, parameters, three_d_secure)
|
903
919
|
add_mc_program_protocol(xml, payment_source, three_d_secure)
|
904
920
|
add_mc_directory_trans_id(xml, payment_source, three_d_secure)
|
@@ -286,16 +286,18 @@ module ActiveMerchant #:nodoc:
|
|
286
286
|
end
|
287
287
|
|
288
288
|
def add_address(post, options)
|
289
|
-
|
290
|
-
|
291
|
-
post['
|
292
|
-
post['
|
293
|
-
post['
|
294
|
-
post['
|
289
|
+
return unless billing_address = options[:billing_address]
|
290
|
+
|
291
|
+
post['address_line1'] = billing_address[:address1]
|
292
|
+
post['address_line2'] = billing_address[:address2]
|
293
|
+
post['city'] = billing_address[:city]
|
294
|
+
post['state'] = billing_address[:state]
|
295
|
+
post['zip'] = billing_address[:zip]
|
296
|
+
post['country'] = billing_address[:country]
|
295
297
|
end
|
296
298
|
|
297
299
|
def add_phone(post, options)
|
298
|
-
post['
|
300
|
+
post['phone_number'] = options[:billing_address][:phone] if options.dig(:billing_address, :phone)
|
299
301
|
end
|
300
302
|
|
301
303
|
def add_money(post, money, options)
|
@@ -79,7 +79,9 @@ module ActiveMerchant #:nodoc:
|
|
79
79
|
force_utf8(transcript).
|
80
80
|
gsub(%r((api_accesskey=)\w+), '\1[FILTERED]').
|
81
81
|
gsub(%r((card_number=)\w+), '\1[FILTERED]').
|
82
|
-
gsub(%r((card_verification=)\w+), '\1[FILTERED]')
|
82
|
+
gsub(%r((card_verification=)\w+), '\1[FILTERED]').
|
83
|
+
gsub(%r((bank_account_number=)\w+), '\1[FILTERED]').
|
84
|
+
gsub(%r((bank_routing_number=)\w+), '\1[FILTERED]')
|
83
85
|
end
|
84
86
|
|
85
87
|
private
|
@@ -118,7 +118,7 @@ module ActiveMerchant #:nodoc:
|
|
118
118
|
check_token_response(response, ENDPOINTS[:store], post, options)
|
119
119
|
end
|
120
120
|
|
121
|
-
def
|
121
|
+
def unstore(customer_id)
|
122
122
|
post = {}
|
123
123
|
post[:customer_id] = customer_id
|
124
124
|
response = commit(ENDPOINTS[:redact], post)
|
@@ -289,20 +289,28 @@ module ActiveMerchant #:nodoc:
|
|
289
289
|
xml.tag! 'ECI', three_d_secure[:eci] unless three_d_secure[:eci].blank?
|
290
290
|
xml.tag! 'CAVV', three_d_secure[:cavv] unless three_d_secure[:cavv].blank?
|
291
291
|
xml.tag! 'XID', three_d_secure[:xid] unless three_d_secure[:xid].blank?
|
292
|
-
xml.tag! '
|
293
|
-
xml.tag! '
|
292
|
+
xml.tag! 'ThreeDSVersion', three_d_secure[:version] unless three_d_secure[:version].blank?
|
293
|
+
xml.tag! 'DSTransactionID', three_d_secure[:ds_transaction_id] unless three_d_secure[:ds_transaction_id].blank?
|
294
294
|
end
|
295
295
|
end
|
296
296
|
end
|
297
297
|
|
298
298
|
def authentication_status(three_d_secure, xml)
|
299
|
-
if three_d_secure[:authentication_response_status].present?
|
300
|
-
|
301
|
-
|
302
|
-
|
299
|
+
status = if three_d_secure[:authentication_response_status].present?
|
300
|
+
three_d_secure[:authentication_response_status]
|
301
|
+
elsif three_d_secure[:directory_response_status].present?
|
302
|
+
three_d_secure[:directory_response_status]
|
303
|
+
end
|
304
|
+
if status.present?
|
305
|
+
xml.tag! 'Status', status
|
306
|
+
xml.tag! 'AuthenticationStatus', status if version_2_or_newer?(three_d_secure)
|
303
307
|
end
|
304
308
|
end
|
305
309
|
|
310
|
+
def version_2_or_newer?(three_d_secure)
|
311
|
+
three_d_secure[:version]&.start_with?('2')
|
312
|
+
end
|
313
|
+
|
306
314
|
def credit_card_type(credit_card)
|
307
315
|
return '' if card_brand(credit_card).blank?
|
308
316
|
|
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
|
|
9
9
|
|
10
10
|
self.supported_countries = %w[MX EC CO BR CL PE]
|
11
11
|
self.default_currency = 'USD'
|
12
|
-
self.supported_cardtypes = %i[visa master american_express diners_club elo alia olimpica]
|
12
|
+
self.supported_cardtypes = %i[visa master american_express diners_club elo alia olimpica discover maestro sodexo carnet unionpay jcb]
|
13
13
|
|
14
14
|
self.homepage_url = 'https://secure.paymentez.com/'
|
15
15
|
self.display_name = 'Paymentez'
|
@@ -39,7 +39,14 @@ module ActiveMerchant #:nodoc:
|
|
39
39
|
'master' => 'mc',
|
40
40
|
'american_express' => 'ax',
|
41
41
|
'diners_club' => 'di',
|
42
|
-
'elo' => 'el'
|
42
|
+
'elo' => 'el',
|
43
|
+
'discover' => 'dc',
|
44
|
+
'maestro' => 'ms',
|
45
|
+
'sodexo' => 'sx',
|
46
|
+
'olimpica' => 'ol',
|
47
|
+
'carnet' => 'ct',
|
48
|
+
'unionpay' => 'up',
|
49
|
+
'jcb' => 'jc'
|
43
50
|
}.freeze
|
44
51
|
|
45
52
|
def initialize(options = {})
|