activemerchant 1.95.0 → 1.96.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +45 -0
  3. data/README.md +3 -0
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +2 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +14 -0
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +19 -6
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +39 -10
  10. data/lib/active_merchant/billing/gateways/blue_snap.rb +4 -1
  11. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  12. data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -1
  13. data/lib/active_merchant/billing/gateways/card_connect.rb +1 -0
  14. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
  15. data/lib/active_merchant/billing/gateways/checkout_v2.rb +24 -24
  16. data/lib/active_merchant/billing/gateways/credorax.rb +29 -3
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +2 -2
  18. data/lib/active_merchant/billing/gateways/decidir.rb +232 -0
  19. data/lib/active_merchant/billing/gateways/global_collect.rb +2 -6
  20. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  21. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  23. data/lib/active_merchant/billing/gateways/mundipagg.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  25. data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
  26. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  27. data/lib/active_merchant/billing/gateways/payflow.rb +40 -2
  28. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  29. data/lib/active_merchant/billing/gateways/realex.rb +11 -5
  30. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  31. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
  32. data/lib/active_merchant/billing/gateways/trust_commerce.rb +24 -5
  33. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
  34. data/lib/active_merchant/billing/gateways/worldpay.rb +157 -37
  35. data/lib/active_merchant/country.rb +1 -0
  36. data/lib/active_merchant/version.rb +1 -1
  37. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0af5c8a759df2f80d48246fe7d1c71bff144e2e4916ccf47aad3a96f79820f79
4
- data.tar.gz: 5f2865f068ee003ea07f304f64894800ed870f32020b71f73c06e3d422508f1c
3
+ metadata.gz: 7e6a20c62ca88a52c155c0d8f3f33e7a6469e93b8bfb1734dcca624d65277143
4
+ data.tar.gz: b715b562b0d1d59cc77379fd288ee88fe7756df860f2d8e28337b023ecf46f30
5
5
  SHA512:
6
- metadata.gz: 7b341fa74b52b79347fc60ab22e3953616ff0cba341f1564b39f0174c3821d241ae7d63e5965151d73d16d13a1fb40a2175c01b6b27a2d32355f6adc18b61f2f
7
- data.tar.gz: 119cece41b0a7c469be3df3c6db040d67de82f82c389fd3b5695300d361cdd37b0b70e2d1ad1e8604a61802b9e8dd3159fef92b158bdce35238c40a98157df47
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.wellsfargo.com/downloads/pdf/biz/merchant/visa_avs.pdf
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 5-digit and 9-digit postal code do not match.',
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[:state] || 'N/A'
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: amount(money),
236
- currency: options[:currency] || currency(money)
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: amount(money),
244
- currency: options[:currency] || currency(money)
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 = 'v30'
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) if options[:execute_threed]
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['avsResult']
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
- Hash[
214
- response.split('&').map do |x|
215
- key, val = x.split('=', 2)
216
- [key.split('.').last, CGI.unescape(val)]
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
- post[:additionalData] = { executeThreeD: 'true' }
347
- post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
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]
@@ -233,6 +233,7 @@ module ActiveMerchant #:nodoc:
233
233
  item.each_pair do |k, v|
234
234
  updated.merge!(k.to_s.gsub(/_/, '') => v)
235
235
  end
236
+ updated
236
237
  end
237
238
  end
238
239
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class CecabankGateway < Gateway
4
- self.test_url = 'http://tpv.ceca.es:8000'
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 = 'SHA1'
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 = 'tpvanularparcialmente' # use partial refund's URL to avoid time frame limitations and decision logic on client side
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) + "/cgi-bin/#{action}"
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::SHA1.hexdigest(signature_fields)
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, :discover]
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, options={})
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(%r((Authorization: )[^\\]*)i, '\1[FILTERED]').
78
- gsub(%r(("number\\":\\")\d+), '\1[FILTERED]').
79
- gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]')
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(address && post[:source])
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] = options[:eci] if options[:eci]
136
- post[:'3ds'][:cryptogram] = options[:cavv] if options[:cavv]
137
- post[:'3ds'][:xid] = options[:xid] if options[:xid]
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(e.response.code.to_s =~ /4\d\d/)
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' => 'application/json;charset=UTF-8'
178
+ 'Content-Type' => 'application/json;charset=UTF-8',
179
179
  }
180
180
  end
181
181
 
182
- def url(post, action, authorization)
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["error_type"]}: #{response["error_codes"].join(", ")}"
251
+ "#{response['error_type']}: #{response['error_codes'].join(', ')}"
252
252
  elsif response['error_type']
253
253
  response['error_type']
254
254
  else