activemerchant 1.91.0 → 1.92.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 +24 -0
- data/lib/active_merchant/billing/credit_card.rb +2 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +13 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +52 -18
- data/lib/active_merchant/billing/gateways/bambora_apac.rb +54 -14
- data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +12 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +32 -2
- data/lib/active_merchant/billing/gateways/d_local.rb +2 -2
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
- data/lib/active_merchant/billing/gateways/litle.rb +61 -3
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
- data/lib/active_merchant/billing/gateways/mundipagg.rb +2 -2
- data/lib/active_merchant/billing/gateways/orbital.rb +27 -3
- data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
- data/lib/active_merchant/billing/gateways/paymentez.rb +3 -2
- data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
- data/lib/active_merchant/billing/gateways/realex.rb +15 -1
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
- data/lib/active_merchant/billing/gateways/worldpay.rb +13 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7269c204ea4aba074e22b8d23828116e472e5537bee163e0e60159192609cc27
|
|
4
|
+
data.tar.gz: 4b42091ca8a875d56f2bd1cc53d8440e63733930143ee662d9ca5ef87ff3cd00
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a4cf32bc3055e7f8f6663a024f26424a498ec66f746a703f504723275f969f67fbfbd1cb4b7824245deef9dc7769dd94451a0d7a182491a19439a9df258f624
|
|
7
|
+
data.tar.gz: 847b1508be32ccd72185dc2e6d58075e4e6fecf693e069a068ab34dee1c8fd848e6dc760bf44708a9e4d97ca00fbcec9955b6612311555194d3bb5ee9e6351a2
|
data/CHANGELOG
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
== HEAD
|
|
4
4
|
|
|
5
|
+
== Version 1.91.0 (April 8, 2019)
|
|
6
|
+
* BluePay: Send customer IP address when provided [jknipp] #3149
|
|
7
|
+
* PaymentExpress: Use ip field for client_info field [jknipp] #3150
|
|
8
|
+
* Bambora Asia-Pacific: Adds Store [molbrown] #3147
|
|
9
|
+
* Orbital: Pass normalized stored credential fields [curiousepic] #3148
|
|
10
|
+
* Adds Elo card type in general and specifically to Adyen [deedeelavinder] #3153
|
|
11
|
+
* Mercado Pago: Adds Elo card type [deedeelavinder] #3156
|
|
12
|
+
* Litle: Add support for stored credentials [bayprogrammer] #3155
|
|
13
|
+
* Adyen: Correctly process risk_data option [bayprogrammer] #3161
|
|
14
|
+
* Paymentez: Adds Elo card type [deedeelavinder] #3162
|
|
15
|
+
* WorldPay: Adds Elo card type [deedeelavinder] #3163
|
|
16
|
+
* Adyen: Idempotency for non-purchase requests [molbrown] #3164
|
|
17
|
+
* FirstData e4 v27: Support v28 url and stored creds [curiousepic] #3165
|
|
18
|
+
* WorldPay: Fix element order for 3DS + stored cred [bayprogrammer] #3172
|
|
19
|
+
* Braintree: Add risk data to returned response [jknipp] #3169
|
|
20
|
+
* Adyen: Support idempotency on purchase [molbrown] #3168
|
|
21
|
+
* Adyen: Pass phone, statement, device_fingerprint [curiousepic] #3178
|
|
22
|
+
* Adyen: Fix adding phone from billing address [curiousepic] #3179
|
|
23
|
+
* Fix partial or missing address exceptions [molbrown] #3180
|
|
24
|
+
* Adyen: Update to support normalized stored credential fields [molbrown] #3182
|
|
25
|
+
* VisaNet Peru: Always include DSC_COD_ACCION [bayprogrammer] #3174
|
|
26
|
+
* Adyen: Support adjust action [curiousepic] #3190
|
|
27
|
+
* CyberSource: Add support for stored credentials [therufs] #3185
|
|
28
|
+
|
|
5
29
|
== Version 1.91.0 (February 22, 2019)
|
|
6
30
|
* WorldPay: Pull CVC and AVS Result from Response [nfarve] #3106
|
|
7
31
|
* Worldpay: Add AVS and CVC Mapping [nfarve] #3107
|
|
@@ -18,6 +18,7 @@ module ActiveMerchant #:nodoc:
|
|
|
18
18
|
# * Dankort
|
|
19
19
|
# * Maestro
|
|
20
20
|
# * Forbrugsforeningen
|
|
21
|
+
# * Elo
|
|
21
22
|
#
|
|
22
23
|
# For testing purposes, use the 'bogus' credit card brand. This skips the vast majority of
|
|
23
24
|
# validations, allowing you to focus on your core concerns until you're ready to be more concerned
|
|
@@ -88,6 +89,7 @@ module ActiveMerchant #:nodoc:
|
|
|
88
89
|
# * +'dankort'+
|
|
89
90
|
# * +'maestro'+
|
|
90
91
|
# * +'forbrugsforeningen'+
|
|
92
|
+
# * +'elo'+
|
|
91
93
|
#
|
|
92
94
|
# Or, if you wish to test your implementation, +'bogus'+.
|
|
93
95
|
#
|
|
@@ -5,6 +5,7 @@ module ActiveMerchant #:nodoc:
|
|
|
5
5
|
CARD_COMPANY_DETECTORS = {
|
|
6
6
|
'visa' => ->(num) { num =~ /^4\d{12}(\d{3})?(\d{3})?$/ },
|
|
7
7
|
'master' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), MASTERCARD_RANGES) },
|
|
8
|
+
'elo' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), ELO_RANGES) },
|
|
8
9
|
'discover' => ->(num) { num =~ /^(6011|65\d{2}|64[4-9]\d)\d{12,15}|(62\d{14,17})$/ },
|
|
9
10
|
'american_express' => ->(num) { num =~ /^3[47]\d{13}$/ },
|
|
10
11
|
'diners_club' => ->(num) { num =~ /^3(0[0-5]|[68]\d)\d{11}$/ },
|
|
@@ -66,6 +67,18 @@ module ActiveMerchant #:nodoc:
|
|
|
66
67
|
(670000..679999),
|
|
67
68
|
]
|
|
68
69
|
|
|
70
|
+
# https://dev.elo.com.br/apis/tabela-de-bins, download csv from left sidebar
|
|
71
|
+
ELO_RANGES = [
|
|
72
|
+
506707..506708, 506715..506715, 506718..506722, 506724..506724, 506726..506736, 506739..506739, 506741..506743,
|
|
73
|
+
506745..506747, 506753..506753, 506774..506776, 506778..506778, 509000..509001, 509003..509003, 509007..509007,
|
|
74
|
+
509020..509022, 509035..509035, 509039..509042, 509045..509045, 509048..509048, 509051..509071, 509073..509074,
|
|
75
|
+
509077..509080, 509084..509084, 509091..509094, 509098..509098, 509100..509100, 509104..509104, 509106..509109,
|
|
76
|
+
627780..627780, 636368..636368, 650031..650033, 650035..650045, 650047..650047, 650406..650410, 650434..650436,
|
|
77
|
+
650439..650439, 650485..650504, 650506..650530, 650577..650580, 650582..650591, 650721..650727, 650901..650922,
|
|
78
|
+
650928..650928, 650938..650939, 650946..650948, 650954..650955, 650962..650963, 650967..650967, 650971..650971,
|
|
79
|
+
651652..651667, 651675..651678, 655000..655010, 655012..655015, 655051..655052, 655056..655057
|
|
80
|
+
]
|
|
81
|
+
|
|
69
82
|
def self.included(base)
|
|
70
83
|
base.extend(ClassMethods)
|
|
71
84
|
end
|
|
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
|
|
|
9
9
|
|
|
10
10
|
self.supported_countries = ['AT', 'AU', 'BE', 'BG', 'BR', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GI', 'GR', 'HK', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'MX', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SG', 'SK', 'SI', 'US']
|
|
11
11
|
self.default_currency = 'USD'
|
|
12
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover]
|
|
12
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover, :elo]
|
|
13
13
|
|
|
14
14
|
self.money_format = :cents
|
|
15
15
|
|
|
@@ -38,7 +38,7 @@ module ActiveMerchant #:nodoc:
|
|
|
38
38
|
else
|
|
39
39
|
MultiResponse.run do |r|
|
|
40
40
|
r.process { authorize(money, payment, options) }
|
|
41
|
-
r.process { capture(money, r.authorization, options) }
|
|
41
|
+
r.process { capture(money, r.authorization, capture_options(options)) }
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -49,31 +49,38 @@ module ActiveMerchant #:nodoc:
|
|
|
49
49
|
add_invoice(post, money, options)
|
|
50
50
|
add_payment(post, payment)
|
|
51
51
|
add_extra_data(post, payment, options)
|
|
52
|
-
|
|
52
|
+
add_stored_credentials(post, payment, options)
|
|
53
53
|
add_address(post, options)
|
|
54
54
|
add_installments(post, options) if options[:installments]
|
|
55
55
|
add_3ds(post, options)
|
|
56
|
-
commit('authorise', post)
|
|
56
|
+
commit('authorise', post, options)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def capture(money, authorization, options={})
|
|
60
60
|
post = init_post(options)
|
|
61
61
|
add_invoice_for_modification(post, money, options)
|
|
62
62
|
add_reference(post, authorization, options)
|
|
63
|
-
commit('capture', post)
|
|
63
|
+
commit('capture', post, options)
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def refund(money, authorization, options={})
|
|
67
67
|
post = init_post(options)
|
|
68
68
|
add_invoice_for_modification(post, money, options)
|
|
69
69
|
add_original_reference(post, authorization, options)
|
|
70
|
-
commit('refund', post)
|
|
70
|
+
commit('refund', post, options)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def void(authorization, options={})
|
|
74
74
|
post = init_post(options)
|
|
75
75
|
add_reference(post, authorization, options)
|
|
76
|
-
commit('cancel', post)
|
|
76
|
+
commit('cancel', post, options)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def adjust(money, authorization, options={})
|
|
80
|
+
post = init_post(options)
|
|
81
|
+
add_invoice_for_modification(post, money, options)
|
|
82
|
+
add_reference(post, authorization, options)
|
|
83
|
+
commit('adjustAuthorisation', post, options)
|
|
77
84
|
end
|
|
78
85
|
|
|
79
86
|
def store(credit_card, options={})
|
|
@@ -82,14 +89,16 @@ module ActiveMerchant #:nodoc:
|
|
|
82
89
|
add_invoice(post, 0, options)
|
|
83
90
|
add_payment(post, credit_card)
|
|
84
91
|
add_extra_data(post, credit_card, options)
|
|
92
|
+
add_stored_credentials(post, credit_card, options)
|
|
85
93
|
add_recurring_contract(post, options)
|
|
86
94
|
add_address(post, options)
|
|
87
|
-
commit('authorise', post)
|
|
95
|
+
commit('authorise', post, options)
|
|
88
96
|
end
|
|
89
97
|
|
|
90
98
|
def verify(credit_card, options={})
|
|
91
99
|
MultiResponse.run(:use_first_response) do |r|
|
|
92
100
|
r.process { authorize(0, credit_card, options) }
|
|
101
|
+
options[:idempotency_key] = nil
|
|
93
102
|
r.process(:ignore_result) { void(r.authorization, options) }
|
|
94
103
|
end
|
|
95
104
|
end
|
|
@@ -151,9 +160,11 @@ module ActiveMerchant #:nodoc:
|
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
def add_extra_data(post, payment, options)
|
|
163
|
+
post[:telephoneNumber] = options[:billing_address][:phone] if options.dig(:billing_address, :phone)
|
|
154
164
|
post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
|
|
155
165
|
post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip]
|
|
156
166
|
post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference]
|
|
167
|
+
post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
|
|
157
168
|
post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
|
|
158
169
|
post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
|
|
159
170
|
post[:selectedBrand] ||= NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
|
|
@@ -163,18 +174,24 @@ module ActiveMerchant #:nodoc:
|
|
|
163
174
|
post[:additionalData][:overwriteBrand] = normalize(options[:overwrite_brand]) if options[:overwrite_brand]
|
|
164
175
|
post[:additionalData][:customRoutingFlag] = options[:custom_routing_flag] if options[:custom_routing_flag]
|
|
165
176
|
post[:additionalData]['paymentdatasource.type'] = NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
|
|
177
|
+
post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
|
|
166
178
|
add_risk_data(post, options)
|
|
167
179
|
end
|
|
168
180
|
|
|
169
181
|
def add_risk_data(post, options)
|
|
170
|
-
risk_data =
|
|
171
|
-
|
|
182
|
+
if (risk_data = options[:risk_data])
|
|
183
|
+
risk_data = Hash[risk_data.map { |k, v| ["riskdata.#{k}", v] }]
|
|
184
|
+
post[:additionalData].merge!(risk_data)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
172
187
|
|
|
173
|
-
|
|
188
|
+
def add_stored_credentials(post, payment, options)
|
|
189
|
+
add_shopper_interaction(post, payment, options)
|
|
190
|
+
add_recurring_processing_model(post, options)
|
|
174
191
|
end
|
|
175
192
|
|
|
176
193
|
def add_shopper_interaction(post, payment, options={})
|
|
177
|
-
if (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard)
|
|
194
|
+
if options.dig(:stored_credential, :initial_transaction) || (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard)
|
|
178
195
|
shopper_interaction = 'Ecommerce'
|
|
179
196
|
else
|
|
180
197
|
shopper_interaction = 'ContAuth'
|
|
@@ -183,6 +200,17 @@ module ActiveMerchant #:nodoc:
|
|
|
183
200
|
post[:shopperInteraction] = options[:shopper_interaction] || shopper_interaction
|
|
184
201
|
end
|
|
185
202
|
|
|
203
|
+
def add_recurring_processing_model(post, options)
|
|
204
|
+
return unless options.dig(:stored_credential, :reason_type) || options[:recurring_processing_model]
|
|
205
|
+
if options.dig(:stored_credential, :reason_type) && options[:stored_credential][:reason_type] == 'unscheduled'
|
|
206
|
+
recurring_processing_model = 'CardOnFile'
|
|
207
|
+
else
|
|
208
|
+
recurring_processing_model = 'Subscription'
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
post[:recurringProcessingModel] = options[:recurring_processing_model] || recurring_processing_model
|
|
212
|
+
end
|
|
213
|
+
|
|
186
214
|
def add_address(post, options)
|
|
187
215
|
return unless post[:card]&.kind_of?(Hash)
|
|
188
216
|
if (address = options[:billing_address] || options[:address]) && address[:country]
|
|
@@ -202,7 +230,6 @@ module ActiveMerchant #:nodoc:
|
|
|
202
230
|
currency: options[:currency] || currency(money)
|
|
203
231
|
}
|
|
204
232
|
post[:amount] = amount
|
|
205
|
-
post[:recurringProcessingModel] = options[:recurring_processing_model] if options[:recurring_processing_model]
|
|
206
233
|
end
|
|
207
234
|
|
|
208
235
|
def add_invoice_for_modification(post, money, options)
|
|
@@ -239,6 +266,11 @@ module ActiveMerchant #:nodoc:
|
|
|
239
266
|
post[:card] = card
|
|
240
267
|
end
|
|
241
268
|
|
|
269
|
+
def capture_options(options)
|
|
270
|
+
return options.merge(idempotency_key: "#{options[:idempotency_key]}-cap") if options[:idempotency_key]
|
|
271
|
+
options
|
|
272
|
+
end
|
|
273
|
+
|
|
242
274
|
def add_reference(post, authorization, options = {})
|
|
243
275
|
_, psp_reference, _ = authorization.split('#')
|
|
244
276
|
post[:originalReference] = single_reference(authorization) || psp_reference
|
|
@@ -286,9 +318,9 @@ module ActiveMerchant #:nodoc:
|
|
|
286
318
|
JSON.parse(body)
|
|
287
319
|
end
|
|
288
320
|
|
|
289
|
-
def commit(action, parameters)
|
|
321
|
+
def commit(action, parameters, options)
|
|
290
322
|
begin
|
|
291
|
-
raw_response = ssl_post("#{url}/#{action}", post_data(action, parameters), request_headers)
|
|
323
|
+
raw_response = ssl_post("#{url}/#{action}", post_data(action, parameters), request_headers(options))
|
|
292
324
|
response = parse(raw_response)
|
|
293
325
|
rescue ResponseError => e
|
|
294
326
|
raw_response = e.response.body
|
|
@@ -329,18 +361,20 @@ module ActiveMerchant #:nodoc:
|
|
|
329
361
|
Base64.strict_encode64("#{@username}:#{@password}")
|
|
330
362
|
end
|
|
331
363
|
|
|
332
|
-
def request_headers
|
|
333
|
-
{
|
|
364
|
+
def request_headers(options)
|
|
365
|
+
headers = {
|
|
334
366
|
'Content-Type' => 'application/json',
|
|
335
367
|
'Authorization' => "Basic #{basic_auth}"
|
|
336
368
|
}
|
|
369
|
+
headers['Idempotency-Key'] = options[:idempotency_key] if options[:idempotency_key]
|
|
370
|
+
headers
|
|
337
371
|
end
|
|
338
372
|
|
|
339
373
|
def success_from(action, response)
|
|
340
374
|
case action.to_s
|
|
341
375
|
when 'authorise', 'authorise3d'
|
|
342
376
|
['Authorised', 'Received', 'RedirectShopper'].include?(response['resultCode'])
|
|
343
|
-
when 'capture', 'refund', 'cancel'
|
|
377
|
+
when 'capture', 'refund', 'cancel', 'adjustAuthorisation'
|
|
344
378
|
response['response'] == "[#{action}-received]"
|
|
345
379
|
else
|
|
346
380
|
false
|
|
@@ -3,8 +3,8 @@ require 'nokogiri'
|
|
|
3
3
|
module ActiveMerchant #:nodoc:
|
|
4
4
|
module Billing #:nodoc:
|
|
5
5
|
class BamboraApacGateway < Gateway
|
|
6
|
-
self.live_url = 'https://www.bambora.co.nz/interface/api
|
|
7
|
-
self.test_url = 'https://demo.bambora.co.nz/interface/api
|
|
6
|
+
self.live_url = 'https://www.bambora.co.nz/interface/api'
|
|
7
|
+
self.test_url = 'https://demo.bambora.co.nz/interface/api'
|
|
8
8
|
|
|
9
9
|
self.supported_countries = ['AU', 'NZ']
|
|
10
10
|
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
|
|
@@ -32,7 +32,7 @@ module ActiveMerchant #:nodoc:
|
|
|
32
32
|
xml.CustRef options[:order_id]
|
|
33
33
|
add_amount(xml, money)
|
|
34
34
|
xml.TrnType '1'
|
|
35
|
-
|
|
35
|
+
add_payment(xml, payment)
|
|
36
36
|
add_credentials(xml, options)
|
|
37
37
|
xml.TrnSource options[:ip]
|
|
38
38
|
end
|
|
@@ -45,7 +45,7 @@ module ActiveMerchant #:nodoc:
|
|
|
45
45
|
xml.CustRef options[:order_id]
|
|
46
46
|
add_amount(xml, money)
|
|
47
47
|
xml.TrnType '2'
|
|
48
|
-
|
|
48
|
+
add_payment(xml, payment)
|
|
49
49
|
add_credentials(xml, options)
|
|
50
50
|
xml.TrnSource options[:ip]
|
|
51
51
|
end
|
|
@@ -82,6 +82,19 @@ module ActiveMerchant #:nodoc:
|
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
def store(payment, options={})
|
|
86
|
+
commit('TokeniseCreditCard') do |xml|
|
|
87
|
+
xml.TokeniseCreditCard do
|
|
88
|
+
xml.CardNumber payment.number
|
|
89
|
+
xml.ExpM format(payment.month, :two_digits)
|
|
90
|
+
xml.ExpY format(payment.year, :four_digits)
|
|
91
|
+
xml.TokeniseAlgorithmID options[:tokenise_algorithm_id] || 2
|
|
92
|
+
xml.UserName @options[:username]
|
|
93
|
+
xml.Password @options[:password]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
85
98
|
def supports_scrubbing?
|
|
86
99
|
true
|
|
87
100
|
end
|
|
@@ -107,6 +120,21 @@ module ActiveMerchant #:nodoc:
|
|
|
107
120
|
xml.Amount amount(money)
|
|
108
121
|
end
|
|
109
122
|
|
|
123
|
+
def add_payment(xml, payment)
|
|
124
|
+
if payment.is_a?(String)
|
|
125
|
+
add_token(xml, payment)
|
|
126
|
+
else
|
|
127
|
+
add_credit_card(xml, payment)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def add_token(xml, payment)
|
|
132
|
+
xml.CreditCard do
|
|
133
|
+
xml.TokeniseAlgorithmID options[:tokenise_algorithm_id] || 2
|
|
134
|
+
xml.CardNumber payment
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
110
138
|
def add_credit_card(xml, payment)
|
|
111
139
|
xml.CreditCard :Registered => 'False' do
|
|
112
140
|
xml.CardNumber payment.number
|
|
@@ -131,9 +159,9 @@ module ActiveMerchant #:nodoc:
|
|
|
131
159
|
def commit(action, &block)
|
|
132
160
|
headers = {
|
|
133
161
|
'Content-Type' => 'text/xml; charset=utf-8',
|
|
134
|
-
'SOAPAction' => "http://www.ippayments.com.au/interface/api
|
|
162
|
+
'SOAPAction' => "http://www.ippayments.com.au/interface/api/#{endpoint(action)}/#{action}"
|
|
135
163
|
}
|
|
136
|
-
response = parse(ssl_post(commit_url, new_submit_xml(action, &block), headers))
|
|
164
|
+
response = parse(ssl_post("#{commit_url}/#{endpoint(action)}.asmx", new_submit_xml(action, &block), headers))
|
|
137
165
|
|
|
138
166
|
Response.new(
|
|
139
167
|
success_from(response),
|
|
@@ -150,11 +178,19 @@ module ActiveMerchant #:nodoc:
|
|
|
150
178
|
xml.instruct!
|
|
151
179
|
xml.soap :Envelope, 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' do
|
|
152
180
|
xml.soap :Body do
|
|
153
|
-
xml.__send__(action, 'xmlns' =>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
xml.__send__(action, 'xmlns' => "http://www.ippayments.com.au/interface/api/#{endpoint(action)}") do
|
|
182
|
+
if action == 'TokeniseCreditCard'
|
|
183
|
+
xml.tokeniseCreditCardXML do
|
|
184
|
+
inner_xml = Builder::XmlMarkup.new(indent: 2)
|
|
185
|
+
yield(inner_xml)
|
|
186
|
+
xml.cdata!(inner_xml.target!)
|
|
187
|
+
end
|
|
188
|
+
else
|
|
189
|
+
xml.trnXML do
|
|
190
|
+
inner_xml = Builder::XmlMarkup.new(indent: 2)
|
|
191
|
+
yield(inner_xml)
|
|
192
|
+
xml.cdata!(inner_xml.target!)
|
|
193
|
+
end
|
|
158
194
|
end
|
|
159
195
|
end
|
|
160
196
|
end
|
|
@@ -162,12 +198,16 @@ module ActiveMerchant #:nodoc:
|
|
|
162
198
|
xml.target!
|
|
163
199
|
end
|
|
164
200
|
|
|
201
|
+
def endpoint(action)
|
|
202
|
+
action == 'TokeniseCreditCard' ? 'sipp' : 'dts'
|
|
203
|
+
end
|
|
204
|
+
|
|
165
205
|
def commit_url
|
|
166
206
|
test? ? test_url : live_url
|
|
167
207
|
end
|
|
168
208
|
|
|
169
209
|
def success_from(response)
|
|
170
|
-
response[:response_code] == '0'
|
|
210
|
+
response[:response_code] == '0' || response[:return_value] == '0'
|
|
171
211
|
end
|
|
172
212
|
|
|
173
213
|
def error_code_from(response)
|
|
@@ -175,11 +215,11 @@ module ActiveMerchant #:nodoc:
|
|
|
175
215
|
end
|
|
176
216
|
|
|
177
217
|
def message_from(response)
|
|
178
|
-
response[:declined_message]
|
|
218
|
+
success_from(response) ? 'Succeeded' : response[:declined_message]
|
|
179
219
|
end
|
|
180
220
|
|
|
181
221
|
def authorization_from(response)
|
|
182
|
-
response[:receipt]
|
|
222
|
+
response[:receipt] || response[:token]
|
|
183
223
|
end
|
|
184
224
|
end
|
|
185
225
|
end
|
|
@@ -24,7 +24,7 @@ module ActiveMerchant #:nodoc:
|
|
|
24
24
|
'REBID' => :rebid,
|
|
25
25
|
'TRANS_TYPE' => :trans_type,
|
|
26
26
|
'PAYMENT_ACCOUNT_MASK' => :acct_mask,
|
|
27
|
-
'CARD_TYPE' => :card_type
|
|
27
|
+
'CARD_TYPE' => :card_type
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
REBILL_FIELD_MAP = {
|
|
@@ -41,6 +41,7 @@ module ActiveMerchant #:nodoc:
|
|
|
41
41
|
'REB_AMOUNT' => :rebill_amount,
|
|
42
42
|
'NEXT_AMOUNT' => :next_amount,
|
|
43
43
|
'USUAL_DATE' => :undoc_usual_date, # Not found in the bp20rebadmin API doc.
|
|
44
|
+
'CUST_TOKEN' => :cust_token
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
self.supported_countries = ['US', 'CA']
|
|
@@ -84,7 +85,7 @@ module ActiveMerchant #:nodoc:
|
|
|
84
85
|
add_rebill(post, options) if options[:rebill]
|
|
85
86
|
add_duplicate_override(post, options)
|
|
86
87
|
post[:TRANS_TYPE] = 'AUTH'
|
|
87
|
-
commit('AUTH_ONLY', money, post)
|
|
88
|
+
commit('AUTH_ONLY', money, post, options)
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
|
@@ -107,7 +108,7 @@ module ActiveMerchant #:nodoc:
|
|
|
107
108
|
add_rebill(post, options) if options[:rebill]
|
|
108
109
|
add_duplicate_override(post, options)
|
|
109
110
|
post[:TRANS_TYPE] = 'SALE'
|
|
110
|
-
commit('AUTH_CAPTURE', money, post)
|
|
111
|
+
commit('AUTH_CAPTURE', money, post, options)
|
|
111
112
|
end
|
|
112
113
|
|
|
113
114
|
# Captures the funds from an authorize transaction.
|
|
@@ -123,7 +124,7 @@ module ActiveMerchant #:nodoc:
|
|
|
123
124
|
add_customer_data(post, options)
|
|
124
125
|
post[:MASTER_ID] = identification
|
|
125
126
|
post[:TRANS_TYPE] = 'CAPTURE'
|
|
126
|
-
commit('PRIOR_AUTH_CAPTURE', money, post)
|
|
127
|
+
commit('PRIOR_AUTH_CAPTURE', money, post, options)
|
|
127
128
|
end
|
|
128
129
|
|
|
129
130
|
# Void a previous transaction
|
|
@@ -136,7 +137,7 @@ module ActiveMerchant #:nodoc:
|
|
|
136
137
|
post = {}
|
|
137
138
|
post[:MASTER_ID] = identification
|
|
138
139
|
post[:TRANS_TYPE] = 'VOID'
|
|
139
|
-
commit('VOID', nil, post)
|
|
140
|
+
commit('VOID', nil, post, options)
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
# Performs a credit.
|
|
@@ -169,7 +170,7 @@ module ActiveMerchant #:nodoc:
|
|
|
169
170
|
add_invoice(post, options)
|
|
170
171
|
add_address(post, options)
|
|
171
172
|
add_customer_data(post, options)
|
|
172
|
-
commit('CREDIT', money, post)
|
|
173
|
+
commit('CREDIT', money, post, options)
|
|
173
174
|
end
|
|
174
175
|
|
|
175
176
|
def credit(money, payment_object, options = {})
|
|
@@ -189,7 +190,7 @@ module ActiveMerchant #:nodoc:
|
|
|
189
190
|
add_invoice(post, options)
|
|
190
191
|
add_address(post, options)
|
|
191
192
|
add_customer_data(post, options)
|
|
192
|
-
commit('CREDIT', money, post)
|
|
193
|
+
commit('CREDIT', money, post, options)
|
|
193
194
|
end
|
|
194
195
|
|
|
195
196
|
# Create a new recurring payment.
|
|
@@ -313,10 +314,11 @@ module ActiveMerchant #:nodoc:
|
|
|
313
314
|
|
|
314
315
|
private
|
|
315
316
|
|
|
316
|
-
def commit(action, money, fields)
|
|
317
|
+
def commit(action, money, fields, options = {})
|
|
317
318
|
fields[:AMOUNT] = amount(money) unless(fields[:TRANS_TYPE] == 'VOID' || action == 'rebill')
|
|
318
319
|
fields[:MODE] = (test? ? 'TEST' : 'LIVE')
|
|
319
320
|
fields[:ACCOUNT_ID] = @options[:login]
|
|
321
|
+
fields[:CUSTOMER_IP] = options[:ip] if options[:ip]
|
|
320
322
|
|
|
321
323
|
if action == 'rebill'
|
|
322
324
|
url = rebilling_url
|
|
@@ -543,6 +543,17 @@ module ActiveMerchant #:nodoc:
|
|
|
543
543
|
'token' => transaction.credit_card_details.token
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
+
if transaction.risk_data
|
|
547
|
+
risk_data = {
|
|
548
|
+
'id' => transaction.risk_data.id,
|
|
549
|
+
'decision' => transaction.risk_data.decision,
|
|
550
|
+
'device_data_captured' => transaction.risk_data.device_data_captured,
|
|
551
|
+
'fraud_service_provider' => transaction.risk_data.fraud_service_provider
|
|
552
|
+
}
|
|
553
|
+
else
|
|
554
|
+
risk_data = nil
|
|
555
|
+
end
|
|
556
|
+
|
|
546
557
|
{
|
|
547
558
|
'order_id' => transaction.order_id,
|
|
548
559
|
'amount' => transaction.amount.to_s,
|
|
@@ -553,6 +564,7 @@ module ActiveMerchant #:nodoc:
|
|
|
553
564
|
'shipping_details' => shipping_details,
|
|
554
565
|
'vault_customer' => vault_customer,
|
|
555
566
|
'merchant_account_id' => transaction.merchant_account_id,
|
|
567
|
+
'risk_data' => risk_data,
|
|
556
568
|
'processor_response_code' => response_code_from_result(result)
|
|
557
569
|
}
|
|
558
570
|
end
|
|
@@ -24,7 +24,7 @@ module ActiveMerchant #:nodoc:
|
|
|
24
24
|
self.test_url = 'https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor'
|
|
25
25
|
self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor'
|
|
26
26
|
|
|
27
|
-
XSD_VERSION = '1.
|
|
27
|
+
XSD_VERSION = '1.153'
|
|
28
28
|
|
|
29
29
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro]
|
|
30
30
|
self.supported_countries = %w(US BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB)
|
|
@@ -260,6 +260,7 @@ module ActiveMerchant #:nodoc:
|
|
|
260
260
|
add_threeds_services(xml, options)
|
|
261
261
|
add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
|
|
262
262
|
add_business_rules_data(xml, creditcard_or_reference, options)
|
|
263
|
+
add_stored_credential_options(xml, options)
|
|
263
264
|
xml.target!
|
|
264
265
|
end
|
|
265
266
|
|
|
@@ -513,7 +514,24 @@ module ActiveMerchant #:nodoc:
|
|
|
513
514
|
if network_tokenization?(payment_method)
|
|
514
515
|
add_auth_network_tokenization(xml, payment_method, options)
|
|
515
516
|
else
|
|
516
|
-
xml.tag! 'ccAuthService', {'run' => 'true'}
|
|
517
|
+
xml.tag! 'ccAuthService', {'run' => 'true'} do
|
|
518
|
+
check_for_stored_cred_commerce_indicator(xml, options)
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def check_for_stored_cred_commerce_indicator(xml, options)
|
|
524
|
+
return unless options[:stored_credential]
|
|
525
|
+
if commerce_indicator(options)
|
|
526
|
+
xml.tag!('commerceIndicator', commerce_indicator(options))
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def commerce_indicator(options)
|
|
531
|
+
return if options[:stored_credential][:initial_transaction]
|
|
532
|
+
case options[:stored_credential][:reason_type]
|
|
533
|
+
when 'installment' then 'install'
|
|
534
|
+
when 'recurring' then 'recurring'
|
|
517
535
|
end
|
|
518
536
|
end
|
|
519
537
|
|
|
@@ -680,6 +698,18 @@ module ActiveMerchant #:nodoc:
|
|
|
680
698
|
country_code&.code(:alpha2)
|
|
681
699
|
end
|
|
682
700
|
|
|
701
|
+
def add_stored_credential_options(xml, options={})
|
|
702
|
+
return unless options[:stored_credential]
|
|
703
|
+
if options[:stored_credential][:initial_transaction]
|
|
704
|
+
xml.tag! 'subsequentAuthFirst', 'true'
|
|
705
|
+
elsif options[:stored_credential][:reason_type] == 'unscheduled'
|
|
706
|
+
xml.tag! 'subsequentAuth', 'true'
|
|
707
|
+
xml.tag! 'subsequentAuthTransactionID', options[:stored_credential][:network_transaction_id]
|
|
708
|
+
else
|
|
709
|
+
xml.tag! 'subsequentAuthTransactionID', options[:stored_credential][:network_transaction_id]
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
683
713
|
# Where we actually build the full SOAP request using builder
|
|
684
714
|
def build_request(body, options)
|
|
685
715
|
xml = Builder::XmlMarkup.new :indent => 2
|
|
@@ -93,7 +93,7 @@ module ActiveMerchant #:nodoc:
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def lookup_country_code(country)
|
|
96
|
-
Country.find(country).code(:alpha2)
|
|
96
|
+
Country.find(country).code(:alpha2).value
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
def add_payer(post, card, options)
|
|
@@ -102,7 +102,7 @@ module ActiveMerchant #:nodoc:
|
|
|
102
102
|
post[:payer][:name] = card.name
|
|
103
103
|
post[:payer][:email] = options[:email] if options[:email]
|
|
104
104
|
post[:payer][:birth_date] = options[:birth_date] if options[:birth_date]
|
|
105
|
-
post[:payer][:phone] = address[:phone] if address[:phone]
|
|
105
|
+
post[:payer][:phone] = address[:phone] if address && address[:phone]
|
|
106
106
|
post[:payer][:document] = options[:document] if options[:document]
|
|
107
107
|
post[:payer][:document2] = options[:document2] if options[:document2]
|
|
108
108
|
post[:payer][:user_reference] = options[:user_reference] if options[:user_reference]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
|
2
2
|
module Billing #:nodoc:
|
|
3
3
|
class FirstdataE4V27Gateway < Gateway
|
|
4
|
-
self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/
|
|
5
|
-
self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/
|
|
4
|
+
self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v28'
|
|
5
|
+
self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/v28'
|
|
6
6
|
|
|
7
7
|
TRANSACTIONS = {
|
|
8
8
|
sale: '00',
|
|
@@ -148,6 +148,7 @@ module ActiveMerchant #:nodoc:
|
|
|
148
148
|
add_credit_card_token(xml, credit_card_or_store_authorization, options)
|
|
149
149
|
else
|
|
150
150
|
add_credit_card(xml, credit_card_or_store_authorization, options)
|
|
151
|
+
add_stored_credentials(xml, credit_card_or_store_authorization, options)
|
|
151
152
|
end
|
|
152
153
|
|
|
153
154
|
add_address(xml, options)
|
|
@@ -312,6 +313,35 @@ module ActiveMerchant #:nodoc:
|
|
|
312
313
|
xml.tag!('Level3') { |x| x << options[:level_3] } if options[:level_3]
|
|
313
314
|
end
|
|
314
315
|
|
|
316
|
+
def add_stored_credentials(xml, card, options)
|
|
317
|
+
return unless options[:stored_credential]
|
|
318
|
+
xml.tag! 'StoredCredentials' do
|
|
319
|
+
xml.tag! 'Indicator', stored_credential_indicator(xml, card, options)
|
|
320
|
+
if initiator = options.dig(:stored_credential, :initiator)
|
|
321
|
+
xml.tag! initiator == 'merchant' ? 'M' : 'C'
|
|
322
|
+
end
|
|
323
|
+
if reason_type = options.dig(:stored_credential, :reason_type)
|
|
324
|
+
xml.tag! 'Schedule', reason_type == 'unscheduled' ? 'U' : 'S'
|
|
325
|
+
end
|
|
326
|
+
xml.tag! 'AuthorizationTypeOverride', options[:authorization_type_override] if options[:authorization_type_override]
|
|
327
|
+
if network_transaction_id = options[:stored_credential][:network_transaction_id]
|
|
328
|
+
xml.tag! 'TransactionId', network_transaction_id
|
|
329
|
+
else
|
|
330
|
+
xml.tag! 'TransactionId', 'new'
|
|
331
|
+
end
|
|
332
|
+
xml.tag! 'OriginalAmount', options[:original_amount] if options[:original_amount]
|
|
333
|
+
xml.tag! 'ProtectbuyIndicator', options[:protectbuy_indicator] if options[:protectbuy_indicator]
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def stored_credential_indicator(xml, card, options)
|
|
338
|
+
if card.brand == 'master' || options.dig(:stored_credential, :initial_transaction) == false
|
|
339
|
+
'S'
|
|
340
|
+
else
|
|
341
|
+
'1'
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
315
345
|
def expdate(credit_card)
|
|
316
346
|
"#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
|
|
317
347
|
end
|
|
@@ -438,9 +468,18 @@ module ActiveMerchant #:nodoc:
|
|
|
438
468
|
|
|
439
469
|
def parse_elements(response, root)
|
|
440
470
|
root.elements.to_a.each do |node|
|
|
441
|
-
|
|
471
|
+
if node.has_elements?
|
|
472
|
+
parse_elements(response, node)
|
|
473
|
+
else
|
|
474
|
+
response[name_node(root, node)] = (node.text || '').strip
|
|
475
|
+
end
|
|
442
476
|
end
|
|
443
477
|
end
|
|
478
|
+
|
|
479
|
+
def name_node(root, node)
|
|
480
|
+
parent = root.name unless root.name == 'TransactionResult'
|
|
481
|
+
"#{parent}#{node.name}".gsub(/EXact/, 'Exact').underscore.to_sym
|
|
482
|
+
end
|
|
444
483
|
end
|
|
445
484
|
end
|
|
446
485
|
end
|
|
@@ -3,7 +3,7 @@ require 'nokogiri'
|
|
|
3
3
|
module ActiveMerchant #:nodoc:
|
|
4
4
|
module Billing #:nodoc:
|
|
5
5
|
class LitleGateway < Gateway
|
|
6
|
-
SCHEMA_VERSION = '9.
|
|
6
|
+
SCHEMA_VERSION = '9.14'
|
|
7
7
|
|
|
8
8
|
self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online'
|
|
9
9
|
self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online'
|
|
@@ -223,6 +223,7 @@ module ActiveMerchant #:nodoc:
|
|
|
223
223
|
add_descriptor(doc, options)
|
|
224
224
|
add_merchant_data(doc, options)
|
|
225
225
|
add_debt_repayment(doc, options)
|
|
226
|
+
add_stored_credential_params(doc, options)
|
|
226
227
|
end
|
|
227
228
|
|
|
228
229
|
def add_merchant_data(doc, options={})
|
|
@@ -293,6 +294,38 @@ module ActiveMerchant #:nodoc:
|
|
|
293
294
|
end
|
|
294
295
|
end
|
|
295
296
|
|
|
297
|
+
def add_stored_credential_params(doc, options={})
|
|
298
|
+
return unless options[:stored_credential]
|
|
299
|
+
|
|
300
|
+
if options[:stored_credential][:initial_transaction]
|
|
301
|
+
add_stored_credential_params_initial(doc, options)
|
|
302
|
+
else
|
|
303
|
+
add_stored_credential_params_used(doc, options)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def add_stored_credential_params_initial(doc, options)
|
|
308
|
+
case options[:stored_credential][:reason_type]
|
|
309
|
+
when 'unscheduled'
|
|
310
|
+
doc.processingType('initialCOF')
|
|
311
|
+
when 'installment'
|
|
312
|
+
doc.processingType('initialInstallment')
|
|
313
|
+
when 'recurring'
|
|
314
|
+
doc.processingType('initialRecurring')
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def add_stored_credential_params_used(doc, options)
|
|
319
|
+
if options[:stored_credential][:reason_type] == 'unscheduled'
|
|
320
|
+
if options[:stored_credential][:initiator] == 'merchant'
|
|
321
|
+
doc.processingType('merchantInitiatedCOF')
|
|
322
|
+
else
|
|
323
|
+
doc.processingType('cardholderInitiatedCOF')
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
doc.originalNetworkTransactionId(options[:stored_credential][:network_transaction_id])
|
|
327
|
+
end
|
|
328
|
+
|
|
296
329
|
def add_billing_address(doc, payment_method, options)
|
|
297
330
|
return if payment_method.is_a?(String)
|
|
298
331
|
|
|
@@ -332,8 +365,9 @@ module ActiveMerchant #:nodoc:
|
|
|
332
365
|
end
|
|
333
366
|
|
|
334
367
|
def add_order_source(doc, payment_method, options)
|
|
335
|
-
|
|
336
|
-
|
|
368
|
+
order_source = order_source(options)
|
|
369
|
+
if order_source
|
|
370
|
+
doc.orderSource(order_source)
|
|
337
371
|
elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :apple_pay
|
|
338
372
|
doc.orderSource('applepay')
|
|
339
373
|
elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :android_pay
|
|
@@ -345,6 +379,30 @@ module ActiveMerchant #:nodoc:
|
|
|
345
379
|
end
|
|
346
380
|
end
|
|
347
381
|
|
|
382
|
+
def order_source(options={})
|
|
383
|
+
return options[:order_source] unless options[:stored_credential]
|
|
384
|
+
order_source = nil
|
|
385
|
+
|
|
386
|
+
case options[:stored_credential][:reason_type]
|
|
387
|
+
when 'unscheduled'
|
|
388
|
+
if options[:stored_credential][:initiator] == 'merchant'
|
|
389
|
+
# For merchant-initiated, we should always set order source to
|
|
390
|
+
# 'ecommerce'
|
|
391
|
+
order_source = 'ecommerce'
|
|
392
|
+
else
|
|
393
|
+
# For cardholder-initiated, we rely on #add_order_source's
|
|
394
|
+
# default logic to set orderSource appropriately
|
|
395
|
+
order_source = options[:order_source]
|
|
396
|
+
end
|
|
397
|
+
when 'installment'
|
|
398
|
+
order_source = 'installment'
|
|
399
|
+
when 'recurring'
|
|
400
|
+
order_source = 'recurring'
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
order_source
|
|
404
|
+
end
|
|
405
|
+
|
|
348
406
|
def add_pos(doc, payment_method)
|
|
349
407
|
return unless payment_method.respond_to?(:track_data) && payment_method.track_data.present?
|
|
350
408
|
|
|
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
|
|
|
4
4
|
self.live_url = self.test_url = 'https://api.mercadopago.com/v1'
|
|
5
5
|
|
|
6
6
|
self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY']
|
|
7
|
-
self.supported_cardtypes = [:visa, :master, :american_express]
|
|
7
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :elo]
|
|
8
8
|
|
|
9
9
|
self.homepage_url = 'https://www.mercadopago.com/'
|
|
10
10
|
self.display_name = 'Mercado Pago'
|
|
@@ -128,8 +128,8 @@ module ActiveMerchant #:nodoc:
|
|
|
128
128
|
def add_shipping_address(post, options)
|
|
129
129
|
if address = options[:shipping_address]
|
|
130
130
|
post[:address] = {}
|
|
131
|
-
post[:address][:street] = address[:address1].match(/\D+/)[0].strip if address[:address1]
|
|
132
|
-
post[:address][:number] = address[:address1].match(/\d+/)[0] if address[:address1]
|
|
131
|
+
post[:address][:street] = address[:address1].match(/\D+/)[0].strip if address[:address1]&.match(/\D+/)
|
|
132
|
+
post[:address][:number] = address[:address1].match(/\d+/)[0] if address[:address1]&.match(/\d+/)
|
|
133
133
|
post[:address][:compliment] = address[:address2] if address[:address2]
|
|
134
134
|
post[:address][:city] = address[:city] if address[:city]
|
|
135
135
|
post[:address][:state] = address[:state] if address[:state]
|
|
@@ -507,9 +507,33 @@ module ActiveMerchant #:nodoc:
|
|
|
507
507
|
end
|
|
508
508
|
|
|
509
509
|
def add_stored_credentials(xml, parameters)
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
510
|
+
return unless parameters[:mit_stored_credential_ind] == 'Y' || parameters[:stored_credential] && !parameters[:stored_credential].values.all?(&:nil?)
|
|
511
|
+
if msg_type = get_msg_type(parameters)
|
|
512
|
+
xml.tag! :MITMsgType, msg_type
|
|
513
|
+
end
|
|
514
|
+
xml.tag! :MITStoredCredentialInd, 'Y'
|
|
515
|
+
if parameters[:mit_submitted_transaction_id]
|
|
516
|
+
xml.tag! :MITSubmittedTransactionID, parameters[:mit_submitted_transaction_id]
|
|
517
|
+
elsif parameters.dig(:stored_credential, :network_transaction_id) && parameters.dig(:stored_credential, :initiator) == 'merchant'
|
|
518
|
+
xml.tag! :MITSubmittedTransactionID, parameters[:stored_credential][:network_transaction_id]
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def get_msg_type(parameters)
|
|
523
|
+
return parameters[:mit_msg_type] if parameters[:mit_msg_type]
|
|
524
|
+
return 'CSTO' if parameters[:stored_credential][:initial_transaction]
|
|
525
|
+
return unless parameters[:stored_credential][:initiator] && parameters[:stored_credential][:reason_type]
|
|
526
|
+
initiator = case parameters[:stored_credential][:initiator]
|
|
527
|
+
when 'customer' then 'C'
|
|
528
|
+
when 'merchant' then 'M'
|
|
529
|
+
end
|
|
530
|
+
reason = case parameters[:stored_credential][:reason_type]
|
|
531
|
+
when 'recurring' then 'REC'
|
|
532
|
+
when 'installment' then 'INS'
|
|
533
|
+
when 'unscheduled' then 'USE'
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
"#{initiator}#{reason}"
|
|
513
537
|
end
|
|
514
538
|
|
|
515
539
|
def parse(body)
|
|
@@ -153,6 +153,7 @@ module ActiveMerchant #:nodoc:
|
|
|
153
153
|
add_invoice(result, options)
|
|
154
154
|
add_address_verification_data(result, options)
|
|
155
155
|
add_optional_elements(result, options)
|
|
156
|
+
add_ip(result, options)
|
|
156
157
|
result
|
|
157
158
|
end
|
|
158
159
|
|
|
@@ -163,6 +164,7 @@ module ActiveMerchant #:nodoc:
|
|
|
163
164
|
add_invoice(result, options)
|
|
164
165
|
add_reference(result, identification)
|
|
165
166
|
add_optional_elements(result, options)
|
|
167
|
+
add_ip(result, options)
|
|
166
168
|
result
|
|
167
169
|
end
|
|
168
170
|
|
|
@@ -172,6 +174,7 @@ module ActiveMerchant #:nodoc:
|
|
|
172
174
|
add_amount(result, 100, options) # need to make an auth request for $1
|
|
173
175
|
add_token_request(result, options)
|
|
174
176
|
add_optional_elements(result, options)
|
|
177
|
+
add_ip(result, options)
|
|
175
178
|
result
|
|
176
179
|
end
|
|
177
180
|
|
|
@@ -233,6 +236,10 @@ module ActiveMerchant #:nodoc:
|
|
|
233
236
|
xml.add_element('AvsPostCode').text = address[:zip]
|
|
234
237
|
end
|
|
235
238
|
|
|
239
|
+
def add_ip(xml, options)
|
|
240
|
+
xml.add_element('ClientInfo').text = options[:ip] if options[:ip]
|
|
241
|
+
end
|
|
242
|
+
|
|
236
243
|
# The options hash may contain optional data which will be passed
|
|
237
244
|
# through the specialized optional fields at PaymentExpress
|
|
238
245
|
# as follows:
|
|
@@ -241,8 +248,7 @@ module ActiveMerchant #:nodoc:
|
|
|
241
248
|
# :client_type => :web, # Possible values are: :web, :ivr, :moto, :unattended, :internet, or :recurring
|
|
242
249
|
# :txn_data1 => "String up to 255 characters",
|
|
243
250
|
# :txn_data2 => "String up to 255 characters",
|
|
244
|
-
# :txn_data3 => "String up to 255 characters"
|
|
245
|
-
# :client_info => "String up to 15 characters. The IP address of the user who processed the transaction."
|
|
251
|
+
# :txn_data3 => "String up to 255 characters"
|
|
246
252
|
# }
|
|
247
253
|
#
|
|
248
254
|
# +:client_type+, while not documented for PxPost, will be sent as
|
|
@@ -278,8 +284,6 @@ module ActiveMerchant #:nodoc:
|
|
|
278
284
|
xml.add_element('TxnData1').text = options[:txn_data1].to_s.slice(0, 255) unless options[:txn_data1].blank?
|
|
279
285
|
xml.add_element('TxnData2').text = options[:txn_data2].to_s.slice(0, 255) unless options[:txn_data2].blank?
|
|
280
286
|
xml.add_element('TxnData3').text = options[:txn_data3].to_s.slice(0, 255) unless options[:txn_data3].blank?
|
|
281
|
-
|
|
282
|
-
xml.add_element('ClientInfo').text = options[:client_info] if options[:client_info]
|
|
283
287
|
end
|
|
284
288
|
|
|
285
289
|
def new_transaction
|
|
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
|
|
|
9
9
|
|
|
10
10
|
self.supported_countries = %w[MX EC VE CO BR CL]
|
|
11
11
|
self.default_currency = 'USD'
|
|
12
|
-
self.supported_cardtypes = %i[visa master american_express diners_club]
|
|
12
|
+
self.supported_cardtypes = %i[visa master american_express diners_club elo]
|
|
13
13
|
|
|
14
14
|
self.homepage_url = 'https://secure.paymentez.com/'
|
|
15
15
|
self.display_name = 'Paymentez'
|
|
@@ -38,7 +38,8 @@ module ActiveMerchant #:nodoc:
|
|
|
38
38
|
'visa' => 'vi',
|
|
39
39
|
'master' => 'mc',
|
|
40
40
|
'american_express' => 'ax',
|
|
41
|
-
'diners_club' => 'di'
|
|
41
|
+
'diners_club' => 'di',
|
|
42
|
+
'elo' => 'el'
|
|
42
43
|
}.freeze
|
|
43
44
|
|
|
44
45
|
def initialize(options = {})
|
|
@@ -146,7 +146,9 @@ module ActiveMerchant #:nodoc:
|
|
|
146
146
|
xml.tag! 'n2:cpp-payflow-color', options[:background_color] unless options[:background_color].blank?
|
|
147
147
|
if options[:allow_guest_checkout]
|
|
148
148
|
xml.tag! 'n2:SolutionType', 'Sole'
|
|
149
|
-
|
|
149
|
+
unless options[:paypal_chooses_landing_page]
|
|
150
|
+
xml.tag! 'n2:LandingPage', options[:landing_page] || 'Billing'
|
|
151
|
+
end
|
|
150
152
|
end
|
|
151
153
|
xml.tag! 'n2:BuyerEmail', options[:email] unless options[:email].blank?
|
|
152
154
|
|
|
@@ -103,7 +103,7 @@ module ActiveMerchant
|
|
|
103
103
|
post = {}
|
|
104
104
|
|
|
105
105
|
add_amount(post, money, options)
|
|
106
|
-
add_credit_card_or_reference(post, credit_card_or_reference)
|
|
106
|
+
add_credit_card_or_reference(post, credit_card_or_reference, options)
|
|
107
107
|
add_additional_params(:authorize, post, options)
|
|
108
108
|
|
|
109
109
|
post
|
|
@@ -217,6 +217,12 @@ module ActiveMerchant
|
|
|
217
217
|
post[:card][:expiration] = expdate(credit_card_or_reference)
|
|
218
218
|
post[:card][:issued_to] = credit_card_or_reference.name
|
|
219
219
|
end
|
|
220
|
+
|
|
221
|
+
if options[:three_d_secure]
|
|
222
|
+
post[:card][:cavv]= options.dig(:three_d_secure, :cavv)
|
|
223
|
+
post[:card][:eci] = options.dig(:three_d_secure, :eci)
|
|
224
|
+
post[:card][:xav] = options.dig(:three_d_secure, :xid)
|
|
225
|
+
end
|
|
220
226
|
end
|
|
221
227
|
|
|
222
228
|
def parse(body)
|
|
@@ -145,7 +145,11 @@ module ActiveMerchant
|
|
|
145
145
|
add_card(xml, credit_card)
|
|
146
146
|
xml.tag! 'autosettle', 'flag' => auto_settle_flag(action)
|
|
147
147
|
add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
|
|
148
|
-
|
|
148
|
+
if credit_card.is_a?(NetworkTokenizationCreditCard)
|
|
149
|
+
add_network_tokenization_card(xml, credit_card)
|
|
150
|
+
else
|
|
151
|
+
add_three_d_secure(xml, options)
|
|
152
|
+
end
|
|
149
153
|
add_comments(xml, options)
|
|
150
154
|
add_address_and_customer_info(xml, options)
|
|
151
155
|
end
|
|
@@ -284,6 +288,16 @@ module ActiveMerchant
|
|
|
284
288
|
end
|
|
285
289
|
end
|
|
286
290
|
|
|
291
|
+
def add_three_d_secure(xml, options)
|
|
292
|
+
if options[:three_d_secure]
|
|
293
|
+
xml.tag! 'mpi' do
|
|
294
|
+
xml.tag! 'cavv', options[:three_d_secure][:cavv]
|
|
295
|
+
xml.tag! 'eci', options[:three_d_secure][:eci]
|
|
296
|
+
xml.tag! 'xid', options[:three_d_secure][:xid]
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
287
301
|
def format_address_code(address)
|
|
288
302
|
code = [address[:zip].to_s, address[:address1].to_s + address[:address2].to_s]
|
|
289
303
|
code.collect { |e| e.gsub(/\D/, '') }.reject(&:empty?).join('|')
|
|
@@ -57,7 +57,10 @@ module ActiveMerchant #:nodoc:
|
|
|
57
57
|
response = commit('cancelDeposit', params, options)
|
|
58
58
|
return response if response.success? || split_authorization(authorization).length == 1 || !options[:force_full_refund_if_unsettled]
|
|
59
59
|
|
|
60
|
-
# Attempt RefundSingleTransaction if unsettled
|
|
60
|
+
# Attempt RefundSingleTransaction if unsettled (and stash the original
|
|
61
|
+
# response message so it will be included it in the follow-up response
|
|
62
|
+
# message)
|
|
63
|
+
options[:error_message] = response.message
|
|
61
64
|
prepare_refund_data(params, authorization, options)
|
|
62
65
|
commit('refund', params, options)
|
|
63
66
|
end
|
|
@@ -197,15 +200,24 @@ module ActiveMerchant #:nodoc:
|
|
|
197
200
|
end
|
|
198
201
|
|
|
199
202
|
def message_from(response, options, action)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
message_from_messages(
|
|
204
|
+
response['errorMessage'],
|
|
205
|
+
action_code_description(response),
|
|
206
|
+
options[:error_message]
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def message_from_messages(*args)
|
|
211
|
+
args.reject { |m| error_message_empty?(m) }.join(' | ')
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def action_code_description(response)
|
|
215
|
+
return nil unless response['data']
|
|
216
|
+
response['data']['DSC_COD_ACCION']
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def error_message_empty?(error_message)
|
|
220
|
+
empty?(error_message) || error_message == '[ ]'
|
|
209
221
|
end
|
|
210
222
|
|
|
211
223
|
def response_error(raw_response, options, action)
|
|
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
|
|
|
7
7
|
self.default_currency = 'GBP'
|
|
8
8
|
self.money_format = :cents
|
|
9
9
|
self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
|
|
10
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro]
|
|
10
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :elo]
|
|
11
11
|
self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
|
|
12
12
|
self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
|
|
13
13
|
self.homepage_url = 'http://www.worldpay.com/'
|
|
@@ -21,6 +21,7 @@ module ActiveMerchant #:nodoc:
|
|
|
21
21
|
'jcb' => 'JCB-SSL',
|
|
22
22
|
'maestro' => 'MAESTRO-SSL',
|
|
23
23
|
'diners_club' => 'DINERS-SSL',
|
|
24
|
+
'elo' => 'ELO-SSL'
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
AVS_CODE_MAP = {
|
|
@@ -262,13 +263,23 @@ module ActiveMerchant #:nodoc:
|
|
|
262
263
|
|
|
263
264
|
add_address(xml, (options[:billing_address] || options[:address]))
|
|
264
265
|
end
|
|
266
|
+
add_stored_credential_options(xml, options)
|
|
265
267
|
if options[:ip] && options[:session_id]
|
|
266
268
|
xml.tag! 'session', 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
|
|
267
269
|
else
|
|
268
270
|
xml.tag! 'session', 'shopperIPAddress' => options[:ip] if options[:ip]
|
|
269
271
|
xml.tag! 'session', 'id' => options[:session_id] if options[:session_id]
|
|
270
272
|
end
|
|
271
|
-
|
|
273
|
+
|
|
274
|
+
if three_d_secure = options[:three_d_secure]
|
|
275
|
+
xml.tag! 'info3DSecure' do
|
|
276
|
+
xml.tag! 'threeDSVersion', three_d_secure[:version]
|
|
277
|
+
xid_tag = three_d_secure[:version] =~ /^2/ ? 'dsTransactionId' : 'xid'
|
|
278
|
+
xml.tag! xid_tag, three_d_secure[:xid]
|
|
279
|
+
xml.tag! 'cavv', three_d_secure[:cavv]
|
|
280
|
+
xml.tag! 'eci', three_d_secure[:eci]
|
|
281
|
+
end
|
|
282
|
+
end
|
|
272
283
|
end
|
|
273
284
|
end
|
|
274
285
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activemerchant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.92.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tobias Luetke
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-04-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|