braintree 1.0.1 → 1.1.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.
Files changed (60) hide show
  1. data/lib/braintree.rb +36 -46
  2. data/lib/braintree/address.rb +14 -14
  3. data/lib/braintree/base_module.rb +3 -3
  4. data/lib/braintree/configuration.rb +16 -16
  5. data/lib/braintree/credit_card.rb +39 -30
  6. data/lib/braintree/credit_card_verification.rb +4 -3
  7. data/lib/braintree/customer.rb +22 -22
  8. data/lib/braintree/digest.rb +2 -8
  9. data/lib/braintree/error_codes.rb +16 -3
  10. data/lib/braintree/error_result.rb +5 -5
  11. data/lib/braintree/exceptions.rb +58 -0
  12. data/lib/braintree/http.rb +7 -7
  13. data/lib/braintree/paged_collection.rb +14 -14
  14. data/lib/braintree/ssl_expiration_check.rb +5 -1
  15. data/lib/braintree/subscription.rb +110 -0
  16. data/lib/braintree/successful_result.rb +3 -3
  17. data/lib/braintree/test/credit_card_numbers.rb +1 -1
  18. data/lib/braintree/test/transaction_amounts.rb +18 -0
  19. data/lib/braintree/transaction.rb +52 -25
  20. data/lib/braintree/transaction/address_details.rb +2 -2
  21. data/lib/braintree/transaction/credit_card_details.rb +12 -4
  22. data/lib/braintree/transaction/customer_details.rb +9 -1
  23. data/lib/braintree/transaction/status_details.rb +1 -1
  24. data/lib/braintree/transparent_redirect.rb +15 -15
  25. data/lib/braintree/util.rb +7 -7
  26. data/lib/braintree/validation_error.rb +1 -1
  27. data/lib/braintree/validation_error_collection.rb +6 -6
  28. data/lib/braintree/version.rb +3 -3
  29. data/lib/braintree/xml/generator.rb +2 -2
  30. data/lib/braintree/xml/libxml.rb +1 -1
  31. data/lib/braintree/xml/parser.rb +1 -1
  32. data/spec/integration/braintree/address_spec.rb +12 -12
  33. data/spec/integration/braintree/credit_card_spec.rb +189 -37
  34. data/spec/integration/braintree/customer_spec.rb +35 -35
  35. data/spec/integration/braintree/http_spec.rb +3 -3
  36. data/spec/integration/braintree/subscription_spec.rb +362 -0
  37. data/spec/integration/braintree/transaction_spec.rb +130 -58
  38. data/spec/integration/spec_helper.rb +1 -1
  39. data/spec/spec_helper.rb +4 -4
  40. data/spec/unit/braintree/address_spec.rb +6 -6
  41. data/spec/unit/braintree/base_module_spec.rb +18 -0
  42. data/spec/unit/braintree/configuration_spec.rb +10 -10
  43. data/spec/unit/braintree/credit_card_spec.rb +15 -15
  44. data/spec/unit/braintree/credit_card_verification_spec.rb +4 -2
  45. data/spec/unit/braintree/customer_spec.rb +8 -8
  46. data/spec/unit/braintree/digest_spec.rb +4 -0
  47. data/spec/unit/braintree/http_spec.rb +2 -2
  48. data/spec/unit/braintree/paged_collection_spec.rb +12 -12
  49. data/spec/unit/braintree/ssl_expiration_check_spec.rb +18 -9
  50. data/spec/unit/braintree/transaction/credit_card_details_spec.rb +15 -0
  51. data/spec/unit/braintree/transaction/customer_details_spec.rb +19 -0
  52. data/spec/unit/braintree/transaction_spec.rb +14 -14
  53. data/spec/unit/braintree/transparent_redirect_spec.rb +11 -11
  54. data/spec/unit/braintree/util_spec.rb +8 -8
  55. data/spec/unit/braintree/validation_error_collection_spec.rb +6 -6
  56. data/spec/unit/braintree/validation_error_spec.rb +2 -2
  57. data/spec/unit/braintree/xml/libxml_spec.rb +5 -5
  58. data/spec/unit/braintree/xml_spec.rb +16 -16
  59. data/spec/unit/braintree_spec.rb +11 -0
  60. metadata +8 -2
@@ -38,6 +38,20 @@ module Braintree
38
38
  _data(params)
39
39
  end
40
40
 
41
+ def self.parse_and_validate_query_string(query_string) # :nodoc:
42
+ params = Util.symbolize_keys(Util.parse_query_string(query_string))
43
+ query_string_without_hash = query_string[/(.*)&hash=.*/, 1]
44
+ if _hash(query_string_without_hash) == params[:hash]
45
+ if params[:http_status] == '200'
46
+ params
47
+ else
48
+ Util.raise_exception_for_status_code(params[:http_status])
49
+ end
50
+ else
51
+ raise ForgedQueryString
52
+ end
53
+ end
54
+
41
55
  # Returns the tr_data string for creating a transaction.
