activemerchant 1.48.0 → 1.49.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ff9f55a9e47319466b22c9d9826ffb0d9c2d8a7
4
- data.tar.gz: cfe3110700b68bb12392232759ed730376435e3b
3
+ metadata.gz: 5057426f88d783e8a04528d24fb75c31011eca30
4
+ data.tar.gz: de26a0e5fff0c27aad8a96bd8b832e7cd1c53c1f
5
5
  SHA512:
6
- metadata.gz: 7bce2c57e79a9683a0c2d6557290efef7e2315b317158a4eb302b081d9c5e56f28a5a6102b30d39bfdbfd15acb88134094b0a11b6ea5e79b6d66a6cc1373e4d0
7
- data.tar.gz: 22b1046d34bdbd344a06a9b6bd3917216b738da94ce79ed64b586c5f9a1c0ac9314bf6650f57dc2dfd30a03e34c272d0e83180444612a617cb84bef81412e458
6
+ metadata.gz: 4d4df9ee441a742077ebc2109758b58ad76e76668d3e4a4169bf778e365fe300d9b8a1f977abc95df6e606fcd1d09491344453c79055771d7ba2ef4f44a1a52b
7
+ data.tar.gz: fdc30b7c943d11a2f7e505f2f978615b27cb4816360a7e5cde48598f8d3ff72ef58df2feb39a93d77984c0a6e44def9f11fd80ae590487e35dcd19482e99e406
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- ��j����&��h� t�4�N
2
- ����#�-�%���kFdn./B„���V���ھ"k=AU��N��(��8x�ݔ6"/KY��ۿ�
3
- |���+�$������
1
+ 8
2
+ ���� |��XRa|�� YsE���qͻ�h�~� �O�َ!y��5�=��%51�tB�M�Pl��h?{�?�� �h�l8�$�s��ݮ�.@�v�adX��U�(x��ރ/�7Q��bO8��)�9Oa5�?]�f�~|&��h�13��.�o��[�5h X�h���7T%�: ,w������z��2e=-�V�Yi��rJ
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,28 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.49.0 (May 1, 2015)
4
+
5
+ * Braintree: Add support for AVS error codes [ivanvfer]
6
+ * MerchantWarrior: Truncate description field [duff]
7
+ * Braintree: Add service_fee_amount option [duff]
8
+ * SecureNet: Allow shipping_address[:name] [duff]
9
+ * MonerisUS: Add verify [mrezentes]
10
+ * Ezic: Add gateway [duff]
11
+ * Stripe: Add destination field [cwise]
12
+ * SecureNet: Fix ordering of shipping field names [duff]
13
+ * SecurePayAu: Update API URL [girasquid]
14
+ * Stripe: Add EMV "chip & sign", "chip & offline PIN" and Maestro support [bizla]
15
+ * Add Errno::EHOSTUNREACH to NetworkConnectionRetries::DEFAULT_CONNECTION_ERRORS [randito78]
16
+ * Stripe: Add support for idempotency keys [michaelherold]
17
+ * WePay: Handle JSON::ParserError exceptions [duff]
18
+ * Borgun: Update country list and homepage url [mrezentes]
19
+ * AuthorizeNet: Add cvv to request only if it's valid [tjstankus]
20
+ * Stripe: Bug fix: add amounts only on non-EMV transactions, temporarily omit EMV testcases [bizla]
21
+ * Ezic: Add support for void [duff]
22
+ * iATS: Update supported countries [mrezentes]
23
+ * Ezic: Update supported countries [duff]
24
+ * AuthorizeNet: Truncate card number [tjstankus]
25
+
3
26
  == Version 1.48.0 (April 8, 2015)
4
27
 
5
28
  * Clean up `rake gateways:hosts` output [ntalbott]
data/README.md CHANGED
@@ -115,6 +115,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
115
115
  * [eWAY](http://www.eway.com.au/) - AU, NZ, GB
116
116
  * [eWAY Rapid](http://www.eway.com.au/) - AU, NZ, GB, SG
117
117
  * [E-xact](http://www.e-xact.com) - CA, US
118
+ * [Ezic](http://www.ezic.com/) - AU, CA, CN, FR, DE, GI, IL, MT, MU, MX, NL, NZ, PA, PH, RU, SG, KR, ES, KN, GB
118
119
  * [Fat Zebra](https://www.fatzebra.com.au/) - AU
119
120
  * [Federated Canada](http://www.federatedcanada.com/) - CA
120
121
  * [Finansbank WebPOS](https://www.fbwebpos.com/) - US, TR
@@ -138,6 +138,17 @@ module ActiveMerchant #:nodoc:
138
138
  # @return [String]
139
139
  attr_accessor :track_data
140
140
 
141
+ # Returns or sets the ICC/ASN1 credit card data for a EMV transaction, typically this is a BER-encoded TLV string.
142
+ #
143
+ # @return [String]
144
+ attr_accessor :icc_data
145
+
146
+ # Returns or sets a fallback reason for a EMV transaction whereby the customer's card entered a fallback scenario.
147
+ # This can be an arbitrary string.
148
+ #
149
+ # @return [String]
150
+ attr_accessor :fallback_reason
151
+
141
152
  def type
142
153
  ActiveMerchant.deprecated "CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead."
143
154
  brand
@@ -253,6 +264,10 @@ module ActiveMerchant #:nodoc:
253
264
  require_name
254
265
  end
255
266
 
267
+ def emv?
268
+ icc_data.present?
269
+ end
270
+
256
271
  private
257
272
 
258
273
  def validate_essential_attributes #:nodoc:
@@ -3,7 +3,7 @@ module ActiveMerchant #:nodoc:
3
3
  # Convenience methods that can be included into a custom Credit Card object, such as an ActiveRecord based Credit Card object.
4
4
  module CreditCardMethods
5
5
  CARD_COMPANIES = {
6
- 'visa' => /^4\d{12}(\d{3})?$/,
6
+ 'visa' => /^4\d{12}(\d{3})?(\d{3})?$/,
7
7
  'master' => /^(5[1-5]\d{4}|677189)\d{10}$/,
8
8
  'discover' => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/,
9
9
  'american_express' => /^3[47]\d{13}$/,
@@ -49,11 +49,11 @@ module ActiveMerchant #:nodoc:
49
49
  def valid_card_verification_value?(cvv, brand)
50
50
  cvv.to_s =~ /^\d{#{card_verification_value_length(brand)}}$/
51
51
  end
52
-
52
+
53
53
  def card_verification_value_length(brand)
54
54
  brand == 'american_express' ? 4 : 3
55
55
  end
56
-
56
+
57
57
  def valid_issue_number?(number)
58
58
  (number.to_s =~ /^\d{1,2}$/)
59
59
  end
@@ -254,6 +254,11 @@ module ActiveMerchant #:nodoc:
254
254
  money.respond_to?(:currency) ? money.currency : self.default_currency
255
255
  end
256
256
 
257
+ def truncate(value, max_size)
258
+ return nil unless value
259
+ value.to_s[0, max_size]
260
+ end
261
+
257
262
  def requires_start_date_or_issue_number?(credit_card)
258
263
  return false if card_brand(credit_card).blank?
259
264
  DEBIT_CARDS.include?(card_brand(credit_card).to_sym)
@@ -22,7 +22,7 @@ module ActiveMerchant #:nodoc:
22
22
  '2315' => STANDARD_ERROR_CODE[:invalid_number],
23
23
  '37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
24
24
  '2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
25
- '378' => STANDARD_ERROR_CODE[:invalid_cvc],
25
+ '378' => STANDARD_ERROR_CODE[:invalid_cvc],
26
26
  '38' => STANDARD_ERROR_CODE[:expired_card],
27
27
  '2317' => STANDARD_ERROR_CODE[:expired_card],
28
28
  '244' => STANDARD_ERROR_CODE[:incorrect_cvc],
@@ -232,9 +232,9 @@ module ActiveMerchant #:nodoc:
232
232
  else
233
233
  xml.payment do
234
234
  xml.creditCard do
235
- xml.cardNumber(credit_card.number)
235
+ xml.cardNumber(truncate(credit_card.number, 16))
236
236
  xml.expirationDate(format(credit_card.month, :two_digits) + '/' + format(credit_card.year, :four_digits))
237
- unless empty?(credit_card.verification_value)
237
+ if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand)
238
238
  xml.cardCode(credit_card.verification_value)
239
239
  end
240
240
  if credit_card.is_a?(NetworkTokenizationCreditCard)
@@ -486,10 +486,6 @@ module ActiveMerchant #:nodoc:
486
486
  (response[:response_code] == FRAUD_REVIEW)
487
487
  end
488
488
 
489
- def truncate(value, max_size)
490
- return nil unless value
491
- value.to_s[0, max_size]
492
- end
493
489
 
494
490
  def using_live_gateway_in_test_mode?(response)
495
491
  !test? && response[:test_request] == "1"
@@ -4,11 +4,12 @@ module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
5
5
  class BorgunGateway < Gateway
6
6
  self.display_name = "Borgun"
7
+ self.homepage_url = 'http://www.borgun.com'
7
8
 
8
9
  self.test_url = 'https://gatewaytest.borgun.is/ws/Heimir.pub.ws:Authorization'
9
10
  self.live_url = 'https://gateway01.borgun.is/ws/Heimir.pub.ws:Authorization'
10
11
 
11
- self.supported_countries = ['IS']
12
+ self.supported_countries = ['IS', 'GB', 'HU', 'CZ', 'DE', 'DK', 'SE' ]
12
13
  self.default_currency = 'ISK'
13
14
  self.money_format = :cents
14
15
  self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb]
@@ -335,7 +335,8 @@ module ActiveMerchant #:nodoc:
335
335
  end
336
336
 
337
337
  def avs_code_from(transaction)
338
- avs_mapping["street: #{transaction.avs_street_address_response_code}, zip: #{transaction.avs_postal_code_response_code}"]
338
+ transaction.avs_error_response_code ||
339
+ avs_mapping["street: #{transaction.avs_street_address_response_code}, zip: #{transaction.avs_postal_code_response_code}"]
339
340
  end
340
341
 
341
342
  def avs_mapping
@@ -518,6 +519,7 @@ module ActiveMerchant #:nodoc:
518
519
 
519
520
  parameters[:custom_fields] = options[:custom_fields]
520
521
  parameters[:device_data] = options[:device_data] if options[:device_data]
522
+ parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
521
523
  if merchant_account_id = (options[:merchant_account_id] || @merchant_account_id)
522
524
  parameters[:merchant_account_id] = merchant_account_id
523
525
  end
@@ -186,7 +186,7 @@ module ActiveMerchant #:nodoc:
186
186
  currency_code = options[:currency] || currency(money)
187
187
  params[key] = {
188
188
  'TotalAmount' => localized_amount(money, currency_code),
189
- 'InvoiceReference' => truncate(options[:order_id]),
189
+ 'InvoiceReference' => truncate(options[:order_id], 50),
190
190
  'InvoiceNumber' => truncate(options[:order_id], 12),
191
191
  'InvoiceDescription' => truncate(options[:description], 64),
192
192
  'CurrencyCode' => currency_code,
@@ -214,9 +214,9 @@ module ActiveMerchant #:nodoc:
214
214
  end
215
215
  params['Title'] = address[:title]
216
216
  params['CompanyName'] = address[:company] unless options[:skip_company]
217
- params['Street1'] = truncate(address[:address1])
218
- params['Street2'] = truncate(address[:address2])
219
- params['City'] = truncate(address[:city])
217
+ params['Street1'] = truncate(address[:address1], 50)
218
+ params['Street2'] = truncate(address[:address2], 50)
219
+ params['City'] = truncate(address[:city], 50)
220
220
  params['State'] = address[:state]
221
221
  params['PostalCode'] = address[:zip]
222
222
  params['Country'] = address[:country].to_s.downcase
@@ -230,7 +230,7 @@ module ActiveMerchant #:nodoc:
230
230
  params['Customer'] ||= {}
231
231
  if credit_card.respond_to? :number
232
232
  card_details = params['Customer']['CardDetails'] = {}
233
- card_details['Name'] = truncate(credit_card.name)
233
+ card_details['Name'] = truncate(credit_card.name, 50)
234
234
  card_details['Number'] = credit_card.number
235
235
  card_details['ExpiryMonth'] = "%02d" % (credit_card.month || 0)
236
236
  card_details['ExpiryYear'] = "%02d" % (credit_card.year || 0)
@@ -337,11 +337,6 @@ module ActiveMerchant #:nodoc:
337
337
  end
338
338
  end
339
339
 
340
- def truncate(value, max_size = 50)
341
- return nil unless value
342
- value.to_s[0, max_size]
343
- end
344
-
345
340
  MESSAGES = {
346
341
  'A2000' => 'Transaction Approved Successful',
347
342
  'A2008' => 'Honour With Identification Successful',
@@ -0,0 +1,206 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ class EzicGateway < Gateway
4
+ self.live_url = 'https://secure-dm3.ezic.com/gw/sas/direct3.2'
5
+
6
+ self.supported_countries = %w(AU CA CN FR DE GI IL MT MU MX NL NZ PA PH RU SG KR ES KN GB US)
7
+ self.default_currency = 'USD'
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
9
+
10
+ self.homepage_url = 'http://www.ezic.com/'
11
+ self.display_name = 'Ezic'
12
+
13
+ def initialize(options={})
14
+ requires!(options, :account_id)
15
+ super
16
+ end
17
+
18
+ def purchase(money, payment, options={})
19
+ post = {}
20
+
21
+ add_account_id(post)
22
+ add_invoice(post, money, options)
23
+ add_payment(post, payment)
24
+ add_customer_data(post, options)
25
+
26
+ commit("S", post)
27
+ end
28
+
29
+ def authorize(money, payment, options={})
30
+ post = {}
31
+
32
+ add_account_id(post)
33
+ add_invoice(post, money, options)
34
+ add_payment(post, payment)
35
+ add_customer_data(post, options)
36
+
37
+ commit("A", post)
38
+ end
39
+
40
+ def capture(money, authorization, options={})
41
+ post = {}
42
+
43
+ add_account_id(post)
44
+ add_invoice(post, money, options)
45
+ add_authorization(post, authorization)
46
+ add_pay_type(post)
47
+
48
+ commit("D", post)
49
+ end
50
+
51
+ def refund(money, authorization, options={})
52
+ post = {}
53
+
54
+ add_account_id(post)
55
+ add_invoice(post, money, options)
56
+ add_authorization(post, authorization)
57
+ add_pay_type(post)
58
+
59
+ commit("R", post)
60
+ end
61
+
62
+ def void(authorization, options={})
63
+ post = {}
64
+
65
+ add_account_id(post)
66
+ add_authorization(post, authorization)
67
+ add_pay_type(post)
68
+
69
+ commit("U", post)
70
+ end
71
+
72
+ def verify(credit_card, options={})
73
+ MultiResponse.run(:use_first_response) do |r|
74
+ r.process { authorize(100, credit_card, options) }
75
+ r.process(:ignore_result) { void(r.authorization, options) }
76
+ end
77
+ end
78
+
79
+ def supports_scrubbing?
80
+ true
81
+ end
82
+
83
+ def scrub(transcript)
84
+ transcript.
85
+ gsub(%r((card_number=)\w+), '\1[FILTERED]').
86
+ gsub(%r((card_cvv2=)\w+), '\1[FILTERED]')
87
+ end
88
+
89
+ private
90
+
91
+ def add_account_id(post)
92
+ post[:account_id] = @options[:account_id]
93
+ end
94
+
95
+ def add_addresses(post, options)
96
+ add_billing_address(post, options)
97
+ add_shipping_address(post, options)
98
+ end
99
+
100
+ def add_billing_address(post, options)
101
+ address = options[:billing_address] || {}
102
+
103
+ if address[:name]
104
+ names = address[:name].split
105
+ post[:bill_name2] = names.pop
106
+ post[:bill_name1] = names.join(" ")
107
+ end
108
+
109
+ post[:bill_street] = address[:address1] if address[:address1]
110
+ post[:bill_city] = address[:city] if address[:city]
111
+ post[:bill_state] = address[:state] if address[:state]
112
+ post[:bill_zip] = address[:zip] if address[:zip]
113
+ post[:bill_country] = address[:country] if address[:country]
114
+ post[:cust_phone] = address[:phone] if address[:phone]
115
+ end
116
+
117
+ def add_shipping_address(post, options)
118
+ address = options[:shipping_address] || {}
119
+
120
+ if address[:name]
121
+ names = address[:name].split
122
+ post[:ship_name2] = names.pop
123
+ post[:ship_name1] = names.join(" ")
124
+ end
125
+
126
+ post[:ship_street] = address[:address1] if address[:address1]
127
+ post[:ship_city] = address[:city] if address[:city]
128
+ post[:ship_state] = address[:state] if address[:state]
129
+ post[:ship_zip] = address[:zip] if address[:zip]
130
+ post[:ship_country] = address[:country] if address[:country]
131
+ end
132
+
133
+ def add_customer_data(post, options)
134
+ post[:cust_ip] = options[:ip] if options[:ip]
135
+ post[:cust_email] = options[:email] if options[:email]
136
+ add_addresses(post, options)
137
+ end
138
+
139
+ def add_invoice(post, money, options)
140
+ post[:amount] = amount(money)
141
+ post[:description] = options[:description] if options[:description]
142
+ end
143
+
144
+ def add_payment(post, payment)
145
+ add_pay_type(post)
146
+ post[:card_number] = payment.number
147
+ post[:card_cvv2] = payment.verification_value
148
+ post[:card_expire] = expdate(payment)
149
+ end
150
+
151
+ def add_authorization(post, authorization)
152
+ post[:orig_id] = authorization
153
+ end
154
+
155
+ def add_pay_type(post)
156
+ post[:pay_type] = "C"
157
+ end
158
+
159
+ def parse(body)
160
+ CGI::parse(body).inject({}) { |hash, (key, value)| hash[key] = value.first; hash }
161
+ end
162
+
163
+ def commit(transaction_type, parameters)
164
+ parameters[:tran_type] = transaction_type
165
+
166
+ begin
167
+ response = parse(ssl_post(live_url, post_data(parameters), headers))
168
+ Response.new(
169
+ success_from(response),
170
+ message_from(response),
171
+ response,
172
+ authorization: authorization_from(response),
173
+ avs_result: AVSResult.new(code: response["avs_code"]),
174
+ cvv_result: CVVResult.new(response["cvv2_code"]),
175
+ test: test?
176
+ )
177
+ rescue ResponseError => e
178
+ Response.new(false, e.response.message)
179
+ end
180
+ end
181
+
182
+ def success_from(response)
183
+ response["status_code"] == "1" || response["status_code"] == "T"
184
+ end
185
+
186
+ def message_from(response)
187
+ response["auth_msg"]
188
+ end
189
+
190
+ def authorization_from(response)
191
+ response["trans_id"]
192
+ end
193
+
194
+ def post_data(parameters = {})
195
+ parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
196
+ end
197
+
198
+ def headers
199
+ {
200
+ "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
201
+ }
202
+ end
203
+ end
204
+
205
+ end
206
+ end
@@ -174,10 +174,6 @@ module ActiveMerchant #:nodoc:
174
174
  }
175
175
  end
176
176
 
177
- def truncate(value, max_size)
178
- return nil unless value
179
- value.to_s[0, max_size]
180
- end
181
177
  end
182
178
  end
183
179
  end
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
  self.live_na_url = 'https://www.iatspayments.com/NetGate'
7
7
  self.live_uk_url = 'https://www.uk.iatspayments.com/NetGate'
8
8
 
9
- self.supported_countries = %w(AU BR CA CH DE DK ES FI FR GR HK IE IT NL NO PT SE SG TR GB US)
9
+ self.supported_countries = %w(AU BR CA CH DE DK ES FI FR GR HK IE IT NL NO PT SE SG TR GB US TH ID PH BE)
10
10
  self.default_currency = 'USD'
11
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
12
 
@@ -107,7 +107,7 @@ module ActiveMerchant #:nodoc:
107
107
  request = build_xml_request do |doc|
108
108
  add_authentication(doc)
109
109
  doc.registerTokenRequest(transaction_attributes(options)) do
110
- doc.orderId(truncated(options[:order_id]))
110
+ doc.orderId(truncate(options[:order_id], 24))
111
111
  doc.accountNumber(creditcard.number)
112
112
  end
113
113
  end
@@ -155,7 +155,7 @@ module ActiveMerchant #:nodoc:
155
155
  end
156
156
 
157
157
  def add_auth_purchase_params(doc, money, payment_method, options)
158
- doc.orderId(truncated(options[:order_id]))
158
+ doc.orderId(truncate(options[:order_id], 24))
159
159
  doc.amount(money)
160
160
  add_order_source(doc, payment_method, options)
161
161
  add_billing_address(doc, payment_method, options)
@@ -296,7 +296,7 @@ module ActiveMerchant #:nodoc:
296
296
 
297
297
  def transaction_attributes(options)
298
298
  attributes = {}
299
- attributes[:id] = truncated(options[:id] || options[:order_id])
299
+ attributes[:id] = truncate(options[:id] || options[:order_id], 24)
300
300
  attributes[:reportGroup] = options[:merchant] || 'Default Report Group'
301
301
  attributes[:customerId] = options[:customer]
302
302
  attributes.delete_if { |key, value| value == nil }
@@ -323,21 +323,6 @@ module ActiveMerchant #:nodoc:
323
323
  test? ? test_url : live_url
324
324
  end
325
325
 
326
- def truncated(value)
327
- return unless value
328
- value[0..24]
329
- end
330
-
331
- def truncated_order_id(options)
332
- return unless options[:order_id]
333
- options[:order_id][0..24]
334
- end
335
-
336
- def truncated_id(options)
337
- return unless options[:id]
338
- options[:id][0..24]
339
- end
340
-
341
326
  def headers
342
327
  {
343
328
  'Content-Type' => 'text/xml'
@@ -86,7 +86,7 @@ module ActiveMerchant #:nodoc:
86
86
  end
87
87
 
88
88
  def add_product(post, options)
89
- post['transactionProduct'] = options[:description]
89
+ post['transactionProduct'] = truncate(options[:description], 34)
90
90
  end
91
91
 
92
92
  def add_payment_method(post, payment_method)
@@ -38,6 +38,13 @@ module ActiveMerchant #:nodoc:
38
38
  super
39
39
  end
40
40
 
41
+ def verify(creditcard_or_datakey, options = {})
42
+ MultiResponse.run(:use_first_response) do |r|
43
+ r.process { authorize(100, creditcard_or_datakey, options) }
44
+ r.process(:ignore_result) { capture(0, r.authorization) }
45
+ end
46
+ end
47
+
41
48
  # Referred to as "PreAuth" in the Moneris integration guide, this action
42
49
  # verifies and locks funds on a customer's card, which then must be
43
50
  # captured at a later date.
@@ -264,11 +264,6 @@ module ActiveMerchant #:nodoc:
264
264
  truncate(cleansed, 20)
265
265
  end
266
266
 
267
- def truncate(value, max_size)
268
- return nil unless value
269
- value[0, max_size]
270
- end
271
-
272
267
  def is_usa(country)
273
268
  truncate(country, 2) == 'US'
274
269
  end
@@ -93,8 +93,7 @@ module ActiveMerchant #:nodoc:
93
93
 
94
94
  xml.tag! 'AMOUNT', amount(money)
95
95
  add_credit_card(xml, creditcard)
96
- add_params_in_required_order(xml, action, options)
97
- add_address(xml, creditcard, options)
96
+ add_params_in_required_order(xml, action, creditcard, options)
98
97
  add_more_required_params(xml, options)
99
98
 
100
99
  xml.target!
@@ -110,7 +109,7 @@ module ActiveMerchant #:nodoc:
110
109
  xml.tag! 'CARDNUMBER', last_four
111
110
  end
112
111
 
113
- add_params_in_required_order(xml, action, options)
112
+ add_params_in_required_order(xml, action, nil, options)
114
113
  xml.tag! 'REF_TRANSID', transaction_id
115
114
  add_more_required_params(xml, options)
116
115
 
@@ -136,6 +135,7 @@ module ActiveMerchant #:nodoc:
136
135
  end
137
136
 
138
137
  def add_address(xml, creditcard, options)
138
+ return unless creditcard
139
139
 
140
140
  if address = options[:billing_address] || options[:address]
141
141
  xml.tag!("CUSTOMER_BILL") do
@@ -161,8 +161,18 @@ module ActiveMerchant #:nodoc:
161
161
  xml.tag! 'CITY', address[:city].to_s
162
162
  xml.tag! 'COMPANY', address[:company].to_s
163
163
  xml.tag! 'COUNTRY', address[:country].to_s
164
- xml.tag! 'FIRSTNAME', address[:first_name].to_s
165
- xml.tag! 'LASTNAME', address[:last_name].to_s
164
+
165
+ if address[:name]
166
+ names = address[:name].split
167
+ last_name = names.pop
168
+ first_name = names.join(" ")
169
+ xml.tag! 'FIRSTNAME', first_name
170
+ xml.tag! 'LASTNAME', last_name
171
+ else
172
+ xml.tag! 'FIRSTNAME', address[:first_name].to_s
173
+ xml.tag! 'LASTNAME', address[:last_name].to_s
174
+ end
175
+
166
176
  xml.tag! 'STATE', address[:state].blank? ? 'n/a' : address[:state]
167
177
  xml.tag! 'ZIP', address[:zip].to_s
168
178
  end
@@ -182,9 +192,10 @@ module ActiveMerchant #:nodoc:
182
192
  end
183
193
 
184
194
  # SecureNet requires some of the xml params to be in a certain order. http://cl.ly/image/3K260E0p0a0n/content.png
185
- def add_params_in_required_order(xml, action, options)
195
+ def add_params_in_required_order(xml, action, creditcard, options)
186
196
  xml.tag! 'CODE', TRANSACTIONS[action]
187
197
  add_customer_data(xml, options)
198
+ add_address(xml, creditcard, options)
188
199
  xml.tag! 'DCI', 0 # No duplicate checking will be done, except for ORDERID
189
200
  xml.tag! 'INSTALLMENT_SEQUENCENUM', 1
190
201
  xml.tag! 'INVOICEDESC', options[:invoice_description] if options[:invoice_description]
@@ -8,8 +8,8 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  class_attribute :test_periodic_url, :live_periodic_url
10
10
 
11
- self.test_url = 'https://www.securepay.com.au/test/payment'
12
- self.live_url = 'https://www.securepay.com.au/xmlapi/payment'
11
+ self.test_url = 'https://api.securepay.com.au/test/payment'
12
+ self.live_url = 'https://api.securepay.com.au/xmlapi/payment'
13
13
 
14
14
  self.test_periodic_url = 'https://test.securepay.com.au/xmlapi/periodic'
15
15
  self.live_periodic_url = 'https://api.securepay.com.au/xmlapi/periodic'
@@ -27,7 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  self.supported_countries = %w(AT AU BE CA CH DE DK ES FI FR GB IE IT LU NL NO SE US)
28
28
  self.default_currency = 'USD'
29
29
  self.money_format = :cents
30
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
30
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
31
31
 
32
32
  self.homepage_url = 'https://stripe.com/'
33
33
  self.display_name = 'Stripe'
@@ -62,7 +62,7 @@ module ActiveMerchant #:nodoc:
62
62
  end
63
63
  r.process do
64
64
  post = create_post_for_auth_or_purchase(money, payment, options)
65
- post[:capture] = "false"
65
+ post[:capture] = "false" unless emv_payment?(payment)
66
66
  commit(:post, 'charges', post, options)
67
67
  end
68
68
  end.responses.last
@@ -90,10 +90,16 @@ module ActiveMerchant #:nodoc:
90
90
 
91
91
  def capture(money, authorization, options = {})
92
92
  post = {}
93
- add_amount(post, money, options)
93
+
94
94
  add_application_fee(post, options)
95
95
 
96
- commit(:post, "charges/#{CGI.escape(authorization)}/capture", post, options)
96
+ if emv_tc_response = options.delete(:icc_data)
97
+ post[:card] = { emv_approval_data: emv_tc_response }
98
+ commit(:post, "charges/#{CGI.escape(authorization)}", post, options)
99
+ else
100
+ add_amount(post, money, options)
101
+ commit(:post, "charges/#{CGI.escape(authorization)}/capture", post, options)
102
+ end
97
103
  end
98
104
 
99
105
  def void(identification, options = {})
@@ -226,24 +232,24 @@ module ActiveMerchant #:nodoc:
226
232
 
227
233
  def create_post_for_auth_or_purchase(money, payment, options)
228
234
  post = {}
229
- add_amount(post, money, options, true)
235
+
230
236
  if payment.is_a?(StripePaymentToken)
231
237
  add_payment_token(post, payment, options)
232
238
  else
233
239
  add_creditcard(post, payment, options)
234
240
  end
235
- add_customer(post, payment, options)
236
- add_customer_data(post, options)
237
- post[:description] = options[:description]
238
- post[:statement_description] = options[:statement_description]
239
-
240
- post[:metadata] = options[:metadata] || {}
241
- post[:metadata][:email] = options[:email] if options[:email]
242
- post[:metadata][:order_id] = options[:order_id] if options[:order_id]
243
- post.delete(:metadata) if post[:metadata].empty?
241
+ unless emv_payment?(payment)
242
+ add_amount(post, money, options, true)
243
+ add_customer_data(post, options)
244
+ add_metadata(post, options)
245
+ post[:description] = options[:description]
246
+ post[:statement_description] = options[:statement_description]
247
+ add_customer(post, payment, options)
248
+ add_flags(post, options)
249
+ end
244
250
 
245
- add_flags(post, options)
246
251
  add_application_fee(post, options)
252
+ add_destination(post, options)
247
253
  post
248
254
  end
249
255
 
@@ -257,6 +263,10 @@ module ActiveMerchant #:nodoc:
257
263
  post[:application_fee] = options[:application_fee] if options[:application_fee]
258
264
  end
259
265
 
266
+ def add_destination(post, options)
267
+ post[:destination] = options[:destination] if options[:destination]
268
+ end
269
+
260
270
  def add_expand_parameters(post, options)
261
271
  post[:expand] = Array.wrap(options[:expand])
262
272
  end
@@ -283,9 +293,12 @@ module ActiveMerchant #:nodoc:
283
293
 
284
294
  def add_creditcard(post, creditcard, options)
285
295
  card = {}
286
- if creditcard.respond_to?(:number)
296
+ if emv_payment?(creditcard)
297
+ add_emv_creditcard(post, creditcard.icc_data)
298
+ elsif creditcard.respond_to?(:number)
287
299
  if creditcard.respond_to?(:track_data) && creditcard.track_data.present?
288
300
  card[:swipe_data] = creditcard.track_data
301
+ card[:fallback_reason] = creditcard.fallback_reason if creditcard.fallback_reason
289
302
  else
290
303
  card[:number] = creditcard.number
291
304
  card[:exp_month] = creditcard.month
@@ -293,7 +306,6 @@ module ActiveMerchant #:nodoc:
293
306
  card[:cvc] = creditcard.verification_value if creditcard.verification_value?
294
307
  card[:name] = creditcard.name if creditcard.name
295
308
  end
296
-
297
309
  post[:card] = card
298
310
 
299
311
  if creditcard.is_a?(NetworkTokenizationCreditCard)
@@ -314,6 +326,10 @@ module ActiveMerchant #:nodoc:
314
326
  end
315
327
  end
316
328
 
329
+ def add_emv_creditcard(post, icc_data, options = {})
330
+ post[:card] = { emv_auth_data: icc_data }
331
+ end
332
+
317
333
  def add_payment_token(post, token, options = {})
318
334
  post[:card] = token.payment_data["id"]
319
335
  end
@@ -327,6 +343,13 @@ module ActiveMerchant #:nodoc:
327
343
  post[:recurring] = true if (options[:eci] == 'recurring' || options[:recurring])
328
344
  end
329
345
 
346
+ def add_metadata(post, options = {})
347
+ post[:metadata] = options[:metadata] || {}
348
+ post[:metadata][:email] = options[:email] if options[:email]
349
+ post[:metadata][:order_id] = options[:order_id] if options[:order_id]
350
+ post.delete(:metadata) if post[:metadata].empty?
351
+ end
352
+
330
353
  def fetch_application_fees(identification, options = {})
331
354
  options.merge!(:key => @fee_refund_api_key)
332
355
 
@@ -359,6 +382,7 @@ module ActiveMerchant #:nodoc:
359
382
  def headers(options = {})
360
383
  key = options[:key] || @api_key
361
384
  version = options[:version] || @version
385
+ idempotency_key = options[:idempotency_key]
362
386
 
363
387
  headers = {
364
388
  "Authorization" => "Basic " + Base64.encode64(key.to_s + ":").strip,
@@ -367,6 +391,7 @@ module ActiveMerchant #:nodoc:
367
391
  "X-Stripe-Client-User-Metadata" => {:ip => options[:ip]}.to_json
368
392
  }
369
393
  headers.merge!("Stripe-Version" => version) if version
394
+ headers.merge!("Idempotency-Key" => idempotency_key) if idempotency_key
370
395
  headers
371
396
  end
372
397
 
@@ -386,11 +411,11 @@ module ActiveMerchant #:nodoc:
386
411
 
387
412
  def commit(method, url, parameters = nil, options = {})
388
413
  add_expand_parameters(parameters, options) if parameters
389
-
390
414
  response = api_request(method, url, parameters, options)
415
+
391
416
  success = !response.key?("error")
392
417
 
393
- card = response["card"] || response["active_card"] || {}
418
+ card = response["card"] || response["active_card"] || response["source"] || {}
394
419
  avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
395
420
  cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]]
396
421
 
@@ -401,6 +426,7 @@ module ActiveMerchant #:nodoc:
401
426
  :authorization => success ? response["id"] : response["error"]["charge"],
402
427
  :avs_result => { :code => avs_code },
403
428
  :cvv_result => cvc_code,
429
+ :emv_authorization => card["emv_auth_data"],
404
430
  :error_code => success ? nil : STANDARD_ERROR_CODE_MAPPING[response["error"]["code"]]
405
431
  )
406
432
  end
@@ -426,6 +452,10 @@ module ActiveMerchant #:nodoc:
426
452
  def non_fractional_currency?(currency)
427
453
  CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
428
454
  end
455
+
456
+ def emv_payment?(payment)
457
+ payment.respond_to?(:emv?) && payment.emv?
458
+ end
429
459
  end
430
460
  end
431
461
  end
@@ -148,13 +148,16 @@ module ActiveMerchant #:nodoc:
148
148
  response = parse(e.response.body)
149
149
  end
150
150
 
151
- Response.new(
151
+ return Response.new(
152
152
  success_from(response),
153
153
  message_from(response),
154
154
  response,
155
155
  authorization: authorization_from(response, params),
156
156
  test: test?
157
157
  )
158
+
159
+ rescue JSON::ParserError
160
+ return unparsable_response(response)
158
161
  end
159
162
 
160
163
  def success_from(response)
@@ -176,6 +179,12 @@ module ActiveMerchant #:nodoc:
176
179
  [auth, original_amount]
177
180
  end
178
181
 
182
+ def unparsable_response(raw_response)
183
+ message = "Invalid JSON response received from WePay. Please contact WePay support if you continue to receive this message."
184
+ message += " (The raw response returned by the API was #{raw_response.inspect})"
185
+ return Response.new(false, message)
186
+ end
187
+
179
188
  def headers
180
189
  {
181
190
  "Content-Type" => "application/json",
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  end
5
5
 
6
6
  class Response
7
- attr_reader :params, :message, :test, :authorization, :avs_result, :cvv_result, :error_code
7
+ attr_reader :params, :message, :test, :authorization, :avs_result, :cvv_result, :error_code, :emv_authorization
8
8
 
9
9
  def success?
10
10
  @success
@@ -24,6 +24,7 @@ module ActiveMerchant #:nodoc:
24
24
  @authorization = options[:authorization]
25
25
  @fraud_review = options[:fraud_review]
26
26
  @error_code = options[:error_code]
27
+ @emv_authorization = options[:emv_authorization]
27
28
 
28
29
  @avs_result = if options[:avs_result].kind_of?(AVSResult)
29
30
  options[:avs_result].to_hash
@@ -79,7 +80,7 @@ module ActiveMerchant #:nodoc:
79
80
  (primary_response ? primary_response.success? : true)
80
81
  end
81
82
 
82
- %w(params message test authorization avs_result cvv_result error_code test? fraud_review?).each do |m|
83
+ %w(params message test authorization avs_result cvv_result error_code emv_authorization test? fraud_review?).each do |m|
83
84
  class_eval %(
84
85
  def #{m}
85
86
  (@responses.empty? ? nil : primary_response.#{m})
@@ -7,6 +7,7 @@ module ActiveMerchant
7
7
  Timeout::Error => "The connection to the remote server timed out",
8
8
  Errno::ETIMEDOUT => "The connection to the remote server timed out",
9
9
  SocketError => "The connection to the remote server could not be established",
10
+ Errno::EHOSTUNREACH => "The connection to the remote server could not be established",
10
11
  OpenSSL::SSL::SSLError => "The SSL connection to the remote server could not be established"
11
12
  }
12
13
 
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.48.0"
2
+ VERSION = "1.49.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.48.0
4
+ version: 1.49.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
@@ -30,7 +30,7 @@ cert_chain:
30
30
  fl3hbtVFTqbOlwL9vy1fudXcolIE/ZTcxQ+er07ZFZdKCXayR9PPs64heamfn0fp
31
31
  TConQSX2BnZdhIEYW+cKzEC/bLc=
32
32
  -----END CERTIFICATE-----
33
- date: 2015-04-08 00:00:00.000000000 Z
33
+ date: 2015-05-01 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: activesupport
@@ -226,6 +226,7 @@ files:
226
226
  - lib/active_merchant/billing/gateways/eway_managed.rb
227
227
  - lib/active_merchant/billing/gateways/eway_rapid.rb
228
228
  - lib/active_merchant/billing/gateways/exact.rb
229
+ - lib/active_merchant/billing/gateways/ezic.rb
229
230
  - lib/active_merchant/billing/gateways/fat_zebra.rb
230
231
  - lib/active_merchant/billing/gateways/federated_canada.rb
231
232
  - lib/active_merchant/billing/gateways/finansbank.rb
metadata.gz.sig CHANGED
@@ -1 +1 @@
1
- �#�VurL��n S���.:d�@)��~>*���*ź���g�7��#�Rۏ>� c�D�t'��{��Q�ª?��Oߴh�_�Ԉo��v�rKĜ/������M�~f)�B#ŏ��F��s�V�֎�RkՂ;s�Z�nd�Q�J(�2��%C���9Z�sz�>+-$�"N�{O���ʥG7�� �q8c���C��
1
+ r���!��ꗐ��u试e0�8�)���qDLe���\�})XI֒�>\�<�Ce?r����÷z>g��EYL�2g�s&!��bE