activemerchant 1.116.0 → 1.121.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +148 -1
- data/README.md +4 -2
- data/lib/active_merchant/billing/check.rb +10 -0
- data/lib/active_merchant/billing/credit_card.rb +3 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +80 -15
- data/lib/active_merchant/billing/gateways/adyen.rb +29 -8
- data/lib/active_merchant/billing/gateways/authorize_net.rb +37 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +4 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +3 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +54 -7
- data/lib/active_merchant/billing/gateways/cashnet.rb +7 -2
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +33 -2
- data/lib/active_merchant/billing/gateways/credorax.rb +30 -14
- data/lib/active_merchant/billing/gateways/cyber_source.rb +51 -8
- data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
- data/lib/active_merchant/billing/gateways/decidir.rb +22 -2
- data/lib/active_merchant/billing/gateways/elavon.rb +54 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +13 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +17 -6
- data/lib/active_merchant/billing/gateways/forte.rb +12 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +25 -6
- data/lib/active_merchant/billing/gateways/hps.rb +65 -2
- data/lib/active_merchant/billing/gateways/litle.rb +21 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +2 -2
- data/lib/active_merchant/billing/gateways/netbanx.rb +37 -2
- data/lib/active_merchant/billing/gateways/orbital.rb +178 -45
- data/lib/active_merchant/billing/gateways/payeezy.rb +53 -11
- data/lib/active_merchant/billing/gateways/payment_express.rb +10 -5
- data/lib/active_merchant/billing/gateways/paymentez.rb +21 -1
- data/lib/active_merchant/billing/gateways/paypal.rb +10 -2
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -0
- data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
- data/lib/active_merchant/billing/gateways/pin.rb +11 -0
- data/lib/active_merchant/billing/gateways/qvalent.rb +23 -9
- data/lib/active_merchant/billing/gateways/redsys.rb +101 -5
- data/lib/active_merchant/billing/gateways/safe_charge.rb +39 -6
- data/lib/active_merchant/billing/gateways/stripe.rb +9 -9
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +82 -25
- data/lib/active_merchant/billing/gateways/vpos.rb +177 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +31 -14
- data/lib/active_merchant/billing/response.rb +2 -1
- data/lib/active_merchant/version.rb +1 -1
- data/lib/certs/cacert.pem +1582 -2431
- metadata +5 -3
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
|
7
7
|
self.supported_countries = %w[AR BR CL CO MX PE UY TR]
|
8
8
|
self.default_currency = 'USD'
|
9
|
-
self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro naranja cabal]
|
9
|
+
self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro naranja cabal elo alia carnet]
|
10
10
|
|
11
11
|
self.homepage_url = 'https://dlocal.com/'
|
12
12
|
self.display_name = 'dLocal'
|
@@ -170,6 +170,12 @@ module ActiveMerchant #:nodoc:
|
|
170
170
|
card_data[:security_code] = credit_card.verification_value if credit_card.verification_value?
|
171
171
|
card_data[:card_holder_name] = credit_card.name if credit_card.name
|
172
172
|
|
173
|
+
# the device_unique_id has to be sent in via the card data (as device_unique_identifier) no other fraud detection fields require this
|
174
|
+
if options[:fraud_detection].present?
|
175
|
+
card_data[:fraud_detection] = {} if (options[:fraud_detection][:device_unique_id]).present?
|
176
|
+
card_data[:fraud_detection][:device_unique_identifier] = (options[:fraud_detection][:device_unique_id]) if (options[:fraud_detection][:device_unique_id]).present?
|
177
|
+
end
|
178
|
+
|
173
179
|
# additional data used for Visa transactions
|
174
180
|
card_data[:card_holder_door_number] = options[:card_holder_door_number].to_i if options[:card_holder_door_number]
|
175
181
|
card_data[:card_holder_birthday] = options[:card_holder_birthday] if options[:card_holder_birthday]
|
@@ -210,6 +216,14 @@ module ActiveMerchant #:nodoc:
|
|
210
216
|
hsh[:channel] = options[:channel] if valid_fraud_detection_option?(options[:channel])
|
211
217
|
hsh[:dispatch_method] = options[:dispatch_method] if valid_fraud_detection_option?(options[:dispatch_method])
|
212
218
|
hsh[:csmdds] = options[:csmdds] if valid_fraud_detection_option?(options[:csmdds])
|
219
|
+
hsh[:device_unique_id] = options[:device_unique_id] if valid_fraud_detection_option?(options[:device_unique_id])
|
220
|
+
hsh[:bill_to] = options[:bill_to] if valid_fraud_detection_option?(options[:bill_to])
|
221
|
+
hsh[:purchase_totals] = options[:purchase_totals] if valid_fraud_detection_option?(options[:purchase_totals])
|
222
|
+
hsh[:customer_in_site] = options[:customer_in_site] if valid_fraud_detection_option?(options[:customer_in_site])
|
223
|
+
hsh[:retail_transaction_data] = options[:retail_transaction_data] if valid_fraud_detection_option?(options[:retail_transaction_data])
|
224
|
+
hsh[:ship_to] = options[:ship_to] if valid_fraud_detection_option?(options[:ship_to])
|
225
|
+
hsh[:tax_voucher_required] = options[:tax_voucher_required] if valid_fraud_detection_option?(options[:tax_voucher_required])
|
226
|
+
hsh[:copy_paste_card_data] = options[:copy_paste_card_data] if valid_fraud_detection_option?(options[:copy_paste_card_data])
|
213
227
|
end
|
214
228
|
end
|
215
229
|
|
@@ -287,15 +301,21 @@ module ActiveMerchant #:nodoc:
|
|
287
301
|
error_code = nil
|
288
302
|
if error = response.dig('status_details', 'error')
|
289
303
|
code = error.dig('reason', 'id')
|
290
|
-
|
304
|
+
standard_error_code = STANDARD_ERROR_CODE_MAPPING[code]
|
305
|
+
error_code = "#{code}, #{standard_error_code}"
|
291
306
|
error_code ||= error['type']
|
292
307
|
elsif response['error_type']
|
293
308
|
error_code = response['error_type'] if response['validation_errors']
|
294
|
-
elsif
|
309
|
+
elsif response.dig('error', 'validation_errors')
|
310
|
+
error = response.dig('error')
|
295
311
|
validation_errors = error.dig('validation_errors', 0)
|
296
312
|
code = validation_errors['code'] if validation_errors && validation_errors['code']
|
297
313
|
param = validation_errors['param'] if validation_errors && validation_errors['param']
|
298
314
|
error_code = "#{error['error_type']} | #{code} | #{param}" if error['error_type']
|
315
|
+
elsif error = response.dig('error')
|
316
|
+
code = error.dig('reason', 'id')
|
317
|
+
standard_error_code = STANDARD_ERROR_CODE_MAPPING[code]
|
318
|
+
error_code = "#{code}, #{standard_error_code}"
|
299
319
|
end
|
300
320
|
|
301
321
|
error_code || STANDARD_ERROR_CODE[:processing_error]
|
@@ -39,6 +39,7 @@ module ActiveMerchant #:nodoc:
|
|
39
39
|
|
40
40
|
def purchase(money, payment_method, options = {})
|
41
41
|
request = build_xml_request do |xml|
|
42
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
42
43
|
xml.ssl_transaction_type self.actions[:purchase]
|
43
44
|
xml.ssl_amount amount(money)
|
44
45
|
|
@@ -63,6 +64,7 @@ module ActiveMerchant #:nodoc:
|
|
63
64
|
|
64
65
|
def authorize(money, creditcard, options = {})
|
65
66
|
request = build_xml_request do |xml|
|
67
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
66
68
|
xml.ssl_transaction_type self.actions[:authorize]
|
67
69
|
xml.ssl_amount amount(money)
|
68
70
|
|
@@ -82,6 +84,8 @@ module ActiveMerchant #:nodoc:
|
|
82
84
|
|
83
85
|
def capture(money, authorization, options = {})
|
84
86
|
request = build_xml_request do |xml|
|
87
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
88
|
+
|
85
89
|
if options[:credit_card]
|
86
90
|
xml.ssl_transaction_type self.actions[:capture]
|
87
91
|
xml.ssl_amount amount(money)
|
@@ -107,6 +111,7 @@ module ActiveMerchant #:nodoc:
|
|
107
111
|
|
108
112
|
def refund(money, identification, options = {})
|
109
113
|
request = build_xml_request do |xml|
|
114
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
110
115
|
xml.ssl_transaction_type self.actions[:refund]
|
111
116
|
xml.ssl_amount amount(money)
|
112
117
|
add_txn_id(xml, identification)
|
@@ -117,6 +122,7 @@ module ActiveMerchant #:nodoc:
|
|
117
122
|
|
118
123
|
def void(identification, options = {})
|
119
124
|
request = build_xml_request do |xml|
|
125
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
120
126
|
xml.ssl_transaction_type self.actions[:void]
|
121
127
|
|
122
128
|
add_txn_id(xml, identification)
|
@@ -129,6 +135,7 @@ module ActiveMerchant #:nodoc:
|
|
129
135
|
raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' if creditcard.is_a?(String)
|
130
136
|
|
131
137
|
request = build_xml_request do |xml|
|
138
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
132
139
|
xml.ssl_transaction_type self.actions[:credit]
|
133
140
|
xml.ssl_amount amount(money)
|
134
141
|
add_invoice(xml, options)
|
@@ -143,6 +150,7 @@ module ActiveMerchant #:nodoc:
|
|
143
150
|
|
144
151
|
def verify(credit_card, options = {})
|
145
152
|
request = build_xml_request do |xml|
|
153
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
146
154
|
xml.ssl_transaction_type self.actions[:verify]
|
147
155
|
add_creditcard(xml, credit_card)
|
148
156
|
add_address(xml, options)
|
@@ -154,6 +162,7 @@ module ActiveMerchant #:nodoc:
|
|
154
162
|
|
155
163
|
def store(creditcard, options = {})
|
156
164
|
request = build_xml_request do |xml|
|
165
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
157
166
|
xml.ssl_transaction_type self.actions[:store]
|
158
167
|
xml.ssl_add_token 'Y'
|
159
168
|
add_creditcard(xml, creditcard)
|
@@ -167,6 +176,7 @@ module ActiveMerchant #:nodoc:
|
|
167
176
|
|
168
177
|
def update(token, creditcard, options = {})
|
169
178
|
request = build_xml_request do |xml|
|
179
|
+
xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
|
170
180
|
xml.ssl_transaction_type self.actions[:update]
|
171
181
|
add_token(xml, token)
|
172
182
|
add_creditcard(xml, creditcard)
|
@@ -285,10 +295,12 @@ module ActiveMerchant #:nodoc:
|
|
285
295
|
|
286
296
|
def add_auth_purchase_params(xml, options)
|
287
297
|
xml.ssl_dynamic_dba options[:dba] if options.has_key?(:dba)
|
288
|
-
xml.ssl_merchant_initiated_unscheduled options
|
298
|
+
xml.ssl_merchant_initiated_unscheduled merchant_initiated_unscheduled(options) if merchant_initiated_unscheduled(options)
|
289
299
|
xml.ssl_customer_code options[:customer] if options.has_key?(:customer)
|
290
300
|
xml.ssl_customer_number options[:customer_number] if options.has_key?(:customer_number)
|
301
|
+
xml.ssl_entry_mode entry_mode(options) if entry_mode(options)
|
291
302
|
add_custom_fields(xml, options) if options[:custom_fields]
|
303
|
+
add_stored_credential(xml, options) if options[:stored_credential]
|
292
304
|
end
|
293
305
|
|
294
306
|
def add_custom_fields(xml, options)
|
@@ -337,6 +349,32 @@ module ActiveMerchant #:nodoc:
|
|
337
349
|
}
|
338
350
|
end
|
339
351
|
|
352
|
+
def add_stored_credential(xml, options)
|
353
|
+
network_transaction_id = options.dig(:stored_credential, :network_transaction_id)
|
354
|
+
case
|
355
|
+
when network_transaction_id.nil?
|
356
|
+
return
|
357
|
+
when network_transaction_id.to_s.include?('|')
|
358
|
+
oar_data, ps2000_data = options[:stored_credential][:network_transaction_id].split('|')
|
359
|
+
xml.ssl_oar_data oar_data unless oar_data.nil? || oar_data.empty?
|
360
|
+
xml.ssl_ps2000_data ps2000_data unless ps2000_data.nil? || ps2000_data.empty?
|
361
|
+
when network_transaction_id.to_s.length > 22
|
362
|
+
xml.ssl_oar_data options.dig(:stored_credential, :network_transaction_id)
|
363
|
+
else
|
364
|
+
xml.ssl_ps2000_data options.dig(:stored_credential, :network_transaction_id)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def merchant_initiated_unscheduled(options)
|
369
|
+
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'
|
371
|
+
end
|
372
|
+
|
373
|
+
def entry_mode(options)
|
374
|
+
return options[:entry_mode] if options[:entry_mode]
|
375
|
+
return 12 if options[:stored_credential]
|
376
|
+
end
|
377
|
+
|
340
378
|
def build_xml_request
|
341
379
|
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
342
380
|
xml.txn do
|
@@ -352,6 +390,7 @@ module ActiveMerchant #:nodoc:
|
|
352
390
|
|
353
391
|
def commit(request)
|
354
392
|
request = "xmldata=#{request}".delete('&')
|
393
|
+
|
355
394
|
response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers))
|
356
395
|
|
357
396
|
Response.new(
|
@@ -362,10 +401,15 @@ module ActiveMerchant #:nodoc:
|
|
362
401
|
authorization: authorization_from(response),
|
363
402
|
error_code: response[:errorCode],
|
364
403
|
avs_result: { code: response[:avs_response] },
|
365
|
-
cvv_result: response[:cvv2_response]
|
404
|
+
cvv_result: response[:cvv2_response],
|
405
|
+
network_transaction_id: build_network_transaction_id(response)
|
366
406
|
)
|
367
407
|
end
|
368
408
|
|
409
|
+
def build_network_transaction_id(response)
|
410
|
+
"#{response[:oar_data]}|#{response[:ps2000_data]}"
|
411
|
+
end
|
412
|
+
|
369
413
|
def headers
|
370
414
|
{
|
371
415
|
'Accept' => 'application/xml',
|
@@ -383,6 +427,14 @@ module ActiveMerchant #:nodoc:
|
|
383
427
|
def authorization_from(response)
|
384
428
|
[response[:approval_code], response[:txn_id]].join(';')
|
385
429
|
end
|
430
|
+
|
431
|
+
def truncate(value, size)
|
432
|
+
return nil unless value
|
433
|
+
|
434
|
+
difference = value.force_encoding('iso-8859-1').length - value.length
|
435
|
+
|
436
|
+
return value.delete('&"<>').to_s[0, (size - difference)]
|
437
|
+
end
|
386
438
|
end
|
387
439
|
end
|
388
440
|
end
|
@@ -53,6 +53,7 @@ module ActiveMerchant #:nodoc:
|
|
53
53
|
add_invoice(params, amount, options)
|
54
54
|
add_customer_data(params, options, payment_method)
|
55
55
|
add_credit_card(params, payment_method, options)
|
56
|
+
add_3ds_authenticated_data(params, options) if options[:three_d_secure]
|
56
57
|
params['Method'] = payment_method.respond_to?(:number) ? 'ProcessPayment' : 'TokenPayment'
|
57
58
|
commit(url_for('Transaction'), params)
|
58
59
|
end
|
@@ -197,6 +198,18 @@ module ActiveMerchant #:nodoc:
|
|
197
198
|
params
|
198
199
|
end
|
199
200
|
|
201
|
+
def add_3ds_authenticated_data(params, options)
|
202
|
+
three_d_secure_options = options[:three_d_secure]
|
203
|
+
params['PaymentInstrument'] ||= {} if params['PaymentInstrument'].nil?
|
204
|
+
threed_secure_auth = params['PaymentInstrument']['ThreeDSecureAuth'] = {}
|
205
|
+
threed_secure_auth['Cryptogram'] = three_d_secure_options[:cavv]
|
206
|
+
threed_secure_auth['ECI'] = three_d_secure_options[:eci]
|
207
|
+
threed_secure_auth['XID'] = three_d_secure_options[:xid]
|
208
|
+
threed_secure_auth['AuthStatus'] = three_d_secure_options[:authentication_response_status]
|
209
|
+
threed_secure_auth['dsTransactionId'] = three_d_secure_options[:ds_transaction_id]
|
210
|
+
threed_secure_auth['Version'] = three_d_secure_options[:version]
|
211
|
+
end
|
212
|
+
|
200
213
|
def add_invoice(params, money, options, key = 'Payment')
|
201
214
|
currency_code = options[:currency] || currency(money)
|
202
215
|
params[key] = {
|
@@ -212,8 +212,8 @@ module ActiveMerchant #:nodoc:
|
|
212
212
|
xml.tag! 'Expiry_Date', expdate(credit_card)
|
213
213
|
xml.tag! 'CardHoldersName', credit_card.name
|
214
214
|
xml.tag! 'CardType', card_type(credit_card.brand)
|
215
|
-
xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id]
|
216
215
|
|
216
|
+
add_wallet_provider_id(xml, credit_card, options)
|
217
217
|
add_credit_card_eci(xml, credit_card, options)
|
218
218
|
add_credit_card_verification_strings(xml, credit_card, options)
|
219
219
|
end
|
@@ -221,10 +221,9 @@ module ActiveMerchant #:nodoc:
|
|
221
221
|
|
222
222
|
def add_credit_card_eci(xml, credit_card, options)
|
223
223
|
eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == 'discover'
|
224
|
-
#
|
225
|
-
#
|
226
|
-
|
227
|
-
'04'
|
224
|
+
# Payeezy requires an ECI of 5 for apple pay transactions
|
225
|
+
# See: https://support.payeezy.com/hc/en-us/articles/203730589-Ecommerce-Flag-Values
|
226
|
+
'05'
|
228
227
|
else
|
229
228
|
(credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI
|
230
229
|
end
|
@@ -276,10 +275,22 @@ module ActiveMerchant #:nodoc:
|
|
276
275
|
xml.tag! 'Expiry_Date', expdate(credit_card)
|
277
276
|
xml.tag! 'CardHoldersName', credit_card.name
|
278
277
|
xml.tag! 'CardType', card_type(credit_card.brand)
|
279
|
-
|
278
|
+
|
279
|
+
add_wallet_provider_id(xml, credit_card, options)
|
280
280
|
add_card_authentication_data(xml, options)
|
281
281
|
end
|
282
282
|
|
283
|
+
def add_wallet_provider_id(xml, credit_card, options)
|
284
|
+
provider_id = if options[:wallet_provider_id]
|
285
|
+
options[:wallet_provider_id]
|
286
|
+
elsif credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay
|
287
|
+
# See: https://support.payeezy.com/hc/en-us/articles/206601408-First-Data-Payeezy-Gateway-Web-Service-API-Reference-Guide#3.9
|
288
|
+
4
|
289
|
+
end
|
290
|
+
|
291
|
+
xml.tag! 'WalletProviderID', provider_id if provider_id
|
292
|
+
end
|
293
|
+
|
283
294
|
def add_customer_data(xml, options)
|
284
295
|
xml.tag! 'Customer_Ref', options[:customer] if options[:customer]
|
285
296
|
xml.tag! 'Client_IP', options[:ip] if options[:ip]
|
@@ -28,6 +28,7 @@ module ActiveMerchant #:nodoc:
|
|
28
28
|
add_payment_method(post, payment_method, options)
|
29
29
|
add_billing_address(post, payment_method, options)
|
30
30
|
add_shipping_address(post, options)
|
31
|
+
add_xdata(post, options)
|
31
32
|
post[:action] = 'sale'
|
32
33
|
|
33
34
|
commit(:post, post)
|
@@ -41,6 +42,7 @@ module ActiveMerchant #:nodoc:
|
|
41
42
|
add_payment_method(post, payment_method, options)
|
42
43
|
add_billing_address(post, payment_method, options)
|
43
44
|
add_shipping_address(post, options)
|
45
|
+
add_xdata(post, options)
|
44
46
|
post[:action] = 'authorize'
|
45
47
|
|
46
48
|
commit(:post, post)
|
@@ -122,6 +124,16 @@ module ActiveMerchant #:nodoc:
|
|
122
124
|
post[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
|
123
125
|
end
|
124
126
|
|
127
|
+
def add_xdata(post, options)
|
128
|
+
post[:xdata] = {}
|
129
|
+
if xdata = options[:xdata]
|
130
|
+
(1..9).each do |n|
|
131
|
+
field = "xdata_#{n}".to_sym
|
132
|
+
post[:xdata][field] = xdata[field] if xdata[field]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
125
137
|
def add_billing_address(post, payment, options)
|
126
138
|
post[:billing_address] = {}
|
127
139
|
if address = options[:billing_address] || options[:address]
|
@@ -32,6 +32,7 @@ module ActiveMerchant #:nodoc:
|
|
32
32
|
add_address(post, payment, options)
|
33
33
|
add_creator_info(post, options)
|
34
34
|
add_fraud_fields(post, options)
|
35
|
+
add_external_cardholder_authentication_data(post, options)
|
35
36
|
commit(:authorize, post)
|
36
37
|
end
|
37
38
|
|
@@ -200,21 +201,21 @@ module ActiveMerchant #:nodoc:
|
|
200
201
|
shipping_address = options[:shipping_address]
|
201
202
|
if billing_address = options[:billing_address] || options[:address]
|
202
203
|
post['order']['customer']['billingAddress'] = {
|
203
|
-
'street' => billing_address[:address1],
|
204
|
-
'additionalInfo' => billing_address[:address2],
|
204
|
+
'street' => truncate(billing_address[:address1], 50),
|
205
|
+
'additionalInfo' => truncate(billing_address[:address2], 50),
|
205
206
|
'zip' => billing_address[:zip],
|
206
207
|
'city' => billing_address[:city],
|
207
|
-
'state' => billing_address[:state],
|
208
|
+
'state' => truncate(billing_address[:state], 35),
|
208
209
|
'countryCode' => billing_address[:country]
|
209
210
|
}
|
210
211
|
end
|
211
212
|
if shipping_address
|
212
213
|
post['order']['customer']['shippingAddress'] = {
|
213
|
-
'street' => shipping_address[:address1],
|
214
|
-
'additionalInfo' => shipping_address[:address2],
|
214
|
+
'street' => truncate(shipping_address[:address1], 50),
|
215
|
+
'additionalInfo' => truncate(shipping_address[:address2], 50),
|
215
216
|
'zip' => shipping_address[:zip],
|
216
217
|
'city' => shipping_address[:city],
|
217
|
-
'state' => shipping_address[:state],
|
218
|
+
'state' => truncate(shipping_address[:state], 35),
|
218
219
|
'countryCode' => shipping_address[:country]
|
219
220
|
}
|
220
221
|
post['order']['customer']['shippingAddress']['name'] = {
|
@@ -232,6 +233,24 @@ module ActiveMerchant #:nodoc:
|
|
232
233
|
post['fraudFields'] = fraud_fields unless fraud_fields.empty?
|
233
234
|
end
|
234
235
|
|
236
|
+
def add_external_cardholder_authentication_data(post, options)
|
237
|
+
return unless threeds_2_options = options[:three_d_secure]
|
238
|
+
|
239
|
+
authentication_data = {}
|
240
|
+
authentication_data[:acsTransactionId] = threeds_2_options[:acs_transaction_id] if threeds_2_options[:acs_transaction_id]
|
241
|
+
authentication_data[:cavv] = threeds_2_options[:cavv] if threeds_2_options[:cavv]
|
242
|
+
authentication_data[:cavvAlgorithm] = threeds_2_options[:cavv_algorithm] if threeds_2_options[:cavv_algorithm]
|
243
|
+
authentication_data[:directoryServerTransactionId] = threeds_2_options[:ds_transaction_id] if threeds_2_options[:ds_transaction_id]
|
244
|
+
authentication_data[:eci] = threeds_2_options[:eci] if threeds_2_options[:eci]
|
245
|
+
authentication_data[:threeDSecureVersion] = threeds_2_options[:version] if threeds_2_options[:version]
|
246
|
+
authentication_data[:validationResult] = threeds_2_options[:authentication_response_status] if threeds_2_options[:authentication_response_status]
|
247
|
+
authentication_data[:xid] = threeds_2_options[:xid] if threeds_2_options[:xid]
|
248
|
+
|
249
|
+
post['cardPaymentMethodSpecificInput'] ||= {}
|
250
|
+
post['cardPaymentMethodSpecificInput']['threeDSecure'] ||= {}
|
251
|
+
post['cardPaymentMethodSpecificInput']['threeDSecure']['externalCardholderAuthenticationData'] = authentication_data unless authentication_data.empty?
|
252
|
+
end
|
253
|
+
|
235
254
|
def add_number_of_installments(post, options)
|
236
255
|
post['order']['additionalInput']['numberOfInstallments'] = options[:number_of_installments] if options[:number_of_installments]
|
237
256
|
end
|
@@ -39,6 +39,7 @@ module ActiveMerchant #:nodoc:
|
|
39
39
|
add_descriptor_name(xml, options)
|
40
40
|
add_card_or_token_payment(xml, card_or_token, options)
|
41
41
|
add_three_d_secure(xml, card_or_token, options)
|
42
|
+
add_stored_credentials(xml, options)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
@@ -52,6 +53,8 @@ module ActiveMerchant #:nodoc:
|
|
52
53
|
def purchase(money, payment_method, options = {})
|
53
54
|
if payment_method.is_a?(Check)
|
54
55
|
commit_check_sale(money, payment_method, options)
|
56
|
+
elsif options.dig(:stored_credential, :reason_type) == 'recurring'
|
57
|
+
commit_recurring_billing_sale(money, payment_method, options)
|
55
58
|
else
|
56
59
|
commit_credit_sale(money, payment_method, options)
|
57
60
|
end
|
@@ -67,6 +70,15 @@ module ActiveMerchant #:nodoc:
|
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
73
|
+
def credit(money, payment_method, options = {})
|
74
|
+
commit('CreditReturn') do |xml|
|
75
|
+
add_amount(xml, money)
|
76
|
+
add_allow_dup(xml)
|
77
|
+
add_card_or_token_payment(xml, payment_method, options)
|
78
|
+
add_details(xml, options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
70
82
|
def verify(card_or_token, options = {})
|
71
83
|
commit('CreditAccountVerify') do |xml|
|
72
84
|
add_card_or_token_customer_data(xml, card_or_token, options)
|
@@ -122,6 +134,21 @@ module ActiveMerchant #:nodoc:
|
|
122
134
|
add_descriptor_name(xml, options)
|
123
135
|
add_card_or_token_payment(xml, card_or_token, options)
|
124
136
|
add_three_d_secure(xml, card_or_token, options)
|
137
|
+
add_stored_credentials(xml, options)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def commit_recurring_billing_sale(money, card_or_token, options)
|
142
|
+
commit('RecurringBilling') do |xml|
|
143
|
+
add_amount(xml, money)
|
144
|
+
add_allow_dup(xml)
|
145
|
+
add_card_or_token_customer_data(xml, card_or_token, options)
|
146
|
+
add_details(xml, options)
|
147
|
+
add_descriptor_name(xml, options)
|
148
|
+
add_card_or_token_payment(xml, card_or_token, options)
|
149
|
+
add_three_d_secure(xml, card_or_token, options)
|
150
|
+
add_stored_credentials(xml, options)
|
151
|
+
add_stored_credentials_for_recurring_billing(xml, options)
|
125
152
|
end
|
126
153
|
end
|
127
154
|
|
@@ -148,7 +175,7 @@ module ActiveMerchant #:nodoc:
|
|
148
175
|
xml.hps :CardHolderAddr, billing_address[:address1] if billing_address[:address1]
|
149
176
|
xml.hps :CardHolderCity, billing_address[:city] if billing_address[:city]
|
150
177
|
xml.hps :CardHolderState, billing_address[:state] if billing_address[:state]
|
151
|
-
xml.hps :CardHolderZip, billing_address[:zip] if billing_address[:zip]
|
178
|
+
xml.hps :CardHolderZip, alphanumeric_zip(billing_address[:zip]) if billing_address[:zip]
|
152
179
|
end
|
153
180
|
end
|
154
181
|
end
|
@@ -210,7 +237,7 @@ module ActiveMerchant #:nodoc:
|
|
210
237
|
def add_details(xml, options)
|
211
238
|
xml.hps :AdditionalTxnFields do
|
212
239
|
xml.hps :Description, options[:description] if options[:description]
|
213
|
-
xml.hps :InvoiceNbr, options[:order_id] if options[:order_id]
|
240
|
+
xml.hps :InvoiceNbr, options[:order_id][0..59] if options[:order_id]
|
214
241
|
xml.hps :CustomerID, options[:customer_id] if options[:customer_id]
|
215
242
|
end
|
216
243
|
end
|
@@ -256,6 +283,38 @@ module ActiveMerchant #:nodoc:
|
|
256
283
|
end
|
257
284
|
end
|
258
285
|
|
286
|
+
# We do not currently support installments on this gateway.
|
287
|
+
# The HPS gateway treats recurring transactions as a seperate transaction type
|
288
|
+
def add_stored_credentials(xml, options)
|
289
|
+
return unless options[:stored_credential]
|
290
|
+
|
291
|
+
xml.hps :CardOnFileData do
|
292
|
+
if options[:stored_credential][:initiator] == 'customer'
|
293
|
+
xml.hps :CardOnFile, 'C'
|
294
|
+
elsif options[:stored_credential][:initiator] == 'merchant'
|
295
|
+
xml.hps :CardOnFile, 'M'
|
296
|
+
else
|
297
|
+
return
|
298
|
+
end
|
299
|
+
|
300
|
+
if options[:stored_credential][:network_transaction_id]
|
301
|
+
xml.hps :CardBrandTxnId, options[:stored_credential][:network_transaction_id]
|
302
|
+
else
|
303
|
+
return
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def add_stored_credentials_for_recurring_billing(xml, options)
|
309
|
+
xml.hps :RecurringData do
|
310
|
+
if options[:stored_credential][:reason_type] = 'recurring'
|
311
|
+
xml.hps :OneTime, 'N'
|
312
|
+
else
|
313
|
+
xml.hps :OneTime, 'Y'
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
259
318
|
def strip_leading_zero(value)
|
260
319
|
return value unless value[0] == '0'
|
261
320
|
|
@@ -380,6 +439,10 @@ module ActiveMerchant #:nodoc:
|
|
380
439
|
@options[:secret_api_key]&.include?('_cert_')
|
381
440
|
end
|
382
441
|
|
442
|
+
def alphanumeric_zip(zip)
|
443
|
+
zip.gsub(/[^0-9a-z]/i, '')
|
444
|
+
end
|
445
|
+
|
383
446
|
ISSUER_MESSAGES = {
|
384
447
|
'13' => 'Must be greater than or equal 0.',
|
385
448
|
'14' => 'The card number is incorrect.',
|