42
56
  def self.transaction_data(params)
43
57
  Util.verify_keys(TransactionSignature, params)
@@ -78,20 +92,6 @@ module Braintree
78
92
  _data(params)
79
93
  end
80
94
 
81
- def self.parse_and_validate_query_string(query_string) # :nodoc:
82
- params = Util.symbolize_keys(Util.parse_query_string(query_string))
83
- query_string_without_hash = query_string[/(.*)&hash=.*/, 1]
84
- if _hash(query_string_without_hash) == params[:hash]
85
- if params[:http_status] == '200'
86
- params
87
- else
88
- Util.raise_exception_for_status_code(params[:http_status])
89
- end
90
- else
91
- raise ForgedQueryString
92
- end
93
- end
94
-
95
95
  def self._data(params) # :nodoc:
96
96
  raise ArgumentError, "expected params to contain :redirect_url" unless params[:redirect_url]
97
97
  tr_data_segment = Util.hash_to_query_string(params.merge(
@@ -102,7 +102,7 @@ module Braintree
102
102
  tr_data_hash = _hash(tr_data_segment)
103
103
  "#{tr_data_hash}|#{tr_data_segment}"
104
104
  end
105
-
105
+
106
106
  def self._hash(string) # :nodoc:
107
107
  ::Braintree::Digest.hexdigest(string)
108
108
  end
@@ -15,7 +15,7 @@ module Braintree
15
15
  end
16
16
  end.sort * '&'
17
17
  end
18
-
18
+
19
19
  def self.parse_query_string(qs)
20
20
  qs.split('&').inject({}) do |result, couplet|
21
21
  pair = couplet.split('=')
@@ -23,7 +23,7 @@ module Braintree
23
23
  result
24
24
  end
25
25
  end
26
-
26
+
27
27
  def self.url_encode(text)
28
28
  CGI.escape text.to_s
29
29
  end
@@ -37,10 +37,10 @@ module Braintree
37
37
  elsif value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
38
38
  value.each { |v| symbolize_keys(v) }
39
39
  end
40
- end
40
+ end
41
41
  hash
42
42
  end
43
-
43
+
44
44
  def self.raise_exception_for_status_code(status_code)
45
45
  case status_code.to_i
46
46
  when 401
@@ -57,7 +57,7 @@ module Braintree
57
57
  raise UnexpectedError, "Unexpected HTTP_RESPONSE #{status_code.to_i}"
58
58
  end
59
59
  end
60
-
60
+
61
61
  def self.verify_keys(valid_keys, hash)
62
62
  flattened_valid_keys = _flatten_valid_keys(valid_keys)
63
63
  invalid_keys = _flatten_hash_keys(hash) - flattened_valid_keys
@@ -67,7 +67,7 @@ module Braintree
67
67
  raise ArgumentError, "invalid keys: #{sorted}"
68
68
  end
69
69
  end
70
-
70
+
71
71
  def self._flatten_valid_keys(valid_keys, namespace = nil)
72
72
  valid_keys.inject([]) do |result, key|
73
73
  if key.is_a?(Hash)
@@ -85,7 +85,7 @@ module Braintree
85
85
  result
86
86
  end.sort
87
87
  end
88
-
88
+
89
89
  def self._flatten_hash_keys(hash, namespace = nil)
90
90
  hash.inject([]) do |result, (key, value)|
91
91
  full_key = (namespace ? "#{namespace}[#{key}]" : key.to_s)
@@ -7,7 +7,7 @@ module Braintree
7
7
  def initialize(attributes)
8
8
  set_instance_variables_from_hash attributes
9
9
  end
10
-
10
+
11
11
  def inspect # :nodoc:
12
12
  "#<#{self.class} (#{code}) #{message}>"
13
13
  end
@@ -20,7 +20,7 @@ module Braintree
20
20
  # #=> [#<Braintree::ValidationError (91803) Country name is not an accepted country.>]
21
21
  class ValidationErrorCollection
22
22
  include Enumerable
23
-
23
+
24
24
  def initialize(data) # :nodoc:
25
25
  @errors = data[:errors].map { |hash| Braintree::ValidationError.new(hash) }
26
26
  @nested = {}
@@ -29,7 +29,7 @@ module Braintree
29
29
  @nested[key] = ValidationErrorCollection.new(data[key])
30
30
  end
31
31
  end
32
-
32
+
33
33
  # Accesses the error at the given index.
34
34
  def [](index)
35
35
  @errors[index]
@@ -38,7 +38,7 @@ module Braintree
38
38
  def deep_size # :nodoc:
39
39
  size + @nested.values.inject(0) { |count, error_collection| count + error_collection.deep_size }
40
40
  end
41
-
41
+
42
42
  # Iterates over errors at the current level. Nested errors will not be yielded.
43
43
  def each(&block)
44
44
  @errors.each(&block)
@@ -58,11 +58,11 @@ module Braintree
58
58
  def on(attribute)
59
59
  @errors.select { |error| error.attribute == attribute.to_s }
60
60
  end
61
-
61
+
62
62
  # The number of errors at this level. This does not include nested errors.
63
63
  def size
64
64
  @errors.size
65
- end
65
+ end
66
66
 
67
67
  def _inner_inspect(scope = []) # :nodoc:
68
68
  all = []
@@ -75,6 +75,6 @@ module Braintree
75
75
  end
76
76
  all.join(", ")
77
77
  end
78
- end
78
+ end
79
79
  end
80
80
 
@@ -1,9 +1,9 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 1
4
- Minor = 0
5
- Tiny = 1
6
-
4
+ Minor = 1
5
+ Tiny = 0
6
+
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
8
8
  end
9
9
  end
@@ -15,7 +15,7 @@ module Braintree
15
15
  "symbol" => Proc.new { |symbol| symbol.to_s },
16
16
  "datetime" => Proc.new { |time| time.xmlschema },
17
17
  }
18
-
18
+
19
19
  def self.hash_to_xml(hash)
20
20
  root, contents = hash.keys[0], hash.values[0]
21
21
 
@@ -60,7 +60,7 @@ module Braintree
60
60
  end
61
61
 
62
62
  end
63
-
63
+
64
64
  def self._array_to_xml(array, options = {})
65
65
  raise "expected all elements to be hashes" unless array.all? { |e| e.is_a?(Hash) }
66
66
  raise "expected options[:root]" unless options[:root]
@@ -13,7 +13,7 @@ module Braintree
13
13
  ensure
14
14
  ::LibXML::XML.default_keep_blanks = old_keep_blanks_setting
15
15
  end
16
-
16
+
17
17
  def self._node_to_hash(node, hash = {})
18
18
  if node.text?
19
19
  raise ::LibXML::XML::Error if node.content.length >= LIB_XML_LIMIT
@@ -48,7 +48,7 @@ module Braintree
48
48
  ""
49
49
  elsif value.nil? || value['nil'] == 'true'
50
50
  nil
51
- # If the type is the only element which makes it then
51
+ # If the type is the only element which makes it then
52
52
  # this still makes the value nil, except if type is
53
53
  # a XML node(where type['value'] is a Hash)
54
54
  elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
@@ -28,7 +28,7 @@ describe Braintree::Address do
28
28
  result.address.postal_code.should == "60622"
29
29
  result.address.country_name.should == "United States of America"
30
30
  end
31
-
31
+
32
32
  it "returns an error response if invalid" do
33
33
  customer = Braintree::Customer.create!(:last_name => "Wilson")
34
34
  result = Braintree::Address.create(
@@ -72,7 +72,7 @@ describe Braintree::Address do
72
72
  address.postal_code.should == "60623"
73
73
  address.country_name.should == "United States of America"
74
74
  end
75
-
75
+
76
76
  it "raises a ValidationsFailed if invalid" do
77
77
  customer = Braintree::Customer.create!(:last_name => "Wilson")
78
78
  expect do
@@ -83,7 +83,7 @@ describe Braintree::Address do
83
83
  end.to raise_error(Braintree::ValidationsFailed)
84
84
  end
85
85
  end
86
-
86
+
87
87
  describe "self.delete" do
88
88
  it "deletes the address given a customer id and an address id" do
89
89
  customer = Braintree::Customer.create!(:last_name => "Wilson")
@@ -103,7 +103,7 @@ describe Braintree::Address do
103
103
  end.to raise_error(Braintree::NotFoundError)
104
104
  end
105
105
  end
106
-
106
+
107
107
  describe "self.find" do
108
108
  it "finds the address given a customer and an address id" do
109
109
  customer = Braintree::Customer.create!(:last_name => "Wilson")
@@ -116,7 +116,7 @@ describe Braintree::Address do
116
116
  address = Braintree::Address.create!(:customer_id => customer.id, :street_address => "123 E Main St")
117
117
  Braintree::Address.find(customer.id, address.id).should == address
118
118
  end
119
-
119
+
120
120
  it "raises a NotFoundError if it cannot be found because of customer id" do
121
121
  customer = Braintree::Customer.create!(:last_name => "Wilson")
122
122
  address = Braintree::Address.create!(:customer_id => customer.id, :street_address => "123 E Main St")
@@ -137,7 +137,7 @@ describe Braintree::Address do
137
137
  "address for customer \"#{customer.id}\" with id \"invalid\" not found")
138
138
  end
139
139
  end
140
-
140
+
141
141
  describe "self.update" do
142
142
  it "raises NotFoundError if the address can't be found" do
143
143
  customer = Braintree::Customer.create!(:last_name => "Wilson")
@@ -176,7 +176,7 @@ describe Braintree::Address do
176
176
  result.address.postal_code.should == "60621"
177
177
  result.address.country_name.should == "United States of America"
178
178
  end
179
-
179
+
180
180
  it "returns an error response if invalid" do
181
181
  customer = Braintree::Customer.create!(:last_name => "Miller")
182
182
  address = Braintree::Address.create!(
@@ -232,7 +232,7 @@ describe Braintree::Address do
232
232
  updated_address.postal_code.should == "60621"
233
233
  updated_address.country_name.should == "United States of America"
234
234
  end
235
-
235
+
236
236
  it "raises a ValidationsFailed invalid" do
237
237
  customer = Braintree::Customer.create!(:last_name => "Miller")
238
238
  address = Braintree::Address.create!(
@@ -250,7 +250,7 @@ describe Braintree::Address do
250
250
  end
251
251
  end
252
252
 
253
-
253
+
254
254
  describe "delete" do
255
255
  it "deletes the address" do
256
256
  customer = Braintree::Customer.create!(:last_name => "Wilson")
@@ -261,7 +261,7 @@ describe Braintree::Address do
261
261
  end.to raise_error(Braintree::NotFoundError)
262
262
  end
263
263
  end
264
-
264
+
265
265
  describe "update" do
266
266
  it "returns a success response and updates the address if valid" do
267
267
  customer = Braintree::Customer.create!(:last_name => "Miller")
@@ -291,7 +291,7 @@ describe Braintree::Address do
291
291
  address.postal_code.should == "60621"
292
292
  address.country_name.should == "United States of America"
293
293
  end
294
-
294
+
295
295
  it "returns an error response if invalid" do
296
296
  customer = Braintree::Customer.create!(:last_name => "Miller")
297
297
  address = Braintree::Address.create!(
@@ -334,7 +334,7 @@ describe Braintree::Address do
334
334
  address.postal_code.should == "60621"
335
335
  address.country_name.should == "United States of America"
336
336
  end
337
-
337
+
338
338
  it "raises a ValidationsFailed invalid" do
339
339
  customer = Braintree::Customer.create!(:last_name => "Miller")
340
340
  address = Braintree::Address.create!(
@@ -53,6 +53,8 @@ describe Braintree::CreditCard do
53
53
  )
54
54
  result.success?.should == false
55
55
  result.credit_card_verification.status.should == "processor_declined"
56
+ result.credit_card_verification.processor_response_code.should == "2000"
57
+ result.credit_card_verification.processor_response_text.should == "Do Not Honor"
56
58
  result.credit_card_verification.cvv_response_code.should == "I"
57
59
  result.credit_card_verification.avs_error_response_code.should == nil
58
60
  result.credit_card_verification.avs_postal_code_response_code.should == "I"
@@ -69,7 +71,7 @@ describe Braintree::CreditCard do
69
71
  )
70
72
  result.success?.should == true
71
73
  end
72
-
74
+
73
75
  it "adds credit card with billing address to customer" do
74
76
  customer = Braintree::Customer.create!
75
77
  result = Braintree::CreditCard.create(
@@ -88,7 +90,7 @@ describe Braintree::CreditCard do
88
90
  credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
89
91
  credit_card.billing_address.street_address.should == "123 Abc Way"
90
92
  end
91
-
93
+
92
94
  it "returns an error response if unsuccessful" do
93
95
  customer = Braintree::Customer.create!
94
96
  result = Braintree::CreditCard.create(
@@ -127,7 +129,7 @@ describe Braintree::CreditCard do
127
129
  end.to raise_error(Braintree::ValidationsFailed)
128
130
  end
129
131
  end
130
-
132
+
131
133
  describe "self.credit" do
132
134
  it "creates a credit transaction using the payment method token, returning a result object" do
133
135
  customer = Braintree::Customer.create!(
@@ -141,7 +143,7 @@ describe Braintree::CreditCard do
141
143
  :amount => "100.00"
142
144
  )
143
145
  result.success?.should == true
144
- result.transaction.amount.should == "100.00"
146
+ result.transaction.amount.should == BigDecimal.new("100.00")
145
147
  result.transaction.type.should == "credit"
146
148
  result.transaction.customer_details.id.should == customer.id
147
149
  result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -150,7 +152,7 @@ describe Braintree::CreditCard do
150
152
  result.transaction.credit_card_details.expiration_date.should == "05/2010"
151
153
  end
152
154
  end
153
-
155
+
154
156
  describe "self.credit!" do
155
157
  it "creates a credit transaction using the payment method token, returning the transaction" do
156
158
  customer = Braintree::Customer.create!(
@@ -163,7 +165,7 @@ describe Braintree::CreditCard do
163
165
  customer.credit_cards[0].token,
164
166
  :amount => "100.00"
165
167
  )
166
- transaction.amount.should == "100.00"
168
+ transaction.amount.should == BigDecimal.new("100.00")
167
169
  transaction.type.should == "credit"
168
170
  transaction.customer_details.id.should == customer.id
169
171
  transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -202,7 +204,7 @@ describe Braintree::CreditCard do
202
204
  credit_card.expiration_date.should == "05/2012"
203
205
  credit_card.customer_id.should == customer.id
204
206
  end
205
-
207
+
206
208
  it "returns xml with nested errors if validation errors" do
207
209
  customer = Braintree::Customer.create.customer
208
210
  params = {
@@ -218,7 +220,7 @@ describe Braintree::CreditCard do
218
220
  }
219
221
  }
220
222
  query_string_response = create_credit_card_via_tr(params, tr_data_params)
221
- result = Braintree::CreditCard.create_from_transparent_redirect(query_string_response)
223
+ result = Braintree::CreditCard.create_from_transparent_redirect(query_string_response)
222
224
  result.success?.should == false
223
225
  result.params[:customer_id] == customer.id
224
226
  result.params[:credit_card]["cardholder_name"] == customer.id
@@ -227,6 +229,156 @@ describe Braintree::CreditCard do
227
229
  end
228
230
  end
229
231
 
232
+ describe "self.update" do
233
+ it "updates the credit card" do
234
+ customer = Braintree::Customer.create!
235
+ credit_card = Braintree::CreditCard.create!(
236
+ :cardholder_name => "Original Holder",
237
+ :customer_id => customer.id,
238
+ :cvv => "123",
239
+ :number => Braintree::Test::CreditCardNumbers::Visa,
240
+ :expiration_date => "05/2012"
241
+ )
242
+ update_result = Braintree::CreditCard.update(credit_card.token,
243
+ :cardholder_name => "New Holder",
244
+ :cvv => "456",
245
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
246
+ :expiration_date => "06/2013"
247
+ )
248
+ update_result.success?.should == true
249
+ update_result.credit_card.should == credit_card
250
+ updated_credit_card = update_result.credit_card
251
+ updated_credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
252
+ updated_credit_card.last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
253
+ updated_credit_card.expiration_date.should == "06/2013"
254
+ updated_credit_card.cardholder_name.should == "New Holder"
255
+ end
256
+
257
+ it "verifies the update if options[verify_card]=true" do
258
+ customer = Braintree::Customer.create!
259
+ credit_card = Braintree::CreditCard.create!(
260
+ :cardholder_name => "Original Holder",
261
+ :customer_id => customer.id,
262
+ :cvv => "123",
263
+ :number => Braintree::Test::CreditCardNumbers::Visa,
264
+ :expiration_date => "05/2012"
265
+ )
266
+ update_result = Braintree::CreditCard.update(credit_card.token,
267
+ :cardholder_name => "New Holder",
268
+ :cvv => "456",
269
+ :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::MasterCard,
270
+ :expiration_date => "06/2013",
271
+ :options => {:verify_card => true}
272
+ )
273
+ update_result.success?.should == false
274
+ update_result.credit_card_verification.status.should == "processor_declined"
275
+ end
276
+
277
+ it "can update the billing address" do
278
+ customer = Braintree::Customer.create!
279
+ credit_card = Braintree::CreditCard.create!(
280
+ :cardholder_name => "Original Holder",
281
+ :customer_id => customer.id,
282
+ :cvv => "123",
283
+ :number => Braintree::Test::CreditCardNumbers::Visa,
284
+ :expiration_date => "05/2012",
285
+ :billing_address => {
286
+ :first_name => "Old First Name",
287
+ :last_name => "Old Last Name",
288
+ :company => "Old Company",
289
+ :street_address => "123 Old St",
290
+ :extended_address => "Apt Old",
291
+ :locality => "Old City",
292
+ :region => "Old State",
293
+ :postal_code => "12345",
294
+ :country_name => "Canada"
295
+ }
296
+ )
297
+ result = Braintree::CreditCard.update(credit_card.token,
298
+ :options => {:verify_card => false},
299
+ :billing_address => {
300
+ :first_name => "New First Name",
301
+ :last_name => "New Last Name",
302
+ :company => "New Company",
303
+ :street_address => "123 New St",
304
+ :extended_address => "Apt New",
305
+ :locality => "New City",
306
+ :region => "New State",
307
+ :postal_code => "56789",
308
+ :country_name => "United States of America"
309
+ }
310
+ )
311
+ result.success?.should == true
312
+ address = result.credit_card.billing_address
313
+ address.first_name.should == "New First Name"
314
+ address.last_name.should == "New Last Name"
315
+ address.company.should == "New Company"
316
+ address.street_address.should == "123 New St"
317
+ address.extended_address.should == "Apt New"
318
+ address.locality.should == "New City"
319
+ address.region.should == "New State"
320
+ address.postal_code.should == "56789"
321
+ address.country_name.should == "United States of America"
322
+ end
323
+
324
+ it "returns an error response if invalid" do
325
+ customer = Braintree::Customer.create!
326
+ credit_card = Braintree::CreditCard.create!(
327
+ :cardholder_name => "Original Holder",
328
+ :customer_id => customer.id,
329
+ :number => Braintree::Test::CreditCardNumbers::Visa,
330
+ :expiration_date => "05/2012"
331
+ )
332
+ update_result = Braintree::CreditCard.update(credit_card.token,
333
+ :cardholder_name => "New Holder",
334
+ :number => "invalid",
335
+ :expiration_date => "05/2014"
336
+ )
337
+ update_result.success?.should == false
338
+ update_result.errors.for(:credit_card).on(:number)[0].message.should == "Credit card number must be 12-19 digits."
339
+ end
340
+ end
341
+
342
+ describe "self.update!" do
343
+ it "updates the credit card and returns true if valid" do
344
+ customer = Braintree::Customer.create!
345
+ credit_card = Braintree::CreditCard.create!(
346
+ :cardholder_name => "Original Holder",
347
+ :customer_id => customer.id,
348
+ :number => Braintree::Test::CreditCardNumbers::Visa,
349
+ :expiration_date => "05/2012"
350
+ )
351
+ updated_credit_card = Braintree::CreditCard.update!(credit_card.token,
352
+ :cardholder_name => "New Holder",
353
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
354
+ :expiration_date => "06/2013"
355
+ )
356
+ updated_credit_card.token.should == credit_card.token
357
+ updated_credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
358
+ updated_credit_card.last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
359
+ updated_credit_card.expiration_date.should == "06/2013"
360
+ updated_credit_card.cardholder_name.should == "New Holder"
361
+ updated_credit_card.updated_at.between?(Time.now - 5, Time.now).should == true
362
+ end
363
+
364
+ it "raises a ValidationsFailed if invalid" do
365
+ customer = Braintree::Customer.create!
366
+ credit_card = Braintree::CreditCard.create!(
367
+ :cardholder_name => "Original Holder",
368
+ :customer_id => customer.id,
369
+ :number => Braintree::Test::CreditCardNumbers::Visa,
370
+ :expiration_date => "05/2012"
371
+ )
372
+ expect do
373
+ Braintree::CreditCard.update!(credit_card.token,
374
+ :cardholder_name => "New Holder",
375
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
376
+ :expiration_date => "invalid/date"
377
+ )
378
+ end.to raise_error(Braintree::ValidationsFailed)
379
+ end
380
+ end
381
+
230
382
  describe "self.update_from_transparent_redirect" do
231
383
  it "updates the credit card" do
232
384
  old_token = "token#{rand(1_000_000)}"
@@ -276,7 +428,7 @@ describe Braintree::CreditCard do
276
428
  :amount => "100.00"
277
429
  )
278
430
  result.success?.should == true
279
- result.transaction.amount.should == "100.00"
431
+ result.transaction.amount.should == BigDecimal.new("100.00")
280
432
  result.transaction.type.should == "credit"
281
433
  result.transaction.customer_details.id.should == customer.id
282
434
  result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -295,7 +447,7 @@ describe Braintree::CreditCard do
295
447
  }
296
448
  )
297
449
  transaction = customer.credit_cards[0].credit!(:amount => "100.00")
298
- transaction.amount.should == "100.00"
450
+ transaction.amount.should == BigDecimal.new("100.00")
299
451
  transaction.type.should == "credit"
300
452
  transaction.customer_details.id.should == customer.id
301
453
  transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -303,7 +455,7 @@ describe Braintree::CreditCard do
303
455
  transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
304
456
  transaction.credit_card_details.expiration_date.should == "05/2010"
305
457
  end
306
-
458
+
307
459
  it "raises a ValidationsFailed if invalid" do
308
460
  customer = Braintree::Customer.create!(
309
461
  :credit_card => {
@@ -316,16 +468,16 @@ describe Braintree::CreditCard do
316
468
  end.to raise_error(Braintree::ValidationsFailed)
317
469
  end
318
470
  end
319
-
471
+
320
472
  describe "delete" do
321
473
  it "deletes the credit card" do
322
474
  customer = Braintree::Customer.create.customer
323
475
  result = Braintree::CreditCard.create(
324
476
  :customer_id => customer.id,
325
477
  :number => Braintree::Test::CreditCardNumbers::Visa,
326
- :expiration_date => "05/2012"
478
+ :expiration_date => "05/2012"
327
479
  )
328
-
480
+
329
481
  result.success?.should == true
330
482
  credit_card = result.credit_card
331
483
  credit_card.delete.should == true
@@ -334,7 +486,7 @@ describe Braintree::CreditCard do
334
486
  end.to raise_error(Braintree::NotFoundError)
335
487
  end
336
488
  end
337
-
489
+
338
490
  describe "self.expired" do
339
491
  it "finds expired payment methods, paginated" do
340
492
  first_page = Braintree::CreditCard.expired
@@ -353,7 +505,7 @@ describe Braintree::CreditCard do
353
505
  # second_page.all? { |pm| pm.expired?.should == true }
354
506
  end
355
507
  end
356
-
508
+
357
509
  describe "self.expiring_between" do
358
510
  it "finds payment methods expiring between the given dates" do
359
511
  next_year = Time.now.year + 1
@@ -382,7 +534,7 @@ describe Braintree::CreditCard do
382
534
  result = Braintree::CreditCard.create(
383
535
  :customer_id => customer.id,
384
536
  :number => Braintree::Test::CreditCardNumbers::Visa,
385
- :expiration_date => "05/2012"
537
+ :expiration_date => "05/2012"
386
538
  )
387
539
  result.success?.should == true
388
540
  credit_card = Braintree::CreditCard.find(result.credit_card.token)
@@ -391,14 +543,14 @@ describe Braintree::CreditCard do
391
543
  credit_card.token.should == result.credit_card.token
392
544
  credit_card.expiration_date.should == "05/2012"
393
545
  end
394
-
546
+
395
547
  it "raises a NotFoundError exception if payment method cannot be found" do
396
548
  expect do
397
549
  Braintree::CreditCard.find("invalid-token")
398
550
  end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found')
399
551
  end
400
552
  end
401
-
553
+
402
554
  describe "self.sale" do
403
555
  it "creates a sale transaction using the credit card, returning a result object" do
404
556
  customer = Braintree::Customer.create!(
@@ -410,7 +562,7 @@ describe Braintree::CreditCard do
410
562
  result = Braintree::CreditCard.sale(customer.credit_cards[0].token, :amount => "100.00")
411
563
 
412
564
  result.success?.should == true
413
- result.transaction.amount.should == "100.00"
565
+ result.transaction.amount.should == BigDecimal.new("100.00")
414
566
  result.transaction.type.should == "sale"
415
567
  result.transaction.customer_details.id.should == customer.id
416
568
  result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -429,7 +581,7 @@ describe Braintree::CreditCard do
429
581
  }
430
582
  )
431
583
  transaction = Braintree::CreditCard.sale!(customer.credit_cards[0].token, :amount => "100.00")
432
- transaction.amount.should == "100.00"
584
+ transaction.amount.should == BigDecimal.new("100.00")
433
585
  transaction.type.should == "sale"
434
586
  transaction.customer_details.id.should == customer.id
435
587
  transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -438,7 +590,7 @@ describe Braintree::CreditCard do
438
590
  transaction.credit_card_details.expiration_date.should == "05/2010"
439
591
  end
440
592
  end
441
-
593
+
442
594
  describe "sale" do
443
595
  it "creates a sale transaction using the credit card, returning a result object" do
444
596
  customer = Braintree::Customer.create!(
@@ -451,7 +603,7 @@ describe Braintree::CreditCard do
451
603
  :amount => "100.00"
452
604
  )
453
605
  result.success?.should == true
454
- result.transaction.amount.should == "100.00"
606
+ result.transaction.amount.should == BigDecimal.new("100.00")
455
607
  result.transaction.type.should == "sale"
456
608
  result.transaction.customer_details.id.should == customer.id
457
609
  result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -470,7 +622,7 @@ describe Braintree::CreditCard do
470
622
  }
471
623
  )
