activemerchant 1.95.0 → 1.96.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 +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
|