braintree 2.2.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/braintree.rb CHANGED
@@ -12,10 +12,6 @@ require "time"
12
12
  require "zlib"
13
13
 
14
14
  require "builder"
15
- require "libxml"
16
- unless ::LibXML::XML.respond_to?(:default_keep_blanks=)
17
- raise LoadError, "The version of libxml that you're using is not compatible with the Braintree gem."
18
- end
19
15
 
20
16
  module Braintree
21
17
  end
@@ -55,6 +51,7 @@ require "braintree/version.rb"
55
51
  require "braintree/xml.rb"
56
52
  require "braintree/xml/generator.rb"
57
53
  require "braintree/xml/libxml.rb"
54
+ require "braintree/xml/rexml.rb"
58
55
  require "braintree/xml/parser.rb"
59
56
 
60
57
  Braintree::SSLExpirationCheck.check_dates
@@ -46,10 +46,12 @@ module Braintree
46
46
 
47
47
  # The transparent redirect URL to use to create a credit card.
48
48
  def self.create_credit_card_url
49
+ warn "[DEPRECATED] CreditCard.create_credit_card_url is deprecated. Please use TransparentRedirect.url"
49
50
  "#{Braintree::Configuration.base_merchant_url}/payment_methods/all/create_via_transparent_redirect_request"
50
51
  end
51
52
 
52
53
  def self.create_from_transparent_redirect(query_string)
54
+ warn "[DEPRECATED] CreditCard.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
53
55
  params = TransparentRedirect.parse_and_validate_query_string query_string
54
56
  _do_create("/payment_methods/all/confirm_transparent_redirect_request", :id => params[:id])
55
57
  end
@@ -107,12 +109,14 @@ module Braintree
107
109
  end
108
110
 
109
111
  def self.update_from_transparent_redirect(query_string)
112
+ warn "[DEPRECATED] CreditCard.update_via_transparent_redirect_request is deprecated. Please use TransparentRedirect.confirm"
110
113
  params = TransparentRedirect.parse_and_validate_query_string query_string
111
114
  _do_update(:post, "/payment_methods/all/confirm_transparent_redirect_request", :id => params[:id])
112
115
  end
113
116
 
114
117
  # The transparent redirect URL to use to update a credit card.
115
118
  def self.update_credit_card_url
119
+ warn "[DEPRECATED] CreditCard.update_credit_card_url is deprecated. Please use TransparentRedirect.url"
116
120
  "#{Braintree::Configuration.base_merchant_url}/payment_methods/all/update_via_transparent_redirect_request"
117
121
  end
118
122
 
@@ -163,10 +167,7 @@ module Braintree
163
167
 
164
168
  # Returns true if the credit card is expired.
165
169
  def expired?
166
- if expiration_year.to_i == Time.now.year
167
- return expiration_month.to_i < Time.now.month
168
- end
169
- expiration_year.to_i < Time.now.year
170
+ @expired
170
171
  end
171
172
 
172
173
  def inspect # :nodoc:
@@ -233,7 +234,7 @@ module Braintree
233
234
  self.new *args
234
235
  end
235
236
 
236
- def self._do_create(url, params) # :nodoc:
237
+ def self._do_create(url, params=nil) # :nodoc:
237
238
  response = Http.post url, params
238
239
  if response[:credit_card]
239
240
  SuccessfulResult.new(:credit_card => new(response[:credit_card]))
@@ -263,7 +264,7 @@ module Braintree
263
264
  billing_address_params = [:company, :country_name, :extended_address, :first_name, :last_name, :locality, :postal_code, :region, :street_address]
264
265
  signature = [
265
266
  :cardholder_name, :cvv, :expiration_date, :expiration_month, :expiration_year, :number, :token,
266
- {:options => [:make_default, :verify_card]},
267
+ {:options => [:make_default, :verification_merchant_account_id, :verify_card]},
267
268
  {:billing_address => billing_address_params}
268
269
  ]
269
270
 
@@ -3,7 +3,7 @@ module Braintree
3
3
  include BaseModule
4
4
 
5
5
  attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code,
6
- :cvv_response_code, :processor_response_code, :processor_response_text, :status
6
+ :cvv_response_code, :merchant_account_id, :processor_response_code, :processor_response_text, :status
7
7
 
8
8
  def initialize(attributes) # :nodoc:
9
9
  set_instance_variables_from_hash(attributes)