472
624
  transaction = customer.credit_cards[0].sale!(:amount => "100.00")
473
- transaction.amount.should == "100.00"
625
+ transaction.amount.should == BigDecimal.new("100.00")
474
626
  transaction.type.should == "sale"
475
627
  transaction.customer_details.id.should == customer.id
476
628
  transaction.credit_card_details.token.should == customer.credit_cards[0].token
@@ -478,7 +630,7 @@ describe Braintree::CreditCard do
478
630
  transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
479
631
  transaction.credit_card_details.expiration_date.should == "05/2010"
480
632
  end
481
-
633
+
482
634
  it "raises a ValidationsFailed if invalid" do
483
635
  customer = Braintree::Customer.create!(
484
636
  :credit_card => {
@@ -491,7 +643,7 @@ describe Braintree::CreditCard do
491
643
  end.to raise_error(Braintree::ValidationsFailed)
492
644
  end
493
645
  end
494
-
646
+
495
647
  describe "update" do
496
648
  it "updates the credit card" do
497
649
  customer = Braintree::Customer.create!
@@ -500,7 +652,7 @@ describe Braintree::CreditCard do
500
652
  :customer_id => customer.id,
501
653
  :cvv => "123",
502
654
  :number => Braintree::Test::CreditCardNumbers::Visa,
503
- :expiration_date => "05/2012"
655
+ :expiration_date => "05/2012"
504
656
  )
505
657
  update_result = credit_card.update(
506
658
  :cardholder_name => "New Holder",
@@ -524,7 +676,7 @@ describe Braintree::CreditCard do
524
676
  :customer_id => customer.id,
525
677
  :cvv => "123",
526
678
  :number => Braintree::Test::CreditCardNumbers::Visa,
527
- :expiration_date => "05/2012"
679
+ :expiration_date => "05/2012"
528
680
  )
529
681
  update_result = credit_card.update(
530
682
  :cardholder_name => "New Holder",
@@ -555,7 +707,7 @@ describe Braintree::CreditCard do
555
707
  :region => "Old State",
556
708
  :postal_code => "12345",
557
709
  :country_name => "Canada"
558
- }
710
+ }
559
711
  )
