braintree 2.2.0 → 2.3.1

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.
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
+