@@ -13,7 +13,8 @@ module Braintree
13
13
  attr_order = [
14
14
  :status, :processor_response_code, :processor_response_text,
15
15
  :cvv_response_code, :avs_error_response_code,
16
- :avs_postal_code_response_code, :avs_street_address_response_code
16
+ :avs_postal_code_response_code, :avs_street_address_response_code,
17
+ :merchant_account_id
17
18
  ]
18
19
  formatted_attrs = attr_order.map do |attr|
19
20
  "#{attr}: #{send(attr).inspect}"
@@ -52,18 +52,16 @@ module Braintree
52
52
  end
53
53
 
54
54
  def self.create_customer_url
55
+ warn "[DEPRECATED] Customer.create_customer_url is deprecated. Please use TransparentRedirect.url"
55
56
  "#{Braintree::Configuration.base_merchant_url}/customers/all/create_via_transparent_redirect_request"
56
57
  end
57
58
 
58
59
  def self.create_from_transparent_redirect(query_string)
60
+ warn "[DEPRECATED] Customer.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
59
61
  params = TransparentRedirect.parse_and_validate_query_string query_string
60
62
  _do_create("/customers/all/confirm_transparent_redirect_request", :id => params[:id])
61
63
  end
62
64
 
63
- def self.create_customer_transparent_redirect_url
64
- "#{Braintree::Configuration.base_merchant_url}/customers"
65
- end
66
-
67
65
  def self.credit(customer_id, transaction_attributes)
68
66
  Transaction.credit(transaction_attributes.merge(:customer_id => customer_id))
69
67
  end
@@ -118,10 +116,12 @@ module Braintree
118
116
  end
119
117
 
120
118
  def self.update_customer_url
119
+ warn "[DEPRECATED] Customer.update_customer_url is deprecated. Please use TransparentRedirect.url"
121
120
  "#{Braintree::Configuration.base_merchant_url}/customers/all/update_via_transparent_redirect_request"
122
121
  end
123
122
 
124
123
  def self.update_from_transparent_redirect(query_string)
124
+ warn "[DEPRECATED] Customer.update_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
125
125
  params = TransparentRedirect.parse_and_validate_query_string(query_string)
126
126
  _do_update(:post, "/customers/all/confirm_transparent_redirect_request", :id => params[:id])
127
127
  end
@@ -208,7 +208,7 @@ module Braintree
208
208
  ]
209
209
  end
210
210
 
211
- def self._do_create(url, params) # :nodoc:
211
+ def self._do_create(url, params=nil) # :nodoc:
212
212
  response = Http.post url, params
213
213
  if response[:customer]
214
214
  SuccessfulResult.new(:customer => new(response[:customer]))
@@ -235,7 +235,14 @@ module Braintree
235
235
  end
236
236
 
237
237
  def self._update_signature # :nodoc:
238
- [ :company, :email, :fax, :first_name, :id, :last_name, :phone, :website, {:custom_fields => :_any_key_} ]
238
+ credit_card_signature = CreditCard._update_signature - [:customer_id]
239
+ credit_card_options = credit_card_signature.find { |item| item.respond_to?(:keys) && item.keys == [:options] }
240
+ credit_card_options[:options] << :update_existing_token
241
+ [
242
+ :company, :email, :fax, :first_name, :id, :last_name, :phone, :website,
243
+ {:credit_card => credit_card_signature},
244
+ {:custom_fields => :_any_key_}
245
+ ]
239
246
  end
240
247
  end
241
248
  end
@@ -24,29 +24,34 @@ module Braintree
24
24
  BillingAddressIdIsInvalid = "91702"
25
25
  CardholderNameIsTooLong = "81723"
26
26
  CreditCardTypeIsNotAccepted = "81703"
27
- CustomerIdIsRequired = "91704"
27
+ CreditCardTypeIsNotAcceptedBySubscriptionMerchantAccount = "81718"
28
28
  CustomerIdIsInvalid = "91705"
29
- CvvIsRequired = "81706"
29
+ CustomerIdIsRequired = "91704"
30
30
  CvvIsInvalid = "81707"
31
+ CvvIsRequired = "81706"
31
32
  ExpirationDateConflict = "91708"
32
- ExpirationDateIsRequired = "81709"
33
33
  ExpirationDateIsInvalid = "81710"
