activemerchant 1.90.0 → 1.99.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 +202 -0
- data/README.md +6 -2
- data/lib/active_merchant/billing/avs_result.rb +4 -5
- data/lib/active_merchant/billing/credit_card.rb +8 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +81 -5
- data/lib/active_merchant/billing/gateway.rb +10 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +206 -54
- data/lib/active_merchant/billing/gateways/bambora_apac.rb +226 -0
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
- data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_snap.rb +211 -36
- data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +79 -18
- data/lib/active_merchant/billing/gateways/card_connect.rb +6 -1
- data/lib/active_merchant/billing/gateways/cecabank.rb +20 -9
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
- data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
- data/lib/active_merchant/billing/gateways/cyber_source.rb +85 -14
- data/lib/active_merchant/billing/gateways/d_local.rb +3 -3
- data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
- data/lib/active_merchant/billing/gateways/epay.rb +13 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +26 -7
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
- data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
- data/lib/active_merchant/billing/gateways/hps.rb +46 -1
- data/lib/active_merchant/billing/gateways/ipp.rb +1 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
- data/lib/active_merchant/billing/gateways/litle.rb +61 -3
- data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +8 -0
- data/lib/active_merchant/billing/gateways/monei.rb +31 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +3 -4
- data/lib/active_merchant/billing/gateways/mundipagg.rb +37 -9
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbanx.rb +4 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +45 -5
- data/lib/active_merchant/billing/gateways/openpay.rb +1 -1
- data/lib/active_merchant/billing/gateways/opp.rb +20 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +92 -11
- data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
- data/lib/active_merchant/billing/gateways/payment_express.rb +7 -0
- data/lib/active_merchant/billing/gateways/paymentez.rb +7 -11
- data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
- data/lib/active_merchant/billing/gateways/pin.rb +19 -6
- data/lib/active_merchant/billing/gateways/pro_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
- data/lib/active_merchant/billing/gateways/qvalent.rb +54 -1
- data/lib/active_merchant/billing/gateways/realex.rb +42 -5
- data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
- data/lib/active_merchant/billing/gateways/stripe.rb +66 -34
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
- data/lib/active_merchant/billing/gateways/tns.rb +10 -5
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +5 -5
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +46 -6
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +19 -8
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
- data/lib/active_merchant/billing/gateways/worldpay.rb +237 -34
- data/lib/active_merchant/country.rb +2 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +20 -4
|
@@ -13,7 +13,7 @@ module ActiveMerchant #:nodoc:
|
|
|
13
13
|
self.homepage_url = 'https://www.barclaycardsmartpay.com/'
|
|
14
14
|
self.display_name = 'Barclaycard Smartpay'
|
|
15
15
|
|
|
16
|
-
API_VERSION = '
|
|
16
|
+
API_VERSION = 'v40'
|
|
17
17
|
|
|
18
18
|
def initialize(options = {})
|
|
19
19
|
requires!(options, :company, :merchant, :password)
|
|
@@ -37,7 +37,9 @@ module ActiveMerchant #:nodoc:
|
|
|
37
37
|
post[:card] = credit_card_hash(creditcard)
|
|
38
38
|
post[:billingAddress] = billing_address_hash(options) if options[:billing_address]
|
|
39
39
|
post[:deliveryAddress] = shipping_address_hash(options) if options[:shipping_address]
|
|
40
|
-
|
|
40
|
+
post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
|
|
41
|
+
|
|
42
|
+
add_3ds(post, options)
|
|
41
43
|
commit('authorise', post)
|
|
42
44
|
end
|
|
43
45
|
|
|
@@ -186,7 +188,7 @@ module ActiveMerchant #:nodoc:
|
|
|
186
188
|
end
|
|
187
189
|
|
|
188
190
|
def parse_avs_code(response)
|
|
189
|
-
AVS_MAPPING[response['avsResult'][0..1].strip] if response
|
|
191
|
+
AVS_MAPPING[response['additionalData']['avsResult'][0..1].strip] if response.dig('additionalData', 'avsResult')
|
|
190
192
|
end
|
|
191
193
|
|
|
192
194
|
def flatten_hash(hash, prefix = nil)
|
|
@@ -210,12 +212,18 @@ module ActiveMerchant #:nodoc:
|
|
|
210
212
|
end
|
|
211
213
|
|
|
212
214
|
def parse(response)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
parsed_response = {}
|
|
216
|
+
params = CGI.parse(response)
|
|
217
|
+
params.each do |key, value|
|
|
218
|
+
parsed_key = key.split('.', 2)
|
|
219
|
+
if parsed_key.size > 1
|
|
220
|
+
parsed_response[parsed_key[0]] ||= {}
|
|
221
|
+
parsed_response[parsed_key[0]][parsed_key[1]] = value[0]
|
|
222
|
+
else
|
|
223
|
+
parsed_response[parsed_key[0]] = value[0]
|
|
217
224
|
end
|
|
218
|
-
|
|
225
|
+
end
|
|
226
|
+
parsed_response
|
|
219
227
|
end
|
|
220
228
|
|
|
221
229
|
def post_data(data)
|
|
@@ -343,8 +351,33 @@ module ActiveMerchant #:nodoc:
|
|
|
343
351
|
end
|
|
344
352
|
|
|
345
353
|
def add_3ds(post, options)
|
|
346
|
-
|
|
347
|
-
|
|
354
|
+
if three_ds_2_options = options[:three_ds_2]
|
|
355
|
+
device_channel = three_ds_2_options[:channel]
|
|
356
|
+
if device_channel == 'app'
|
|
357
|
+
post[:threeDS2RequestData] = { deviceChannel: device_channel }
|
|
358
|
+
else
|
|
359
|
+
add_browser_info(three_ds_2_options[:browser_info], post)
|
|
360
|
+
post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
|
|
361
|
+
end
|
|
362
|
+
else
|
|
363
|
+
return unless options[:execute_threed] || options[:threed_dynamic]
|
|
364
|
+
post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
|
|
365
|
+
post[:additionalData] = { executeThreeD: 'true' } if options[:execute_threed]
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def add_browser_info(browser_info, post)
|
|
370
|
+
return unless browser_info
|
|
371
|
+
post[:browserInfo] = {
|
|
372
|
+
acceptHeader: browser_info[:accept_header],
|
|
373
|
+
colorDepth: browser_info[:depth],
|
|
374
|
+
javaEnabled: browser_info[:java],
|
|
375
|
+
language: browser_info[:language],
|
|
376
|
+
screenHeight: browser_info[:height],
|
|
377
|
+
screenWidth: browser_info[:width],
|
|
378
|
+
timeZoneOffset: browser_info[:timezone],
|
|
379
|
+
userAgent: browser_info[:user_agent]
|
|
380
|
+
}
|
|
348
381
|
end
|
|
349
382
|
end
|
|
350
383
|
end
|
|
@@ -315,6 +315,9 @@ module ActiveMerchant #:nodoc:
|
|
|
315
315
|
post[:operationType] = options[:operationType] || options[:operation] || secure_profile_action(:new)
|
|
316
316
|
post[:customerCode] = options[:billing_id] || options[:vault_id] || false
|
|
317
317
|
post[:status] = options[:status]
|
|
318
|
+
|
|
319
|
+
billing_address = options[:billing_address] || options[:address]
|
|
320
|
+
post[:trnCardOwner] = billing_address ? billing_address[:name] : nil
|
|
318
321
|
end
|
|
319
322
|
|
|
320
323
|
def add_recurring_amount(post, money)
|
|
@@ -93,12 +93,15 @@ module ActiveMerchant #:nodoc:
|
|
|
93
93
|
|
|
94
94
|
def void(authorization, options = {})
|
|
95
95
|
reference, amount, type = split_auth(authorization)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
if type == TRANSACTIONS[:authorization]
|
|
97
|
+
capture(0, authorization, options)
|
|
98
|
+
else
|
|
99
|
+
post = {}
|
|
100
|
+
add_reference(post, reference)
|
|
101
|
+
add_original_amount(post, amount)
|
|
102
|
+
add_transaction_type(post, void_action(type))
|
|
103
|
+
commit(post)
|
|
104
|
+
end
|
|
102
105
|
end
|
|
103
106
|
|
|
104
107
|
def verify(source, options={})
|
|
@@ -153,6 +156,8 @@ module ActiveMerchant #:nodoc:
|
|
|
153
156
|
|
|
154
157
|
# To match the other stored-value gateways, like TrustCommerce,
|
|
155
158
|
# store and unstore need to be defined
|
|
159
|
+
#
|
|
160
|
+
# When passing a single-use token the :name option is required
|
|
156
161
|
def store(payment_method, options = {})
|
|
157
162
|
post = {}
|
|
158
163
|
add_address(post, options)
|
|
@@ -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
|
|
@@ -5,10 +5,10 @@ module ActiveMerchant
|
|
|
5
5
|
class BlueSnapGateway < Gateway
|
|
6
6
|
self.test_url = 'https://sandbox.bluesnap.com/services/2'
|
|
7
7
|
self.live_url = 'https://ws.bluesnap.com/services/2'
|
|
8
|
-
self.supported_countries = %w(US CA GB AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE)
|
|
8
|
+
self.supported_countries = %w(US CA GB AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE AR BO BR BZ CL CO CR DO EC GF GP GT HN HT MF MQ MX NI PA PE PR PY SV UY VE)
|
|
9
9
|
|
|
10
10
|
self.default_currency = 'USD'
|
|
11
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
|
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja, :cabal]
|
|
12
12
|
|
|
13
13
|
self.homepage_url = 'https://home.bluesnap.com/'
|
|
14
14
|
self.display_name = 'BlueSnap'
|
|
@@ -59,14 +59,29 @@ module ActiveMerchant
|
|
|
59
59
|
'line1: N, zip: N, name: N' => 'N',
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
BANK_ACCOUNT_TYPE_MAPPING = {
|
|
63
|
+
'personal_checking' => 'CONSUMER_CHECKING',
|
|
64
|
+
'personal_savings' => 'CONSUMER_SAVINGS',
|
|
65
|
+
'business_checking' => 'CORPORATE_CHECKING',
|
|
66
|
+
'business_savings' => 'CORPORATE_SAVINGS'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
STATE_CODE_COUNTRIES = %w(US CA)
|
|
70
|
+
|
|
62
71
|
def initialize(options={})
|
|
63
72
|
requires!(options, :api_username, :api_password)
|
|
64
73
|
super
|
|
65
74
|
end
|
|
66
75
|
|
|
67
76
|
def purchase(money, payment_method, options={})
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
payment_method_details = PaymentMethodDetails.new(payment_method)
|
|
78
|
+
|
|
79
|
+
commit(:purchase, :post, payment_method_details) do |doc|
|
|
80
|
+
if payment_method_details.alt_transaction?
|
|
81
|
+
add_alt_transaction_purchase(doc, money, payment_method_details, options)
|
|
82
|
+
else
|
|
83
|
+
add_auth_purchase(doc, money, payment_method, options)
|
|
84
|
+
end
|
|
70
85
|
end
|
|
71
86
|
end
|
|
72
87
|
|
|
@@ -80,6 +95,7 @@ module ActiveMerchant
|
|
|
80
95
|
commit(:capture, :put) do |doc|
|
|
81
96
|
add_authorization(doc, authorization)
|
|
82
97
|
add_order(doc, options)
|
|
98
|
+
add_amount(doc, money, options) if options[:include_capture_amount] == true
|
|
83
99
|
end
|
|
84
100
|
end
|
|
85
101
|
|
|
@@ -102,18 +118,33 @@ module ActiveMerchant
|
|
|
102
118
|
authorize(0, payment_method, options)
|
|
103
119
|
end
|
|
104
120
|
|
|
105
|
-
def store(
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
def store(payment_method, options = {})
|
|
122
|
+
payment_method_details = PaymentMethodDetails.new(payment_method)
|
|
123
|
+
|
|
124
|
+
commit(:store, :post, payment_method_details) do |doc|
|
|
125
|
+
add_personal_info(doc, payment_method, options)
|
|
126
|
+
add_echeck_company(doc, payment_method) if payment_method_details.check?
|
|
108
127
|
doc.send('payment-sources') do
|
|
109
|
-
|
|
110
|
-
add_credit_card(doc, credit_card)
|
|
111
|
-
end
|
|
128
|
+
payment_method_details.check? ? store_echeck(doc, payment_method) : store_credit_card(doc, payment_method)
|
|
112
129
|
end
|
|
113
130
|
add_order(doc, options)
|
|
114
131
|
end
|
|
115
132
|
end
|
|
116
133
|
|
|
134
|
+
def store_credit_card(doc, payment_method)
|
|
135
|
+
doc.send('credit-card-info') do
|
|
136
|
+
add_credit_card(doc, payment_method)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def store_echeck(doc, payment_method)
|
|
141
|
+
doc.send('ecp-info') do
|
|
142
|
+
doc.send('ecp') do
|
|
143
|
+
add_echeck(doc, payment_method)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
117
148
|
def verify_credentials
|
|
118
149
|
begin
|
|
119
150
|
ssl_get(url.to_s, headers)
|
|
@@ -132,7 +163,9 @@ module ActiveMerchant
|
|
|
132
163
|
transcript.
|
|
133
164
|
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
|
134
165
|
gsub(%r((<card-number>).+(</card-number>)), '\1[FILTERED]\2').
|
|
135
|
-
gsub(%r((<security-code>).+(</security-code>)), '\1[FILTERED]\2')
|
|
166
|
+
gsub(%r((<security-code>).+(</security-code>)), '\1[FILTERED]\2').
|
|
167
|
+
gsub(%r((<(?:public-)?account-number>).+(</(?:public-)?account-number>)), '\1[FILTERED]\2').
|
|
168
|
+
gsub(%r((<(?:public-)?routing-number>).+(</(?:public-)?routing-number>)), '\1[FILTERED]\2')
|
|
136
169
|
end
|
|
137
170
|
|
|
138
171
|
private
|
|
@@ -140,11 +173,9 @@ module ActiveMerchant
|
|
|
140
173
|
def add_auth_purchase(doc, money, payment_method, options)
|
|
141
174
|
doc.send('recurring-transaction', options[:recurring] ? 'RECURRING' : 'ECOMMERCE')
|
|
142
175
|
add_order(doc, options)
|
|
143
|
-
doc.send('
|
|
176
|
+
doc.send('store-card', options[:store_card] || false)
|
|
144
177
|
add_amount(doc, money, options)
|
|
145
|
-
doc
|
|
146
|
-
doc.send('shopper-ip-address', options[:ip]) if options[:ip]
|
|
147
|
-
end
|
|
178
|
+
add_fraud_info(doc, options)
|
|
148
179
|
|
|
149
180
|
if payment_method.is_a?(String)
|
|
150
181
|
doc.send('vaulted-shopper-id', payment_method)
|
|
@@ -161,9 +192,10 @@ module ActiveMerchant
|
|
|
161
192
|
doc.currency(options[:currency] || currency(money))
|
|
162
193
|
end
|
|
163
194
|
|
|
164
|
-
def add_personal_info(doc,
|
|
165
|
-
doc.send('first-name',
|
|
166
|
-
doc.send('last-name',
|
|
195
|
+
def add_personal_info(doc, payment_method, options)
|
|
196
|
+
doc.send('first-name', payment_method.first_name)
|
|
197
|
+
doc.send('last-name', payment_method.last_name)
|
|
198
|
+
doc.send('personal-identification-number', options[:personal_identification_number]) if options[:personal_identification_number]
|
|
167
199
|
doc.email(options[:email]) if options[:email]
|
|
168
200
|
add_address(doc, options)
|
|
169
201
|
end
|
|
@@ -191,6 +223,8 @@ module ActiveMerchant
|
|
|
191
223
|
doc.send('merchant-transaction-id', truncate(options[:order_id], 50)) if options[:order_id]
|
|
192
224
|
doc.send('soft-descriptor', options[:soft_descriptor]) if options[:soft_descriptor]
|
|
193
225
|
add_description(doc, options[:description]) if options[:description]
|
|
226
|
+
add_3ds(doc, options[:three_d_secure]) if options[:three_d_secure]
|
|
227
|
+
add_level_3_data(doc, options)
|
|
194
228
|
end
|
|
195
229
|
|
|
196
230
|
def add_address(doc, options)
|
|
@@ -198,16 +232,114 @@ module ActiveMerchant
|
|
|
198
232
|
return unless address
|
|
199
233
|
|
|
200
234
|
doc.country(address[:country]) if address[:country]
|
|
201
|
-
doc.state(address[:state]) if address[:state]
|
|
235
|
+
doc.state(address[:state]) if address[:state] && STATE_CODE_COUNTRIES.include?(address[:country])
|
|
202
236
|
doc.address(address[:address]) if address[:address]
|
|
203
237
|
doc.city(address[:city]) if address[:city]
|
|
204
238
|
doc.zip(address[:zip]) if address[:zip]
|
|
205
239
|
end
|
|
206
240
|
|
|
241
|
+
def add_3ds(doc, three_d_secure_options)
|
|
242
|
+
eci = three_d_secure_options[:eci]
|
|
243
|
+
cavv = three_d_secure_options[:cavv]
|
|
244
|
+
xid = three_d_secure_options[:xid]
|
|
245
|
+
ds_transaction_id = three_d_secure_options[:ds_transaction_id]
|
|
246
|
+
version = three_d_secure_options[:version]
|
|
247
|
+
|
|
248
|
+
doc.send('three-d-secure') do
|
|
249
|
+
doc.eci(eci) if eci
|
|
250
|
+
doc.cavv(cavv) if cavv
|
|
251
|
+
doc.xid(xid) if xid
|
|
252
|
+
doc.send('three-d-secure-version', version) if version
|
|
253
|
+
doc.send('ds-transaction-id', ds_transaction_id) if ds_transaction_id
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def add_level_3_data(doc, options)
|
|
258
|
+
return unless options[:customer_reference_number]
|
|
259
|
+
doc.send('level-3-data') do
|
|
260
|
+
send_when_present(doc, :customer_reference_number, options)
|
|
261
|
+
send_when_present(doc, :sales_tax_amount, options)
|
|
262
|
+
send_when_present(doc, :freight_amount, options)
|
|
263
|
+
send_when_present(doc, :duty_amount, options)
|
|
264
|
+
send_when_present(doc, :destination_zip_code, options)
|
|
265
|
+
send_when_present(doc, :destination_country_code, options)
|
|
266
|
+
send_when_present(doc, :ship_from_zip_code, options)
|
|
267
|
+
send_when_present(doc, :discount_amount, options)
|
|
268
|
+
send_when_present(doc, :tax_amount, options)
|
|
269
|
+
send_when_present(doc, :tax_rate, options)
|
|
270
|
+
add_level_3_data_items(doc, options[:level_3_data_items]) if options[:level_3_data_items]
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def send_when_present(doc, options_key, options, xml_element_name = nil)
|
|
275
|
+
return unless options[options_key]
|
|
276
|
+
xml_element_name ||= options_key.to_s
|
|
277
|
+
|
|
278
|
+
doc.send(xml_element_name.dasherize, options[options_key])
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def add_level_3_data_items(doc, items)
|
|
282
|
+
items.each do |item|
|
|
283
|
+
doc.send('level-3-data-item') do
|
|
284
|
+
item.each do |key, value|
|
|
285
|
+
key = key.to_s.dasherize
|
|
286
|
+
doc.send(key, value)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
207
292
|
def add_authorization(doc, authorization)
|
|
208
293
|
doc.send('transaction-id', authorization)
|
|
209
294
|
end
|
|
210
295
|
|
|
296
|
+
def add_fraud_info(doc, options)
|
|
297
|
+
doc.send('transaction-fraud-info') do
|
|
298
|
+
doc.send('shopper-ip-address', options[:ip]) if options[:ip]
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def add_alt_transaction_purchase(doc, money, payment_method_details, options)
|
|
303
|
+
doc.send('merchant-transaction-id', truncate(options[:order_id], 50)) if options[:order_id]
|
|
304
|
+
doc.send('soft-descriptor', options[:soft_descriptor]) if options[:soft_descriptor]
|
|
305
|
+
add_amount(doc, money, options)
|
|
306
|
+
|
|
307
|
+
vaulted_shopper_id = payment_method_details.vaulted_shopper_id
|
|
308
|
+
doc.send('vaulted-shopper-id', vaulted_shopper_id) if vaulted_shopper_id
|
|
309
|
+
|
|
310
|
+
if payment_method_details.check?
|
|
311
|
+
add_echeck_transaction(doc, payment_method_details.payment_method, options, vaulted_shopper_id.present?)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
add_fraud_info(doc, options)
|
|
315
|
+
add_description(doc, options)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def add_echeck_transaction(doc, check, options, vaulted_shopper)
|
|
319
|
+
unless vaulted_shopper
|
|
320
|
+
doc.send('payer-info') do
|
|
321
|
+
add_personal_info(doc, check, options)
|
|
322
|
+
add_echeck_company(doc, check)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
doc.send('ecp-transaction') do
|
|
327
|
+
add_echeck(doc, check) unless vaulted_shopper
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
doc.send('authorized-by-shopper', options[:authorized_by_shopper])
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def add_echeck_company(doc, check)
|
|
334
|
+
doc.send('company-name', truncate(check.name, 50)) if check.account_holder_type = 'business'
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def add_echeck(doc, check)
|
|
338
|
+
doc.send('account-number', check.account_number)
|
|
339
|
+
doc.send('routing-number', check.routing_number)
|
|
340
|
+
doc.send('account-type', BANK_ACCOUNT_TYPE_MAPPING["#{check.account_holder_type}_#{check.account_type}"])
|
|
341
|
+
end
|
|
342
|
+
|
|
211
343
|
def parse(response)
|
|
212
344
|
return bad_authentication_response if response.code.to_i == 401
|
|
213
345
|
return forbidden_response(response.body) if response.code.to_i == 403
|
|
@@ -236,15 +368,15 @@ module ActiveMerchant
|
|
|
236
368
|
end
|
|
237
369
|
end
|
|
238
370
|
|
|
239
|
-
def api_request(action, request, verb)
|
|
240
|
-
ssl_request(verb, url(action), request, headers)
|
|
371
|
+
def api_request(action, request, verb, payment_method_details)
|
|
372
|
+
ssl_request(verb, url(action, payment_method_details), request, headers)
|
|
241
373
|
rescue ResponseError => e
|
|
242
374
|
e.response
|
|
243
375
|
end
|
|
244
376
|
|
|
245
|
-
def commit(action, verb = :post)
|
|
246
|
-
request = build_xml_request(action) { |doc| yield(doc) }
|
|
247
|
-
response = api_request(action, request, verb)
|
|
377
|
+
def commit(action, verb = :post, payment_method_details = PaymentMethodDetails.new())
|
|
378
|
+
request = build_xml_request(action, payment_method_details) { |doc| yield(doc) }
|
|
379
|
+
response = api_request(action, request, verb, payment_method_details)
|
|
248
380
|
parsed = parse(response)
|
|
249
381
|
|
|
250
382
|
succeeded = success_from(action, response)
|
|
@@ -252,7 +384,7 @@ module ActiveMerchant
|
|
|
252
384
|
succeeded,
|
|
253
385
|
message_from(succeeded, parsed),
|
|
254
386
|
parsed,
|
|
255
|
-
authorization: authorization_from(action, parsed),
|
|
387
|
+
authorization: authorization_from(action, parsed, payment_method_details),
|
|
256
388
|
avs_result: avs_result(parsed),
|
|
257
389
|
cvv_result: cvv_result(parsed),
|
|
258
390
|
error_code: error_code_from(parsed),
|
|
@@ -260,9 +392,9 @@ module ActiveMerchant
|
|
|
260
392
|
)
|
|
261
393
|
end
|
|
262
394
|
|
|
263
|
-
def url(action = nil)
|
|
395
|
+
def url(action = nil, payment_method_details = PaymentMethodDetails.new())
|
|
264
396
|
base = test? ? test_url : live_url
|
|
265
|
-
resource = action == :store ? 'vaulted-shoppers' :
|
|
397
|
+
resource = action == :store ? 'vaulted-shoppers' : payment_method_details.resource_url
|
|
266
398
|
"#{base}/#{resource}"
|
|
267
399
|
end
|
|
268
400
|
|
|
@@ -287,13 +419,15 @@ module ActiveMerchant
|
|
|
287
419
|
parsed_response['description']
|
|
288
420
|
end
|
|
289
421
|
|
|
290
|
-
def authorization_from(action, parsed_response)
|
|
291
|
-
action == :store ? vaulted_shopper_id(parsed_response) : parsed_response['transaction-id']
|
|
422
|
+
def authorization_from(action, parsed_response, payment_method_details)
|
|
423
|
+
action == :store ? vaulted_shopper_id(parsed_response, payment_method_details) : parsed_response['transaction-id']
|
|
292
424
|
end
|
|
293
425
|
|
|
294
|
-
def vaulted_shopper_id(parsed_response)
|
|
426
|
+
def vaulted_shopper_id(parsed_response, payment_method_details)
|
|
295
427
|
return nil unless parsed_response['content-location-header']
|
|
296
|
-
parsed_response['content-location-header'].split('/').last
|
|
428
|
+
vaulted_shopper_id = parsed_response['content-location-header'].split('/').last
|
|
429
|
+
vaulted_shopper_id += "|#{payment_method_details.payment_method_type}" if payment_method_details.alt_transaction?
|
|
430
|
+
vaulted_shopper_id
|
|
297
431
|
end
|
|
298
432
|
|
|
299
433
|
def error_code_from(parsed_response)
|
|
@@ -306,8 +440,8 @@ module ActiveMerchant
|
|
|
306
440
|
}
|
|
307
441
|
end
|
|
308
442
|
|
|
309
|
-
def root_element(action)
|
|
310
|
-
action == :store ? 'vaulted-shopper' :
|
|
443
|
+
def root_element(action, payment_method_details)
|
|
444
|
+
action == :store ? 'vaulted-shopper' : payment_method_details.root_element
|
|
311
445
|
end
|
|
312
446
|
|
|
313
447
|
def headers
|
|
@@ -317,10 +451,10 @@ module ActiveMerchant
|
|
|
317
451
|
}
|
|
318
452
|
end
|
|
319
453
|
|
|
320
|
-
def build_xml_request(action)
|
|
454
|
+
def build_xml_request(action, payment_method_details)
|
|
321
455
|
builder = Nokogiri::XML::Builder.new
|
|
322
|
-
builder.__send__(root_element(action), root_attributes) do |doc|
|
|
323
|
-
doc.send('card-transaction-type', TRANSACTIONS[action]) if TRANSACTIONS[action]
|
|
456
|
+
builder.__send__(root_element(action, payment_method_details), root_attributes) do |doc|
|
|
457
|
+
doc.send('card-transaction-type', TRANSACTIONS[action]) if TRANSACTIONS[action] && !payment_method_details.alt_transaction?
|
|
324
458
|
yield(doc)
|
|
325
459
|
end
|
|
326
460
|
builder.doc.root.to_xml
|
|
@@ -343,5 +477,46 @@ module ActiveMerchant
|
|
|
343
477
|
{ 'description' => body }
|
|
344
478
|
end
|
|
345
479
|
end
|
|
480
|
+
|
|
481
|
+
class PaymentMethodDetails
|
|
482
|
+
attr_reader :payment_method, :vaulted_shopper_id, :payment_method_type
|
|
483
|
+
|
|
484
|
+
def initialize(payment_method = nil)
|
|
485
|
+
@payment_method = payment_method
|
|
486
|
+
@payment_method_type = nil
|
|
487
|
+
parse(payment_method)
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def check?
|
|
491
|
+
@payment_method.is_a?(Check) || @payment_method_type == 'check'
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
def alt_transaction?
|
|
495
|
+
check?
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def root_element
|
|
499
|
+
alt_transaction? ? 'alt-transaction' : 'card-transaction'
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def resource_url
|
|
503
|
+
alt_transaction? ? 'alt-transactions' : 'transactions'
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
private
|
|
507
|
+
|
|
508
|
+
def parse(payment_method)
|
|
509
|
+
return unless payment_method
|
|
510
|
+
|
|
511
|
+
if payment_method.is_a?(String)
|
|
512
|
+
@vaulted_shopper_id, payment_method_type = payment_method.split('|')
|
|
513
|
+
@payment_method_type = payment_method_type if payment_method_type.present?
|
|
514
|
+
elsif payment_method.is_a?(Check)
|
|
515
|
+
@payment_method_type = payment_method.type
|
|
516
|
+
else
|
|
517
|
+
@payment_method_type = 'credit_card'
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
end
|
|
346
521
|
end
|
|
347
522
|
end
|
|
@@ -163,10 +163,10 @@ module ActiveMerchant #:nodoc:
|
|
|
163
163
|
xml.send('PaymentType', payment_type)
|
|
164
164
|
xml.send('TxnType', 'WEB_SHOP')
|
|
165
165
|
xml.send('BillerCode', options.fetch(:biller_code, ''))
|
|
166
|
-
xml.send('MerchantReference',
|
|
167
|
-
xml.send('CRN1',
|
|
168
|
-
xml.send('CRN2',
|
|
169
|
-
xml.send('CRN3',
|
|
166
|
+
xml.send('MerchantReference', options[:order_id]) if options[:order_id]
|
|
167
|
+
xml.send('CRN1', options[:crn1]) if options[:crn1]
|
|
168
|
+
xml.send('CRN2', options[:crn2]) if options[:crn2]
|
|
169
|
+
xml.send('CRN3', options[:crn3]) if options[:crn3]
|
|
170
170
|
xml.send('Amount', amount)
|
|
171
171
|
end
|
|
172
172
|
|