560
712
  result = credit_card.update(
561
713
  :options => {:verify_card => false},
@@ -584,14 +736,14 @@ describe Braintree::CreditCard do
584
736
  address.postal_code.should == "56789"
585
737
  address.country_name.should == "United States of America"
586
738
  end
587
-
739
+
588
740
  it "returns an error response if invalid" do
589
741
  customer = Braintree::Customer.create!
590
742
  credit_card = Braintree::CreditCard.create!(
591
743
  :cardholder_name => "Original Holder",
592
744
  :customer_id => customer.id,
593
745
  :number => Braintree::Test::CreditCardNumbers::Visa,
594
- :expiration_date => "05/2012"
746
+ :expiration_date => "05/2012"
595
747
  )
596
748
  update_result = credit_card.update(
597
749
  :cardholder_name => "New Holder",
@@ -610,7 +762,7 @@ describe Braintree::CreditCard do
610
762
  :cardholder_name => "Original Holder",
611
763
  :customer_id => customer.id,
612
764
  :number => Braintree::Test::CreditCardNumbers::Visa,
613
- :expiration_date => "05/2012"
765
+ :expiration_date => "05/2012"
614
766
  )
615
767
  credit_card.update!(
616
768
  :cardholder_name => "New Holder",
@@ -623,14 +775,14 @@ describe Braintree::CreditCard do
623
775
  credit_card.cardholder_name.should == "New Holder"
624
776
  credit_card.updated_at.between?(Time.now - 5, Time.now).should == true
625
777
  end
626
-
778
+
627
779
  it "raises a ValidationsFailed if invalid" do
628
780
  customer = Braintree::Customer.create!
629
781
  credit_card = Braintree::CreditCard.create!(
630
782
  :cardholder_name => "Original Holder",
631
783
  :customer_id => customer.id,
632
784
  :number => Braintree::Test::CreditCardNumbers::Visa,
633
- :expiration_date => "05/2012"
785
+ :expiration_date => "05/2012"
634
786
  )
635
787
  expect do
636
788
  credit_card.update!(
@@ -641,7 +793,7 @@ describe Braintree::CreditCard do
641
793
  end.to raise_error(Braintree::ValidationsFailed)
642
794
  end
643
795
  end
644
-
796
+
645
797
  def create_credit_card_via_tr(regular_params, tr_params = {})
646
798
  response = nil
647
799
  Net::HTTP.start("localhost", Braintree::Configuration.port) do |http|
@@ -652,7 +804,7 @@ describe Braintree::CreditCard do
652
804
  response = http.request(request)
653
805
  end
654
806
  if response.code.to_i == 303
655
- query_string = response["Location"].split("?", 2).last
807
+ query_string = response["Location"].split("?", 2).last
656
808
  else
657
809
  raise "did not receive a valid tr response: #{response.body[0,1000].inspect}"
658
810
  end
@@ -668,7 +820,7 @@ describe Braintree::CreditCard do
668
820
  response = http.request(request)
669
821
  end
670
822
  if response.code.to_i == 303
671
- query_string = response["Location"].split("?", 2).last
823
+ query_string = response["Location"].split("?", 2).last
672
824
  else
673
825
  raise "did not receive a valid tr response: #{response.body[0,1000].inspect}"
674
826
  end