34
+ ExpirationDateIsRequired = "81709"
34
35
  ExpirationDateYearIsInvalid = "81711"
35
36
  ExpirationMonthIsInvalid = "81712"
36
37
  ExpirationYearIsInvalid = "81713"
37
- NumberIsRequired = "81714"
38
- NumberIsInvalid = "81715"
39
38
  NumberHasInvalidLength = "81716"
39
+ NumberIsInvalid = "81715"
40
+ NumberIsRequired = "81714"
40
41
  NumberMustBeTestNumber = "81717"
41
42
  TokenInvalid = "91718"
42
43
  TokenIsInUse = "91719"
43
- TokenIsTooLong = "91720"
44
44
  TokenIsNotAllowed = "91721"
45
45
  TokenIsRequired = "91722"
46
+ TokenIsTooLong = "91720"
47
+
48
+ module Options
49
+ UpdateExistingTokenIsInvalid = "91723"
50
+ end
46
51
  end
47
52
 
48
53
  module Customer
49
- CompanyisTooLong = "81601"
54
+ CompanyIsTooLong = "81601"
50
55
  CustomFieldIsInvalid = "91602"
51
56
  CustomFieldIsTooLong = "81603"
52
57
  EmailIsInvalid = "81604"
@@ -67,6 +72,11 @@ module Braintree
67
72
  module Subscription
68
73
  CannotEditCanceledSubscription = "81901"
69
74
  IdIsInUse = "81902"
75
+ MerchantAccountIdIsInvalid = "91901"
76
+ PaymentMethodTokenCardTypeIsNotAccepted = "91902"
77
+ PaymentMethodTokenIsInvalid = "91903"
78
+ PaymentMethodTokenNotAssociatedWithCustomer = "91905"
79
+ PlanIdIsInvalid = "91904"
70
80
  PriceCannotBeBlank = "81903"
71
81
  PriceFormatIsInvalid = "81904"
72
82
  StatusIsCanceled = "81905"
@@ -81,6 +91,7 @@ module Braintree
81
91
  AmountIsRequired = "81502"
82
92
  AmountIsInvalid = "81503"
83
93
  AmountIsTooLarge = "81528"
94
+ BillingAddressConflict = "91530"
84
95
  CannotBeVoided = "91504"
85
96
  CannotRefundCredit = "91505"
86
97
  CannotRefundUnlessSettled = "91506"
@@ -27,7 +27,13 @@ module Braintree
27
27
  end
28
28
 
29
29
  def inspect # :nodoc:
30
- "#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>>"
30
+ if @credit_card_verification
31
+ verification_inspect = " credit_card_verification: #{@credit_card_verification.inspect}"
32
+ end
33
+ if @transaction
34
+ transaction_inspect = " transaction: #{@transaction.inspect}"
35
+ end
36
+ "#<#{self.class} params:{...} errors:<#{@errors._inner_inspect}>#{verification_inspect}#{transaction_inspect}>"
31
37
  end
32
38
 
33
39
  # Always returns false.
@@ -6,7 +6,6 @@ module Braintree
6
6
 
7
7
  def self.check_dates # :nodoc:
8
8
  {
9
- "QA" => qa_expiration_date,
10
9
  "Sandbox" => sandbox_expiration_date,
11
10
  "Production" => production_expiration_date
12
11
  }.each do |host, expiration_date|
@@ -24,9 +23,5 @@ module Braintree
24
23
  def self.sandbox_expiration_date # :nodoc:
25
24
  Date.civil(2010, 12, 1)
26
25
  end
27
-
28
- def self.qa_expiration_date # :nodoc:
29
- Date.civil(2010, 12, 1)
30
- end
31
26
  end
32
27
  end
@@ -176,6 +176,7 @@ module Braintree
176
176
  [
177
177
  :id,
178
178
  :merchant_account_id,
179
+ :payment_method_token,
179
180
  :plan_id,
180
181
  :price
181
182
  ]
@@ -156,6 +156,7 @@ module Braintree
156
156
 
157
157
  attr_reader :avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code
158
158
  attr_reader :amount, :created_at, :credit_card_details, :customer_details, :id
159
+ attr_reader :currency_iso_code
159
160
  attr_reader :custom_fields
160
161
  attr_reader :cvv_response_code
161
162
  attr_reader :merchant_account_id
@@ -167,9 +168,11 @@ module Braintree
167
168
  attr_reader :processor_response_code
