activemerchant 1.95.0 → 1.96.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +45 -0
- data/README.md +3 -0
- data/lib/active_merchant/billing/avs_result.rb +4 -5
- data/lib/active_merchant/billing/credit_card.rb +2 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +14 -0
- data/lib/active_merchant/billing/gateway.rb +10 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +19 -6
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +39 -10
- data/lib/active_merchant/billing/gateways/blue_snap.rb +4 -1
- data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -1
- data/lib/active_merchant/billing/gateways/card_connect.rb +1 -0
- data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +24 -24
- data/lib/active_merchant/billing/gateways/credorax.rb +29 -3
- data/lib/active_merchant/billing/gateways/cyber_source.rb +2 -2
- data/lib/active_merchant/billing/gateways/decidir.rb +232 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +2 -6
- data/lib/active_merchant/billing/gateways/hps.rb +46 -1
- data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +8 -0
- data/lib/active_merchant/billing/gateways/mundipagg.rb +1 -1
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
- data/lib/active_merchant/billing/gateways/opp.rb +20 -1
- data/lib/active_merchant/billing/gateways/payflow.rb +40 -2
- data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
- data/lib/active_merchant/billing/gateways/realex.rb +11 -5
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +24 -5
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
- data/lib/active_merchant/billing/gateways/worldpay.rb +157 -37
- data/lib/active_merchant/country.rb +1 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e6a20c62ca88a52c155c0d8f3f33e7a6469e93b8bfb1734dcca624d65277143
|
4
|
+
data.tar.gz: b715b562b0d1d59cc77379fd288ee88fe7756df860f2d8e28337b023ecf46f30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2853c5308ce93417b2efd259bf34a73d31055d52569bc64549306895b985cb80e2585de6941a51170f071b1057ec4265b54da13d25666ec260f72ace494881f
|
7
|
+
data.tar.gz: 248707f263ef74d7c6847d656de2413dd20f8d235cbb94aa9cad25a9d94f51df0eeb055e3ba28af1499822fa2302f7137097fd4addf8d07b14e341aea38b330f
|
data/CHANGELOG
CHANGED
@@ -2,6 +2,51 @@
|
|
2
2
|
|
3
3
|
== HEAD
|
4
4
|
|
5
|
+
== Version 1.96.0 (Jul 26, 2019)
|
6
|
+
* Bluesnap: Omit state codes for unsupported countries [therufs] #3229
|
7
|
+
* Adyen: Pass updateShopperStatement, industryUsage [curiousepic] #3233
|
8
|
+
* TransFirst Transaction Express: Fix blank address2 values [britth] #3231
|
9
|
+
* WorldPay: Add support for store method [bayprogrammer] #3232
|
10
|
+
* Adyen: Support for additional AVS code mapping [jknipp] #3236
|
11
|
+
* Adyen: Update message for AVS result code 'A' to generically cover postal code mismatches [jknipp] #3237
|
12
|
+
* CyberSource: Update CyberSource SOAP documentation link [vince-smith] #3204
|
13
|
+
* USAePay: Handle additional error codes and add default error code [estelendur] #3167
|
14
|
+
* Braintree: Add `skip_avs` and `skip_cvv` gateway specific fields [leila-alderman] #3241
|
15
|
+
* NAB Transact: Update periodic test url [mengqing] #3177
|
16
|
+
* NMI: Add level 3 gateway-specific fields tax, shipping, and ponumber [jasonxp] #3239
|
17
|
+
* Checkout V2: Update stored card flag [curiousepic] #3247
|
18
|
+
* NMI: Add support for stored credentials [bayprogrammer] #3243
|
19
|
+
* Spreedly: Consolidate API requests and support bank accounts [lancecarlson] #3105
|
20
|
+
* BPoint: Hook up merchant_reference and CRN fields [curiousepic] #3249
|
21
|
+
* Checkout V2: Stop sending phone number to Checkout V2 integration [filipebarcos] #3248
|
22
|
+
* Barclaycard Smartpay: Add support for 3DS2 [britth] #3251
|
23
|
+
* Adyen: Add support for non-fractional currencies [molbrown] #3257
|
24
|
+
* Decidir: Add new gateway [jknipp] #3254
|
25
|
+
* Checkout V2: Reapply Update stored card flag [curiousepic]
|
26
|
+
* CyberSource: Update supported countries [molbrown] #3260
|
27
|
+
* Credorax: Update supported countries [molbrown] #3260
|
28
|
+
* Kushki: Update supported countries [molbrown] #3260
|
29
|
+
* Paypal: Update supported countries [molbrown] #3260
|
30
|
+
* BlueSnap: Send amount in capture requests [jknipp] #3262
|
31
|
+
* Mundipagg: Add Alelo card support [jasonxp] #3255
|
32
|
+
* Adyen: Remove temporary amount modification for non-fractional currencies [molbrown] #3263
|
33
|
+
* Adyen: Set blank state to N/A [therufs] #3252
|
34
|
+
* MiGS: Add tx_source gateway specific field [leila-alderman] #3264
|
35
|
+
* NMI: Correct password scrubber to scrub symbols [hdeters] #3267
|
36
|
+
* Global Collect: Only add name if present [curiousepic] #3268
|
37
|
+
* HPS: Add Apple Pay raw cryptogram support [slogsdon] #3209
|
38
|
+
* CardConnect: Fix parsing of level 3 fields [hdeters] #3273
|
39
|
+
* TrustCommerce: Support void after purchase [jknipp] #3265
|
40
|
+
* Payflow: Support arbitrary level 2 + level 3 fields [therufs] #3272
|
41
|
+
* BlueSnap: Default to not send amount on capture [molbrown] #3270
|
42
|
+
* Spreedly: extra fields, remove extraneous check [montdidier] #3102 #3281
|
43
|
+
* Cecabank: Update encryption to SHA2 [leila-alderman] #3278
|
44
|
+
* Checkout V2: Fix 3DS 1&2 integration [nicolas-maalouf-cko] #3240
|
45
|
+
* Credorax: add 3DS2 MPI auth data support [bayprogrammer] #3274
|
46
|
+
* Add Kosovo to the list of countries [AnotherJoSmith] #3226
|
47
|
+
* Realex: Adds 3DS 1&2 support through external MPI [filipebarcos] #3284
|
48
|
+
* PayPal: Adds 3DS 1 support through external MPI [nebdil] #3279
|
49
|
+
|
5
50
|
== Version 1.95.0 (May 23, 2019)
|
6
51
|
* Adyen: Constantize version to fix subdomains [curiousepic] #3228
|
7
52
|
* Qvalent: Adds support for standard stored credential framework [molbrown] #3227
|
data/README.md
CHANGED
@@ -84,6 +84,9 @@ end
|
|
84
84
|
For more in-depth documentation and tutorials, see [GettingStarted.md](GettingStarted.md) and the
|
85
85
|
[API documentation](http://www.rubydoc.info/github/activemerchant/active_merchant/).
|
86
86
|
|
87
|
+
Emerging ActiveMerchant 3DS conventions are documented in the [Contributing](https://github.com/activemerchant/active_merchant/wiki/Contributing#3ds-options)
|
88
|
+
guide and [Standardized 3DS Fields](https://github.com/activemerchant/active_merchant/wiki/Standardized-3DS-Fields) guide of the wiki.
|
89
|
+
|
87
90
|
## Supported Payment Gateways
|
88
91
|
|
89
92
|
The [ActiveMerchant Wiki](https://github.com/activemerchant/active_merchant/wikis) contains a [table of features supported by each gateway](https://github.com/activemerchant/active_merchant/wiki/Gateway-Feature-Matrix).
|
@@ -3,14 +3,13 @@
|
|
3
3
|
module ActiveMerchant
|
4
4
|
module Billing
|
5
5
|
# Implements the Address Verification System
|
6
|
-
# https://www.
|
6
|
+
# https://www.cybersource.com/developers/other_resources/quick_references/avs_results/.
|
7
7
|
# http://en.wikipedia.org/wiki/Address_Verification_System
|
8
|
-
# http://apps.cybersource.com/library/documentation/dev_guides/CC_Svcs_IG/html/app_avs_cvn_codes.htm#app_AVS_CVN_codes_7891_48375
|
9
|
-
# http://imgserver.skipjack.com/imgServer/5293710/AVS%20and%20CVV2.pdf
|
10
8
|
# http://www.emsecommerce.net/avs_cvv2_response_codes.htm
|
9
|
+
# https://www.cardfellow.com/blog/address-verification-service-avs/
|
11
10
|
class AVSResult
|
12
11
|
MESSAGES = {
|
13
|
-
'A' => 'Street address matches, but
|
12
|
+
'A' => 'Street address matches, but postal code does not match.',
|
14
13
|
'B' => 'Street address matches, but postal code not verified.',
|
15
14
|
'C' => 'Street address and postal code do not match.',
|
16
15
|
'D' => 'Street address and postal code match.',
|
@@ -23,7 +22,7 @@ module ActiveMerchant
|
|
23
22
|
'K' => 'Card member\'s name matches but billing address and billing postal code do not match.',
|
24
23
|
'L' => 'Card member\'s name and billing postal code match, but billing address does not match.',
|
25
24
|
'M' => 'Street address and postal code match.',
|
26
|
-
'N' => 'Street address and postal code do not match.',
|
25
|
+
'N' => 'Street address and postal code do not match. For American Express: Card member\'s name, street address and postal code do not match.',
|
27
26
|
'O' => 'Card member\'s name and billing address match, but billing postal code does not match.',
|
28
27
|
'P' => 'Postal code matches, but street address not verified.',
|
29
28
|
'Q' => 'Card member\'s name, billing address, and postal code match. Shipping information verified but chargeback protection not guaranteed.',
|
@@ -19,6 +19,7 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
# * Maestro
|
20
20
|
# * Forbrugsforeningen
|
21
21
|
# * Elo
|
22
|
+
# * Alelo
|
22
23
|
#
|
23
24
|
# For testing purposes, use the 'bogus' credit card brand. This skips the vast majority of
|
24
25
|
# validations, allowing you to focus on your core concerns until you're ready to be more concerned
|
@@ -90,6 +91,7 @@ module ActiveMerchant #:nodoc:
|
|
90
91
|
# * +'maestro'+
|
91
92
|
# * +'forbrugsforeningen'+
|
92
93
|
# * +'elo'+
|
94
|
+
# * +'alelo'+
|
93
95
|
#
|
94
96
|
# Or, if you wish to test your implementation, +'bogus'+.
|
95
97
|
#
|
@@ -6,6 +6,7 @@ module ActiveMerchant #:nodoc:
|
|
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
8
|
'elo' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), ELO_RANGES) },
|
9
|
+
'alelo' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), ALELO_RANGES) },
|
9
10
|
'discover' => ->(num) { num =~ /^(6011|65\d{2}|64[4-9]\d)\d{12,15}|(62\d{14,17})$/ },
|
10
11
|
'american_express' => ->(num) { num =~ /^3[47]\d{13}$/ },
|
11
12
|
'diners_club' => ->(num) { num =~ /^3(0[0-5]|[68]\d)\d{11}$/ },
|
@@ -79,6 +80,19 @@ module ActiveMerchant #:nodoc:
|
|
79
80
|
651652..651667, 651675..651678, 655000..655010, 655012..655015, 655051..655052, 655056..655057
|
80
81
|
]
|
81
82
|
|
83
|
+
# Alelo provides BIN ranges by e-mailing them out periodically.
|
84
|
+
# The BINs beginning with the digit 4 overlap with Visa's range of valid card numbers.
|
85
|
+
# By placing the 'alelo' entry in CARD_COMPANY_DETECTORS below the 'visa' entry, we
|
86
|
+
# identify these cards as Visa. This works because transactions with such cards will
|
87
|
+
# run on Visa rails.
|
88
|
+
ALELO_RANGES = [
|
89
|
+
402588..402588, 404347..404347, 405876..405876, 405882..405882, 405884..405884,
|
90
|
+
405886..405886, 430471..430471, 438061..438061, 438064..438064, 470063..470066,
|
91
|
+
496067..496067, 506699..506704, 506706..506706, 506713..506714, 506716..506716,
|
92
|
+
506749..506750, 506752..506752, 506754..506756, 506758..506762, 506764..506767,
|
93
|
+
506770..506771, 509015..509019, 509880..509882, 509884..509885, 509987..509988
|
94
|
+
]
|
95
|
+
|
82
96
|
def self.included(base)
|
83
97
|
base.extend(ClassMethods)
|
84
98
|
end
|
@@ -200,6 +200,16 @@ module ActiveMerchant #:nodoc:
|
|
200
200
|
false
|
201
201
|
end
|
202
202
|
|
203
|
+
def add_fields_to_post_if_present(post, options, fields)
|
204
|
+
fields.each do |field|
|
205
|
+
add_field_to_post_if_present(post, options, field)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def add_field_to_post_if_present(post, options, field)
|
210
|
+
post[field] = options[field] if options[field]
|
211
|
+
end
|
212
|
+
|
203
213
|
protected # :nodoc: all
|
204
214
|
|
205
215
|
def normalize(field)
|
@@ -9,6 +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.currencies_without_fractions = %w(CVE DJF GNF IDR JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
|
12
13
|
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover, :elo]
|
13
14
|
|
14
15
|
self.money_format = :cents
|
@@ -140,10 +141,14 @@ module ActiveMerchant #:nodoc:
|
|
140
141
|
'16' => 'N', # Postal code doesn't match, address unknown
|
141
142
|
'17' => 'U', # Postal code doesn't match, address not checked
|
142
143
|
'18' => 'I', # Neither postal code nor address were checked
|
144
|
+
'19' => 'L', # Name and postal code matches.
|
143
145
|
'20' => 'V', # Name, address and postal code matches.
|
146
|
+
'21' => 'O', # Name and address matches.
|
147
|
+
'22' => 'K', # Name matches.
|
144
148
|
'23' => 'F', # Postal code matches, name doesn't match.
|
145
149
|
'24' => 'H', # Both postal code and address matches, name doesn't match.
|
146
|
-
'25' => 'T' # Address matches, name doesn't match.
|
150
|
+
'25' => 'T', # Address matches, name doesn't match.
|
151
|
+
'26' => 'N' # Neither postal code, address nor name matches.
|
147
152
|
}
|
148
153
|
|
149
154
|
CVC_MAPPING = {
|
@@ -179,6 +184,8 @@ module ActiveMerchant #:nodoc:
|
|
179
184
|
post[:additionalData]['paymentdatasource.type'] = NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
|
180
185
|
post[:additionalData][:authorisationType] = options[:authorisation_type] if options[:authorisation_type]
|
181
186
|
post[:additionalData][:adjustAuthorisationData] = options[:adjust_authorisation_data] if options[:adjust_authorisation_data]
|
187
|
+
post[:additionalData][:industryUsage] = options[:industry_usage] if options[:industry_usage]
|
188
|
+
post[:additionalData][:updateShopperStatement] = options[:update_shopper_statement] if options[:update_shopper_statement]
|
182
189
|
post[:additionalData][:RequestedTestAcquirerResponseCode] = options[:requested_test_acquirer_response_code] if options[:requested_test_acquirer_response_code] && test?
|
183
190
|
post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
|
184
191
|
add_risk_data(post, options)
|
@@ -225,23 +232,29 @@ module ActiveMerchant #:nodoc:
|
|
225
232
|
post[:billingAddress][:houseNumberOrName] = address[:address2] || 'N/A'
|
226
233
|
post[:billingAddress][:postalCode] = address[:zip] if address[:zip]
|
227
234
|
post[:billingAddress][:city] = address[:city] || 'N/A'
|
228
|
-
post[:billingAddress][:stateOrProvince] = address
|
235
|
+
post[:billingAddress][:stateOrProvince] = get_state(address)
|
229
236
|
post[:billingAddress][:country] = address[:country] if address[:country]
|
230
237
|
end
|
231
238
|
end
|
232
239
|
|
240
|
+
def get_state(address)
|
241
|
+
address[:state] && !address[:state].blank? ? address[:state] : 'N/A'
|
242
|
+
end
|
243
|
+
|
233
244
|
def add_invoice(post, money, options)
|
245
|
+
currency = options[:currency] || currency(money)
|
234
246
|
amount = {
|
235
|
-
value:
|
236
|
-
currency:
|
247
|
+
value: localized_amount(money, currency),
|
248
|
+
currency: currency
|
237
249
|
}
|
238
250
|
post[:amount] = amount
|
239
251
|
end
|
240
252
|
|
241
253
|
def add_invoice_for_modification(post, money, options)
|
254
|
+
currency = options[:currency] || currency(money)
|
242
255
|
amount = {
|
243
|
-
value:
|
244
|
-
currency:
|
256
|
+
value: localized_amount(money, currency),
|
257
|
+
currency: currency
|
245
258
|
}
|
246
259
|
post[:modificationAmount] = amount
|
247
260
|
end
|
@@ -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,7 @@ 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
|
-
add_3ds(post, options)
|
40
|
+
add_3ds(post, options)
|
41
41
|
commit('authorise', post)
|
42
42
|
end
|
43
43
|
|
@@ -186,7 +186,7 @@ module ActiveMerchant #:nodoc:
|
|
186
186
|
end
|
187
187
|
|
188
188
|
def parse_avs_code(response)
|
189
|
-
AVS_MAPPING[response['avsResult'][0..1].strip] if response
|
189
|
+
AVS_MAPPING[response['additionalData']['avsResult'][0..1].strip] if response.dig('additionalData', 'avsResult')
|
190
190
|
end
|
191
191
|
|
192
192
|
def flatten_hash(hash, prefix = nil)
|
@@ -210,12 +210,18 @@ module ActiveMerchant #:nodoc:
|
|
210
210
|
end
|
211
211
|
|
212
212
|
def parse(response)
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
213
|
+
parsed_response = {}
|
214
|
+
params = CGI.parse(response)
|
215
|
+
params.each do |key, value|
|
216
|
+
parsed_key = key.split('.', 2)
|
217
|
+
if parsed_key.size > 1
|
218
|
+
parsed_response[parsed_key[0]] ||= {}
|
219
|
+
parsed_response[parsed_key[0]][parsed_key[1]] = value[0]
|
220
|
+
else
|
221
|
+
parsed_response[parsed_key[0]] = value[0]
|
217
222
|
end
|
218
|
-
|
223
|
+
end
|
224
|
+
parsed_response
|
219
225
|
end
|
220
226
|
|
221
227
|
def post_data(data)
|
@@ -343,8 +349,31 @@ module ActiveMerchant #:nodoc:
|
|
343
349
|
end
|
344
350
|
|
345
351
|
def add_3ds(post, options)
|
346
|
-
|
347
|
-
|
352
|
+
if three_ds_2_options = options[:three_ds_2]
|
353
|
+
if browser_info = three_ds_2_options[:browser_info]
|
354
|
+
post[:browserInfo] = {
|
355
|
+
acceptHeader: browser_info[:accept_header],
|
356
|
+
colorDepth: browser_info[:depth],
|
357
|
+
javaEnabled: browser_info[:java],
|
358
|
+
language: browser_info[:language],
|
359
|
+
screenHeight: browser_info[:height],
|
360
|
+
screenWidth: browser_info[:width],
|
361
|
+
timeZoneOffset: browser_info[:timezone],
|
362
|
+
userAgent: browser_info[:user_agent]
|
363
|
+
}
|
364
|
+
|
365
|
+
if device_channel = three_ds_2_options[:channel]
|
366
|
+
post[:threeDS2RequestData] = {
|
367
|
+
deviceChannel: device_channel,
|
368
|
+
notificationURL: three_ds_2_options[:notification_url]
|
369
|
+
}
|
370
|
+
end
|
371
|
+
end
|
372
|
+
else
|
373
|
+
return unless options[:execute_threed] || options[:threed_dynamic]
|
374
|
+
post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
|
375
|
+
post[:additionalData] = { executeThreeD: 'true' } if options[:execute_threed]
|
376
|
+
end
|
348
377
|
end
|
349
378
|
end
|
350
379
|
end
|
@@ -66,6 +66,8 @@ module ActiveMerchant
|
|
66
66
|
'business_savings' => 'CORPORATE_SAVINGS'
|
67
67
|
}
|
68
68
|
|
69
|
+
STATE_CODE_COUNTRIES = %w(US CA)
|
70
|
+
|
69
71
|
def initialize(options={})
|
70
72
|
requires!(options, :api_username, :api_password)
|
71
73
|
super
|
@@ -93,6 +95,7 @@ module ActiveMerchant
|
|
93
95
|
commit(:capture, :put) do |doc|
|
94
96
|
add_authorization(doc, authorization)
|
95
97
|
add_order(doc, options)
|
98
|
+
add_amount(doc, money, options) if options[:include_capture_amount] == true
|
96
99
|
end
|
97
100
|
end
|
98
101
|
|
@@ -228,7 +231,7 @@ module ActiveMerchant
|
|
228
231
|
return unless address
|
229
232
|
|
230
233
|
doc.country(address[:country]) if address[:country]
|
231
|
-
doc.state(address[:state]) if address[:state]
|
234
|
+
doc.state(address[:state]) if address[:state] && STATE_CODE_COUNTRIES.include?(address[:country])
|
232
235
|
doc.address(address[:address]) if address[:address]
|
233
236
|
doc.city(address[:city]) if address[:city]
|
234
237
|
doc.zip(address[:zip]) if address[:zip]
|
@@ -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
|
|
@@ -419,7 +419,9 @@ module ActiveMerchant #:nodoc:
|
|
419
419
|
'street: A, zip: N' => 'C',
|
420
420
|
'street: A, zip: U' => 'I',
|
421
421
|
'street: A, zip: I' => 'I',
|
422
|
-
'street: A, zip: A' => 'I'
|
422
|
+
'street: A, zip: A' => 'I',
|
423
|
+
|
424
|
+
'street: B, zip: B' => 'B'
|
423
425
|
}
|
424
426
|
end
|
425
427
|
|
@@ -590,6 +592,14 @@ module ActiveMerchant #:nodoc:
|
|
590
592
|
parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking]
|
591
593
|
end
|
592
594
|
|
595
|
+
if options[:skip_avs]
|
596
|
+
parameters[:options][:skip_avs] = options[:skip_avs]
|
597
|
+
end
|
598
|
+
|
599
|
+
if options[:skip_cvv]
|
600
|
+
parameters[:options][:skip_cvv] = options[:skip_cvv]
|
601
|
+
end
|
602
|
+
|
593
603
|
parameters[:custom_fields] = options[:custom_fields]
|
594
604
|
parameters[:device_data] = options[:device_data] if options[:device_data]
|
595
605
|
parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
3
|
class CecabankGateway < Gateway
|
4
|
-
self.test_url = '
|
4
|
+
self.test_url = 'https://tpv.ceca.es'
|
5
5
|
self.live_url = 'https://pgw.ceca.es'
|
6
6
|
|
7
7
|
self.supported_countries = ['ES']
|
@@ -13,14 +13,14 @@ module ActiveMerchant #:nodoc:
|
|
13
13
|
|
14
14
|
#### CECA's MAGIC NUMBERS
|
15
15
|
CECA_NOTIFICATIONS_URL = 'NONE'
|
16
|
-
CECA_ENCRIPTION = '
|
16
|
+
CECA_ENCRIPTION = 'SHA2'
|
17
17
|
CECA_DECIMALS = '2'
|
18
18
|
CECA_MODE = 'SSL'
|
19
19
|
CECA_UI_LESS_LANGUAGE = 'XML'
|
20
20
|
CECA_UI_LESS_LANGUAGE_REFUND = '1'
|
21
21
|
CECA_UI_LESS_REFUND_PAGE = 'anulacion_xml'
|
22
|
-
CECA_ACTION_REFUND = '
|
23
|
-
CECA_ACTION_PURCHASE = 'tpv'
|
22
|
+
CECA_ACTION_REFUND = 'anulaciones/anularParcial' # use partial refund's URL to avoid time frame limitations and decision logic on client side
|
23
|
+
CECA_ACTION_PURCHASE = 'tpv/compra'
|
24
24
|
CECA_CURRENCIES_DICTIONARY = {'EUR' => 978, 'USD' => 840, 'GBP' => 826}
|
25
25
|
|
26
26
|
# Creates a new CecabankGateway
|
@@ -168,8 +168,8 @@ module ActiveMerchant #:nodoc:
|
|
168
168
|
'AcquirerBIN' => options[:acquirer_bin],
|
169
169
|
'TerminalID' => options[:terminal_id]
|
170
170
|
)
|
171
|
-
url = (test? ? self.test_url : self.live_url) + "/
|
172
|
-
xml = ssl_post(url, post_data(parameters))
|
171
|
+
url = (test? ? self.test_url : self.live_url) + "/tpvweb/#{action}.action"
|
172
|
+
xml = ssl_post("#{url}?", post_data(parameters))
|
173
173
|
response = parse(xml)
|
174
174
|
Response.new(
|
175
175
|
response[:success],
|
@@ -242,7 +242,7 @@ module ActiveMerchant #:nodoc:
|
|
242
242
|
CECA_NOTIFICATIONS_URL +
|
243
243
|
CECA_NOTIFICATIONS_URL
|
244
244
|
end
|
245
|
-
Digest::
|
245
|
+
Digest::SHA2.hexdigest(signature_fields)
|
246
246
|
end
|
247
247
|
end
|
248
248
|
end
|
@@ -9,14 +9,14 @@ module ActiveMerchant #:nodoc:
|
|
9
9
|
self.supported_countries = ['AD', 'AE', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA']
|
10
10
|
self.default_currency = 'USD'
|
11
11
|
self.money_format = :cents
|
12
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :maestro,
|
12
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :maestro, :discover]
|
13
13
|
|
14
|
-
def initialize(options={})
|
14
|
+
def initialize(options = {})
|
15
15
|
requires!(options, :secret_key)
|
16
16
|
super
|
17
17
|
end
|
18
18
|
|
19
|
-
def purchase(amount, payment_method, options={})
|
19
|
+
def purchase(amount, payment_method, options = {})
|
20
20
|
multi = MultiResponse.run do |r|
|
21
21
|
r.process { authorize(amount, payment_method, options) }
|
22
22
|
r.process { capture(amount, r.authorization, options) }
|
@@ -28,11 +28,11 @@ module ActiveMerchant #:nodoc:
|
|
28
28
|
response(:purchase, succeeded, merged_params)
|
29
29
|
end
|
30
30
|
|
31
|
-
def authorize(amount, payment_method, options={})
|
31
|
+
def authorize(amount, payment_method, options = {})
|
32
32
|
post = {}
|
33
33
|
post[:capture] = false
|
34
34
|
add_invoice(post, amount, options)
|
35
|
-
add_payment_method(post, payment_method)
|
35
|
+
add_payment_method(post, payment_method, options)
|
36
36
|
add_customer_data(post, options)
|
37
37
|
add_transaction_data(post, options)
|
38
38
|
add_3ds(post, options)
|
@@ -40,7 +40,7 @@ module ActiveMerchant #:nodoc:
|
|
40
40
|
commit(:authorize, post)
|
41
41
|
end
|
42
42
|
|
43
|
-
def capture(amount, authorization, options={})
|
43
|
+
def capture(amount, authorization, options = {})
|
44
44
|
post = {}
|
45
45
|
add_invoice(post, amount, options)
|
46
46
|
add_customer_data(post, options)
|
@@ -48,12 +48,12 @@ module ActiveMerchant #:nodoc:
|
|
48
48
|
commit(:capture, post, authorization)
|
49
49
|
end
|
50
50
|
|
51
|
-
def void(authorization,
|
51
|
+
def void(authorization, _options = {})
|
52
52
|
post = {}
|
53
53
|
commit(:void, post, authorization)
|
54
54
|
end
|
55
55
|
|
56
|
-
def refund(amount, authorization, options={})
|
56
|
+
def refund(amount, authorization, options = {})
|
57
57
|
post = {}
|
58
58
|
add_invoice(post, amount, options)
|
59
59
|
add_customer_data(post, options)
|
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
|
|
61
61
|
commit(:refund, post, authorization)
|
62
62
|
end
|
63
63
|
|
64
|
-
def verify(credit_card, options={})
|
64
|
+
def verify(credit_card, options = {})
|
65
65
|
MultiResponse.run(:use_first_response) do |r|
|
66
66
|
r.process { authorize(100, credit_card, options) }
|
67
67
|
r.process(:ignore_result) { void(r.authorization, options) }
|
@@ -74,9 +74,9 @@ module ActiveMerchant #:nodoc:
|
|
74
74
|
|
75
75
|
def scrub(transcript)
|
76
76
|
transcript.
|
77
|
-
gsub(
|
78
|
-
gsub(
|
79
|
-
gsub(
|
77
|
+
gsub(/(Authorization: )[^\\]*/i, '\1[FILTERED]').
|
78
|
+
gsub(/("number\\":\\")\d+/, '\1[FILTERED]').
|
79
|
+
gsub(/("cvv\\":\\")\d+/, '\1[FILTERED]')
|
80
80
|
end
|
81
81
|
|
82
82
|
private
|
@@ -94,7 +94,7 @@ module ActiveMerchant #:nodoc:
|
|
94
94
|
post[:metadata][:udf5] = application_id || 'ActiveMerchant'
|
95
95
|
end
|
96
96
|
|
97
|
-
def add_payment_method(post, payment_method)
|
97
|
+
def add_payment_method(post, payment_method, options)
|
98
98
|
post[:source] = {}
|
99
99
|
post[:source][:type] = 'card'
|
100
100
|
post[:source][:name] = payment_method.name
|
@@ -102,6 +102,7 @@ module ActiveMerchant #:nodoc:
|
|
102
102
|
post[:source][:cvv] = payment_method.verification_value
|
103
103
|
post[:source][:expiry_year] = format(payment_method.year, :four_digits)
|
104
104
|
post[:source][:expiry_month] = format(payment_method.month, :two_digits)
|
105
|
+
post[:source][:stored] = 'true' if options[:card_on_file] == true
|
105
106
|
end
|
106
107
|
|
107
108
|
def add_customer_data(post, options)
|
@@ -109,7 +110,7 @@ module ActiveMerchant #:nodoc:
|
|
109
110
|
post[:customer][:email] = options[:email] || nil
|
110
111
|
post[:payment_ip] = options[:ip] if options[:ip]
|
111
112
|
address = options[:billing_address]
|
112
|
-
if
|
113
|
+
if address && post[:source]
|
113
114
|
post[:source][:billing_address] = {}
|
114
115
|
post[:source][:billing_address][:address_line1] = address[:address1] unless address[:address1].blank?
|
115
116
|
post[:source][:billing_address][:address_line2] = address[:address2] unless address[:address2].blank?
|
@@ -117,12 +118,10 @@ module ActiveMerchant #:nodoc:
|
|
117
118
|
post[:source][:billing_address][:state] = address[:state] unless address[:state].blank?
|
118
119
|
post[:source][:billing_address][:country] = address[:country] unless address[:country].blank?
|
119
120
|
post[:source][:billing_address][:zip] = address[:zip] unless address[:zip].blank?
|
120
|
-
post[:source][:phone] = { number: address[:phone] } unless address[:phone].blank?
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
-
def add_transaction_data(post, options={})
|
125
|
-
post[:card_on_file] = true if options[:card_on_file] == true
|
124
|
+
def add_transaction_data(post, options = {})
|
126
125
|
post[:payment_type] = 'Regular' if options[:transaction_indicator] == 1
|
127
126
|
post[:payment_type] = 'Recurring' if options[:transaction_indicator] == 2
|
128
127
|
post[:previous_payment_id] = options[:previous_charge_id] if options[:previous_charge_id]
|
@@ -132,9 +131,10 @@ module ActiveMerchant #:nodoc:
|
|
132
131
|
if options[:three_d_secure]
|
133
132
|
post[:'3ds'] = {}
|
134
133
|
post[:'3ds'][:enabled] = true
|
135
|
-
post[:'3ds'][:eci] =
|
136
|
-
post[:'3ds'][:cryptogram] =
|
137
|
-
post[:'3ds'][:
|
134
|
+
post[:'3ds'][:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
|
135
|
+
post[:'3ds'][:cryptogram] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
|
136
|
+
post[:'3ds'][:version] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
|
137
|
+
post[:'3ds'][:xid] = options[:three_d_secure][:ds_transaction_id] || options[:three_d_secure][:xid]
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
@@ -146,7 +146,7 @@ module ActiveMerchant #:nodoc:
|
|
146
146
|
response['id'] = response['_links']['payment']['href'].split('/')[-1]
|
147
147
|
end
|
148
148
|
rescue ResponseError => e
|
149
|
-
raise unless
|
149
|
+
raise unless e.response.code.to_s =~ /4\d\d/
|
150
150
|
response = parse(e.response.body)
|
151
151
|
end
|
152
152
|
|
@@ -175,11 +175,11 @@ module ActiveMerchant #:nodoc:
|
|
175
175
|
def headers
|
176
176
|
{
|
177
177
|
'Authorization' => @options[:secret_key],
|
178
|
-
'Content-Type'
|
178
|
+
'Content-Type' => 'application/json;charset=UTF-8',
|
179
179
|
}
|
180
180
|
end
|
181
181
|
|
182
|
-
def url(
|
182
|
+
def url(_post, action, authorization)
|
183
183
|
if action == :authorize
|
184
184
|
"#{base_url}/payments"
|
185
185
|
elsif action == :capture
|
@@ -248,7 +248,7 @@ module ActiveMerchant #:nodoc:
|
|
248
248
|
def error_code_from(succeeded, response)
|
249
249
|
return if succeeded
|
250
250
|
if response['error_type'] && response['error_codes']
|
251
|
-
"#{response[
|
251
|
+
"#{response['error_type']}: #{response['error_codes'].join(', ')}"
|
252
252
|
elsif response['error_type']
|
253
253
|
response['error_type']
|
254
254
|
else
|