168
169
  # The response text from the processor.
169
170
  attr_reader :processor_response_text
171
+ attr_reader :refund_id, :refunded_transaction_id
170
172
  # See Transaction::Status
171
173
  attr_reader :status
172
174
  attr_reader :status_history
175
+ attr_reader :subscription_id
173
176
  # Will either be "sale" or "credit"
174
177
  attr_reader :type
175
178
  attr_reader :updated_at
@@ -184,12 +187,14 @@ module Braintree
184
187
  end
185
188
 
186
189
  def self.create_from_transparent_redirect(query_string)
190
+ warn "[DEPRECATED] Transaction.create_from_transparent_redirect is deprecated. Please use TransparentRedirect.confirm"
187
191
  params = TransparentRedirect.parse_and_validate_query_string query_string
188
192
  _do_create("/transactions/all/confirm_transparent_redirect_request", :id => params[:id])
189
193
  end
190
194
 
191
195
  # The URL to use to create transactions via transparent redirect.
192
196
  def self.create_transaction_url
197
+ warn "[DEPRECATED] Transaction.create_transaction_url is deprecated. Please use TransparentRedirect.url"
193
198
  "#{Braintree::Configuration.base_merchant_url}/transactions/all/create_via_transparent_redirect_request"
194
199
  end
195
200
 
@@ -383,7 +388,7 @@ module Braintree
383
388
  end
384
389
  end
385
390
 
386
- def self._do_create(url, params) # :nodoc:
391
+ def self._do_create(url, params=nil) # :nodoc:
387
392
  response = Http.post url, params
388
393
  if response[:transaction]
389
394
  SuccessfulResult.new(:transaction => new(response[:transaction]))
@@ -26,15 +26,38 @@ module Braintree
26
26
  CreateCreditCardSignature = TransparentRedirectKeys + [{:credit_card => CreditCard._create_signature}] # :nodoc:
27
27
  UpdateCreditCardSignature = TransparentRedirectKeys + [:payment_method_token, {:credit_card => CreditCard._update_signature}] # :nodoc:
28
28
 
29
+ module Kind
30
+ CreateCustomer = "create_customer"
31
+ UpdateCustomer = "update_customer"
32
+ CreatePaymentMethod = "create_payment_method"
33
+ UpdatePaymentMethod = "update_payment_method"
34
+ CreateTransaction = "create_transaction"
35
+ end
36
+
37
+ def self.confirm(query_string)
38
+ params = TransparentRedirect.parse_and_validate_query_string query_string
39
+ confirmation_klass = {
40
+ Kind::CreateCustomer => Braintree::Customer,
41
+ Kind::UpdateCustomer => Braintree::Customer,
42
+ Kind::CreatePaymentMethod => Braintree::CreditCard,
43
+ Kind::UpdatePaymentMethod => Braintree::CreditCard,
44
+ Kind::CreateTransaction => Braintree::Transaction
45
+ }[params[:kind]]
46
+
47
+ confirmation_klass._do_create("/transparent_redirect_requests/#{params[:id]}/confirm")
48
+ end
49
+
29
50
  # Returns the tr_data string for creating a credit card.
30
51
  def self.create_credit_card_data(params)
31
52
  Util.verify_keys(CreateCreditCardSignature, params)
53
+ params[:kind] = Kind::CreatePaymentMethod
32
54
  _data(params)
33
55
  end
34
56
 
35
57
  # Returns the tr_data string for creating a customer.
36
58
  def self.create_customer_data(params)
37
59
  Util.verify_keys(CreateCustomerSignature, params)
60
+ params[:kind] = Kind::CreateCustomer
38
61
  _data(params)
39
62
  end
40
63
 
@@ -58,6 +81,7 @@ module Braintree
58
81
  # Returns the tr_data string for creating a transaction.
59
82
  def self.transaction_data(params)
60
83
  Util.verify_keys(TransactionSignature, params)
84
+ params[:kind] = Kind::CreateTransaction
61
85
  transaction_type = params[:transaction] && params[:transaction][:type]
62
86
  unless %w[sale credit].include?(transaction_type)
63
87
  raise ArgumentError, "expected transaction[type] of sale or credit, was: #{transaction_type.inspect}"
@@ -77,6 +101,7 @@ module Braintree
77
101
  unless params[:payment_method_token]
78
102
  raise ArgumentError, "expected params to contain :payment_method_token of payment method to update"
79
103
  end
104
+ params[:kind] = Kind::UpdatePaymentMethod
80
105
  _data(params)
81
106
  end
82
107
 
@@ -92,9 +117,15 @@ module Braintree
92
117
  unless params[:customer_id]
93
118
  raise ArgumentError, "expected params to contain :customer_id of customer to update"
94
119
  end
120
+ params[:kind] = Kind::UpdateCustomer
95
121
  _data(params)
96
122
  end
97
123
 
124
+ # Returns the URL to which Transparent Redirect Requests should be posted
125
+ def self.url
126
+ "#{Braintree::Configuration.base_merchant_url}/transparent_redirect_requests"
127
+ end
128
+
98
129
  def self._data(params) # :nodoc:
99
130
  raise ArgumentError, "expected params to contain :redirect_url" unless params[:redirect_url]
100
131
  tr_data_segment = Util.hash_to_query_string(params.merge(
@@ -1,8 +1,8 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 2
4
- Minor = 2
5
- Tiny = 0
4
+ Minor = 3
5
+ Tiny = 1
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
8
8
  end
@@ -11,13 +11,21 @@ module Braintree
11
11
  "boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
12
12
  }
13
13
 
14
- def self.hash_from_xml(xml)
15
- standardized_hash_structure = ::Braintree::Xml::Libxml.parse(xml)
14
+ def self.hash_from_xml(xml, parser = _determine_parser)
15
+ standardized_hash_structure = parser.parse(xml)
16
16
  with_underscores_in_keys = _unrename_keys(standardized_hash_structure)
17
17
  typecasted_xml = _typecast_xml_value(with_underscores_in_keys)
18
18
  Util.symbolize_keys(typecasted_xml)
19
19
  end
20
20
 
21
+ def self._determine_parser
22
+ if defined?(::LibXml::XML) && ::LibXml::XML.respond_to?(:default_keep_blanks=)
23
+ ::Braintree::Xml::Libxml
24
+ else
25
+ ::Braintree::Xml::Rexml
26
+ end
27
+ end
28
+
21
29
  def self._typecast_xml_value(value)
22
30
  case value.class.to_s
23
31
  when 'Hash'
@@ -0,0 +1,71 @@
1
+ # Portions of this code were copied and modified from Ruby on Rails, released
2
+ # under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
3
+ module Braintree
4
+ module Xml
5
+ module Rexml
6
+
7
+ CONTENT_KEY = '__content__'.freeze
8
+
9
+ def self.parse(string)
10
+ require 'rexml/document' unless defined?(REXML::Document)
11
+ doc = REXML::Document.new(string)
12
+ _merge_element!({}, doc.root)
13
+ end
14
+
15
+ def self._merge_element!(hash, element)
16
+ _merge!(hash, element.name, _collapse(element))
17
+ end
18
+
19
+ def self._collapse(element)
20
+ hash = _get_attributes(element)
21
+
22
+ if element.has_elements?
23
+ element.each_element {|child| _merge_element!(hash, child) }
24
+ _merge_texts!(hash, element) unless _empty_content?(element)
25
+ hash
26
+ else
27
+ _merge_texts!(hash, element)
28
+ end
29
+ end
30
+
31
+ def self._merge_texts!(hash, element)
32
+ unless element.has_text?
33
+ hash
34
+ else
35
+ # must use value to prevent double-escaping
36
+ _merge!(
37
+ hash,
38
+ CONTENT_KEY,
39
+ element.texts.map { |t| t.value}.join
40
+ )
41
+ end
42
+ end
43
+
44
+ def self._merge!(hash, key, value)
45
+ if hash.has_key?(key)
46
+ if hash[key].instance_of?(Array)
47
+ hash[key] << value
48
+ else
49
+ hash[key] = [hash[key], value]
50
+ end
51
+ elsif value.instance_of?(Array)
52
+ hash[key] = [value]
53
+ else
54
+ hash[key] = value
55
+ end
56
+ hash
57
+ end
58
+
59
+ def self._get_attributes(element)
60
+ attributes = {}
61
+ element.attributes.each { |n,v| attributes[n] = v }
62
+ attributes
63
+ end
64
+
65
+ def self._empty_content?(element)
66
+ element.texts.join.strip == ""
67
+ end
68
+ end
69
+ end
70
+ end
71
+