braintree 1.0.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 (65) hide show
  1. data/LICENSE +22 -0
  2. data/README.rdoc +62 -0
  3. data/lib/braintree.rb +66 -0
  4. data/lib/braintree/address.rb +122 -0
  5. data/lib/braintree/base_module.rb +29 -0
  6. data/lib/braintree/configuration.rb +99 -0
  7. data/lib/braintree/credit_card.rb +231 -0
  8. data/lib/braintree/credit_card_verification.rb +31 -0
  9. data/lib/braintree/customer.rb +231 -0
  10. data/lib/braintree/digest.rb +20 -0
  11. data/lib/braintree/error_codes.rb +95 -0
  12. data/lib/braintree/error_result.rb +39 -0
  13. data/lib/braintree/errors.rb +29 -0
  14. data/lib/braintree/http.rb +105 -0
  15. data/lib/braintree/paged_collection.rb +55 -0
  16. data/lib/braintree/ssl_expiration_check.rb +28 -0
  17. data/lib/braintree/successful_result.rb +38 -0
  18. data/lib/braintree/test/credit_card_numbers.rb +50 -0
  19. data/lib/braintree/test/transaction_amounts.rb +10 -0
  20. data/lib/braintree/transaction.rb +360 -0
  21. data/lib/braintree/transaction/address_details.rb +15 -0
  22. data/lib/braintree/transaction/credit_card_details.rb +22 -0
  23. data/lib/braintree/transaction/customer_details.rb +13 -0
  24. data/lib/braintree/transparent_redirect.rb +110 -0
  25. data/lib/braintree/util.rb +94 -0
  26. data/lib/braintree/validation_error.rb +15 -0
  27. data/lib/braintree/validation_error_collection.rb +80 -0
  28. data/lib/braintree/version.rb +9 -0
  29. data/lib/braintree/xml.rb +12 -0
  30. data/lib/braintree/xml/generator.rb +80 -0
  31. data/lib/braintree/xml/libxml.rb +69 -0
  32. data/lib/braintree/xml/parser.rb +93 -0
  33. data/lib/ssl/securetrust_ca.crt +44 -0
  34. data/lib/ssl/valicert_ca.crt +18 -0
  35. data/spec/integration/braintree/address_spec.rb +352 -0
  36. data/spec/integration/braintree/credit_card_spec.rb +676 -0
  37. data/spec/integration/braintree/customer_spec.rb +664 -0
  38. data/spec/integration/braintree/http_spec.rb +201 -0
  39. data/spec/integration/braintree/test/transaction_amounts_spec.rb +29 -0
  40. data/spec/integration/braintree/transaction_spec.rb +900 -0
  41. data/spec/integration/spec_helper.rb +38 -0
  42. data/spec/script/httpsd.rb +27 -0
  43. data/spec/spec_helper.rb +41 -0
  44. data/spec/unit/braintree/address_spec.rb +86 -0
  45. data/spec/unit/braintree/configuration_spec.rb +190 -0
  46. data/spec/unit/braintree/credit_card_spec.rb +137 -0
  47. data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
  48. data/spec/unit/braintree/customer_spec.rb +103 -0
  49. data/spec/unit/braintree/digest_spec.rb +28 -0
  50. data/spec/unit/braintree/error_result_spec.rb +42 -0
  51. data/spec/unit/braintree/errors_spec.rb +81 -0
  52. data/spec/unit/braintree/http_spec.rb +42 -0
  53. data/spec/unit/braintree/paged_collection_spec.rb +128 -0
  54. data/spec/unit/braintree/ssl_expiration_check_spec.rb +92 -0
  55. data/spec/unit/braintree/successful_result_spec.rb +27 -0
  56. data/spec/unit/braintree/transaction/credit_card_details_spec.rb +22 -0
  57. data/spec/unit/braintree/transaction_spec.rb +136 -0
  58. data/spec/unit/braintree/transparent_redirect_spec.rb +154 -0
  59. data/spec/unit/braintree/util_spec.rb +142 -0
  60. data/spec/unit/braintree/validation_error_collection_spec.rb +128 -0
  61. data/spec/unit/braintree/validation_error_spec.rb +19 -0
  62. data/spec/unit/braintree/xml/libxml_spec.rb +51 -0
  63. data/spec/unit/braintree/xml_spec.rb +122 -0
  64. data/spec/unit/spec_helper.rb +1 -0
  65. metadata +118 -0
@@ -0,0 +1,676 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::CreditCard do
4
+
5
+ describe "self.create" do
6
+ it "throws and ArgumentError if given exipiration_date and any combination of expiration_month and expiration_year" do
7
+ expect do
8
+ Braintree::CreditCard.create :expiration_date => "anything", :expiration_month => "anything"
9
+ end.to raise_error(ArgumentError, "create with both expiration_month and expiration_year or only expiration_date")
10
+ end
11
+
12
+ it "adds credit card to an existing customer" do
13
+ customer = Braintree::Customer.create!
14
+ result = Braintree::CreditCard.create(
15
+ :customer_id => customer.id,
16
+ :number => Braintree::Test::CreditCardNumbers::Visa,
17
+ :expiration_date => "05/2009",
18
+ :cvv => "100"
19
+ )
20
+ result.success?.should == true
21
+ credit_card = result.credit_card
22
+ credit_card.token.should =~ /\A\w{4,5}\z/
23
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
24
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
25
+ credit_card.expiration_date.should == "05/2009"
26
+ end
27
+
28
+ it "can specify the desired token" do
29
+ token = "token_#{rand(1_000_000)}"
30
+ customer = Braintree::Customer.create!
31
+ result = Braintree::CreditCard.create(
32
+ :customer_id => customer.id,
33
+ :number => Braintree::Test::CreditCardNumbers::Visa,
34
+ :expiration_date => "05/2009",
35
+ :cvv => "100",
36
+ :token => token
37
+ )
38
+ result.success?.should == true
39
+ credit_card = result.credit_card
40
+ credit_card.token.should == token
41
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
42
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
43
+ credit_card.expiration_date.should == "05/2009"
44
+ end
45
+
46
+ it "verifes the credit card if options[verify_card]=true" do
47
+ customer = Braintree::Customer.create!
48
+ result = Braintree::CreditCard.create(
49
+ :customer_id => customer.id,
50
+ :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
51
+ :expiration_date => "05/2009",
52
+ :options => {:verify_card => true}
53
+ )
54
+ result.success?.should == false
55
+ result.credit_card_verification.status.should == "processor_declined"
56
+ result.credit_card_verification.cvv_response_code.should == "I"
57
+ result.credit_card_verification.avs_error_response_code.should == nil
58
+ result.credit_card_verification.avs_postal_code_response_code.should == "I"
59
+ result.credit_card_verification.avs_street_address_response_code.should == "I"
60
+ end
61
+
62
+ it "does not verify the card if options[verify_card]=false" do
63
+ customer = Braintree::Customer.create!
64
+ result = Braintree::CreditCard.create(
65
+ :customer_id => customer.id,
66
+ :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::Visa,
67
+ :expiration_date => "05/2009",
68
+ :options => {:verify_card => false}
69
+ )
70
+ result.success?.should == true
71
+ end
72
+
73
+ it "adds credit card with billing address to customer" do
74
+ customer = Braintree::Customer.create!
75
+ result = Braintree::CreditCard.create(
76
+ :customer_id => customer.id,
77
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
78
+ :expiration_date => "12/2009",
79
+ :billing_address => {
80
+ :street_address => "123 Abc Way",
81
+ :locality => "Chicago",
82
+ :region => "Illinois",
83
+ :postal_code => "60622"
84
+ }
85
+ )
86
+ result.success?.should == true
87
+ credit_card = result.credit_card
88
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
89
+ credit_card.billing_address.street_address.should == "123 Abc Way"
90
+ end
91
+
92
+ it "returns an error response if unsuccessful" do
93
+ customer = Braintree::Customer.create!
94
+ result = Braintree::CreditCard.create(
95
+ :customer_id => customer.id,
96
+ :number => Braintree::Test::CreditCardNumbers::Visa,
97
+ :expiration_date => "invalid_date"
98
+ )
99
+ result.success?.should == false
100
+ result.errors.for(:credit_card).on(:expiration_date)[0].message.should == "Expiration date is invalid."
101
+ end
102
+ end
103
+
104
+ describe "self.create!" do
105
+ it "returns the credit card if successful" do
106
+ customer = Braintree::Customer.create!
107
+ credit_card = Braintree::CreditCard.create!(
108
+ :customer_id => customer.id,
109
+ :cardholder_name => "Adam Davis",
110
+ :number => Braintree::Test::CreditCardNumbers::Visa,
111
+ :expiration_date => "05/2009"
112
+ )
113
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
114
+ credit_card.cardholder_name.should == "Adam Davis"
115
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
116
+ credit_card.expiration_date.should == "05/2009"
117
+ end
118
+
119
+ it "raises a ValidationsFailed if unsuccessful" do
120
+ customer = Braintree::Customer.create!
121
+ expect do
122
+ Braintree::CreditCard.create!(
123
+ :customer_id => customer.id,
124
+ :number => Braintree::Test::CreditCardNumbers::Visa,
125
+ :expiration_date => "invalid_date"
126
+ )
127
+ end.to raise_error(Braintree::ValidationsFailed)
128
+ end
129
+ end
130
+
131
+ describe "self.credit" do
132
+ it "creates a credit transaction using the payment method token, returning a result object" do
133
+ customer = Braintree::Customer.create!(
134
+ :credit_card => {
135
+ :number => Braintree::Test::CreditCardNumbers::Visa,
136
+ :expiration_date => "05/2010"
137
+ }
138
+ )
139
+ result = Braintree::CreditCard.credit(
140
+ customer.credit_cards[0].token,
141
+ :amount => "100.00"
142
+ )
143
+ result.success?.should == true
144
+ result.transaction.amount.should == "100.00"
145
+ result.transaction.type.should == "credit"
146
+ result.transaction.customer_details.id.should == customer.id
147
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
148
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
149
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
150
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
151
+ end
152
+ end
153
+
154
+ describe "self.credit!" do
155
+ it "creates a credit transaction using the payment method token, returning the transaction" do
156
+ customer = Braintree::Customer.create!(
157
+ :credit_card => {
158
+ :number => Braintree::Test::CreditCardNumbers::Visa,
159
+ :expiration_date => "05/2010"
160
+ }
161
+ )
162
+ transaction = Braintree::CreditCard.credit!(
163
+ customer.credit_cards[0].token,
164
+ :amount => "100.00"
165
+ )
166
+ transaction.amount.should == "100.00"
167
+ transaction.type.should == "credit"
168
+ transaction.customer_details.id.should == customer.id
169
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
170
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
171
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
172
+ transaction.credit_card_details.expiration_date.should == "05/2010"
173
+ end
174
+ end
175
+
176
+ describe "self.create_from_transparent_redirect" do
177
+ it "returns a successful result if successful" do
178
+ result = Braintree::Customer.create
179
+ result.success?.should == true
180
+ customer = result.customer
181
+ params = {
182
+ :credit_card => {
183
+ :cardholder_name => "Card Holder",
184
+ :number => Braintree::Test::CreditCardNumbers::Visa,
185
+ :expiration_date => "05/2012"
186
+ }
187
+ }
188
+ tr_data_params = {
189
+ :credit_card => {
190
+ :customer_id => customer.id
191
+ }
192
+ }
193
+ query_string_response = create_credit_card_via_tr(params, tr_data_params)
194
+ result = Braintree::CreditCard.create_from_transparent_redirect(query_string_response)
195
+ result.success?.should == true
196
+ credit_card = result.credit_card
197
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
198
+ credit_card.cardholder_name.should == "Card Holder"
199
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
200
+ credit_card.expiration_month.should == "05"
201
+ credit_card.expiration_year.should == "2012"
202
+ credit_card.expiration_date.should == "05/2012"
203
+ credit_card.customer_id.should == customer.id
204
+ end
205
+
206
+ it "returns xml with nested errors if validation errors" do
207
+ customer = Braintree::Customer.create.customer
208
+ params = {
209
+ :credit_card => {
210
+ :cardholder_name => "Card Holder",
211
+ :number => "eleventy",
212
+ :expiration_date => "y2k"
213
+ }
214
+ }
215
+ tr_data_params = {
216
+ :credit_card => {
217
+ :customer_id => customer.id
218
+ }
219
+ }
220
+ query_string_response = create_credit_card_via_tr(params, tr_data_params)
221
+ result = Braintree::CreditCard.create_from_transparent_redirect(query_string_response)
222
+ result.success?.should == false
223
+ result.params[:customer_id] == customer.id
224
+ result.params[:credit_card]["cardholder_name"] == customer.id
225
+ result.params[:credit_card]["number"] == "eleventy"
226
+ result.params[:credit_card]["exipiration_date"] == "y2k"
227
+ end
228
+ end
229
+
230
+ describe "self.update_from_transparent_redirect" do
231
+ it "updates the credit card" do
232
+ old_token = "token#{rand(1_000_000)}"
233
+ new_token = "token#{rand(1_000_000)}"
234
+ customer = Braintree::Customer.create!(
235
+ :credit_card => {
236
+ :cardholder_name => "Old Cardholder Name",
237
+ :number => Braintree::Test::CreditCardNumbers::Visa,
238
+ :expiration_date => "05/2012",
239
+ :token => old_token
240
+ }
241
+ )
242
+ credit_card = customer.credit_cards[0]
243
+ params = {
244
+ :credit_card => {
245
+ :cardholder_name => "New Cardholder Name",
246
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
247
+ :expiration_date => "05/2014"
248
+ }
249
+ }
250
+ tr_data_params = {
251
+ :payment_method_token => old_token,
252
+ :credit_card => {
253
+ :token => new_token
254
+ }
255
+ }
256
+ query_string_response = update_credit_card_via_tr(params, tr_data_params)
257
+ result = Braintree::CreditCard.update_from_transparent_redirect(query_string_response)
258
+ result.success?.should == true
259
+ credit_card = result.credit_card
260
+ credit_card.cardholder_name.should == "New Cardholder Name"
261
+ credit_card.masked_number.should == "555555******4444"
262
+ credit_card.expiration_date.should == "05/2014"
263
+ credit_card.token.should == new_token
264
+ end
265
+ end
266
+
267
+ describe "credit" do
268
+ it "creates a credit transaction using the customer, returning a result object" do
269
+ customer = Braintree::Customer.create!(
270
+ :credit_card => {
271
+ :number => Braintree::Test::CreditCardNumbers::Visa,
272
+ :expiration_date => "05/2010"
273
+ }
274
+ )
275
+ result = customer.credit_cards[0].credit(
276
+ :amount => "100.00"
277
+ )
278
+ result.success?.should == true
279
+ result.transaction.amount.should == "100.00"
280
+ result.transaction.type.should == "credit"
281
+ result.transaction.customer_details.id.should == customer.id
282
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
283
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
284
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
285
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
286
+ end
287
+ end
288
+
289
+ describe "credit!" do
290
+ it "returns the created credit tranaction if valid" do
291
+ customer = Braintree::Customer.create!(
292
+ :credit_card => {
293
+ :number => Braintree::Test::CreditCardNumbers::Visa,
294
+ :expiration_date => "05/2010"
295
+ }
296
+ )
297
+ transaction = customer.credit_cards[0].credit!(:amount => "100.00")
298
+ transaction.amount.should == "100.00"
299
+ transaction.type.should == "credit"
300
+ transaction.customer_details.id.should == customer.id
301
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
302
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
303
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
304
+ transaction.credit_card_details.expiration_date.should == "05/2010"
305
+ end
306
+
307
+ it "raises a ValidationsFailed if invalid" do
308
+ customer = Braintree::Customer.create!(
309
+ :credit_card => {
310
+ :number => Braintree::Test::CreditCardNumbers::Visa,
311
+ :expiration_date => "05/2010"
312
+ }
313
+ )
314
+ expect do
315
+ customer.credit_cards[0].credit!(:amount => "invalid")
316
+ end.to raise_error(Braintree::ValidationsFailed)
317
+ end
318
+ end
319
+
320
+ describe "delete" do
321
+ it "deletes the credit card" do
322
+ customer = Braintree::Customer.create.customer
323
+ result = Braintree::CreditCard.create(
324
+ :customer_id => customer.id,
325
+ :number => Braintree::Test::CreditCardNumbers::Visa,
326
+ :expiration_date => "05/2012"
327
+ )
328
+
329
+ result.success?.should == true
330
+ credit_card = result.credit_card
331
+ credit_card.delete.should == true
332
+ expect do
333
+ Braintree::CreditCard.find(credit_card.token)
334
+ end.to raise_error(Braintree::NotFoundError)
335
+ end
336
+ end
337
+
338
+ describe "self.expired" do
339
+ it "finds expired payment methods, paginated" do
340
+ first_page = Braintree::CreditCard.expired
341
+ first_page.current_page_number.should == 1
342
+ first_page.total_items.should > 0
343
+ first_page.all? { |pm| pm.expired?.should == true }
344
+ end
345
+
346
+ it "can get the next_page" do
347
+ first_page = Braintree::CreditCard.expired
348
+ first_page.current_page_number.should == 1
349
+ first_page.all? { |pm| pm.expired?.should == true }
350
+ second_page = first_page.next_page
351
+ # TODO: we don't have enough expired payment methods to go onto a second page
352
+ # second_page.current_page_number.should == 2
353
+ # second_page.all? { |pm| pm.expired?.should == true }
354
+ end
355
+ end
356
+
357
+ describe "self.expiring_between" do
358
+ it "finds payment methods expiring between the given dates" do
359
+ next_year = Time.now.year + 1
360
+ first_page = Braintree::CreditCard.expiring_between(Time.mktime(next_year, 1), Time.mktime(next_year, 12))
361
+ first_page.current_page_number.should == 1
362
+ first_page.total_items.should > 0
363
+ first_page.all? { |pm| pm.expired?.should == false }
364
+ first_page.all? { |pm| pm.expiration_year.should == next_year.to_s }
365
+ end
366
+
367
+ it "can get the next_page" do
368
+ next_year = Time.now.year + 1
369
+ first_page = Braintree::CreditCard.expiring_between(Time.mktime(next_year, 1), Time.mktime(next_year, 12))
370
+ first_page.current_page_number.should == 1
371
+ second_page = first_page.next_page
372
+ # TODO: we don't have enough expired payment methods to go onto a second page
373
+ # second_page.current_page_number.should == 2
374
+ # second_page.all? { |pm| pm.expired?.should == false }
375
+ # second_page.all? { |pm| pm.expiration_year.should == next_year.to_s }
376
+ end
377
+ end
378
+
379
+ describe "self.find" do
380
+ it "finds the payment method with the given token" do
381
+ customer = Braintree::Customer.create.customer
382
+ result = Braintree::CreditCard.create(
383
+ :customer_id => customer.id,
384
+ :number => Braintree::Test::CreditCardNumbers::Visa,
385
+ :expiration_date => "05/2012"
386
+ )
387
+ result.success?.should == true
388
+ credit_card = Braintree::CreditCard.find(result.credit_card.token)
389
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
390
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
391
+ credit_card.token.should == result.credit_card.token
392
+ credit_card.expiration_date.should == "05/2012"
393
+ end
394
+
395
+ it "raises a NotFoundError exception if payment method cannot be found" do
396
+ expect do
397
+ Braintree::CreditCard.find("invalid-token")
398
+ end.to raise_error(Braintree::NotFoundError, 'payment method with token "invalid-token" not found')
399
+ end
400
+ end
401
+
402
+ describe "self.sale" do
403
+ it "creates a sale transaction using the credit card, returning a result object" do
404
+ customer = Braintree::Customer.create!(
405
+ :credit_card => {
406
+ :number => Braintree::Test::CreditCardNumbers::Visa,
407
+ :expiration_date => "05/2010"
408
+ }
409
+ )
410
+ result = Braintree::CreditCard.sale(customer.credit_cards[0].token, :amount => "100.00")
411
+
412
+ result.success?.should == true
413
+ result.transaction.amount.should == "100.00"
414
+ result.transaction.type.should == "sale"
415
+ result.transaction.customer_details.id.should == customer.id
416
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
417
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
418
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
419
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
420
+ end
421
+ end
422
+
423
+ describe "self.sale!" do
424
+ it "creates a sale transaction using the credit card, returning the transaction" do
425
+ customer = Braintree::Customer.create!(
426
+ :credit_card => {
427
+ :number => Braintree::Test::CreditCardNumbers::Visa,
428
+ :expiration_date => "05/2010"
429
+ }
430
+ )
431
+ transaction = Braintree::CreditCard.sale!(customer.credit_cards[0].token, :amount => "100.00")
432
+ transaction.amount.should == "100.00"
433
+ transaction.type.should == "sale"
434
+ transaction.customer_details.id.should == customer.id
435
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
436
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
437
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
438
+ transaction.credit_card_details.expiration_date.should == "05/2010"
439
+ end
440
+ end
441
+
442
+ describe "sale" do
443
+ it "creates a sale transaction using the credit card, returning a result object" do
444
+ customer = Braintree::Customer.create!(
445
+ :credit_card => {
446
+ :number => Braintree::Test::CreditCardNumbers::Visa,
447
+ :expiration_date => "05/2010"
448
+ }
449
+ )
450
+ result = customer.credit_cards[0].sale(
451
+ :amount => "100.00"
452
+ )
453
+ result.success?.should == true
454
+ result.transaction.amount.should == "100.00"
455
+ result.transaction.type.should == "sale"
456
+ result.transaction.customer_details.id.should == customer.id
457
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
458
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
459
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
460
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
461
+ end
462
+ end
463
+
464
+ describe "sale!" do
465
+ it "returns the created sale tranaction if valid" do
466
+ customer = Braintree::Customer.create!(
467
+ :credit_card => {
468
+ :number => Braintree::Test::CreditCardNumbers::Visa,
469
+ :expiration_date => "05/2010"
470
+ }
471
+ )
472
+ transaction = customer.credit_cards[0].sale!(:amount => "100.00")
473
+ transaction.amount.should == "100.00"
474
+ transaction.type.should == "sale"
475
+ transaction.customer_details.id.should == customer.id
476
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
477
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
478
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
479
+ transaction.credit_card_details.expiration_date.should == "05/2010"
480
+ end
481
+
482
+ it "raises a ValidationsFailed if invalid" do
483
+ customer = Braintree::Customer.create!(
484
+ :credit_card => {
485
+ :number => Braintree::Test::CreditCardNumbers::Visa,
486
+ :expiration_date => "05/2010"
487
+ }
488
+ )
489
+ expect do
490
+ customer.credit_cards[0].sale!(:amount => "invalid")
491
+ end.to raise_error(Braintree::ValidationsFailed)
492
+ end
493
+ end
494
+
495
+ describe "update" do
496
+ it "updates the credit card" do
497
+ customer = Braintree::Customer.create!
498
+ credit_card = Braintree::CreditCard.create!(
499
+ :cardholder_name => "Original Holder",
500
+ :customer_id => customer.id,
501
+ :cvv => "123",
502
+ :number => Braintree::Test::CreditCardNumbers::Visa,
503
+ :expiration_date => "05/2012"
504
+ )
505
+ update_result = credit_card.update(
506
+ :cardholder_name => "New Holder",
507
+ :cvv => "456",
508
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
509
+ :expiration_date => "06/2013"
510
+ )
511
+ update_result.success?.should == true
512
+ update_result.credit_card.should == credit_card
513
+ updated_credit_card = update_result.credit_card
514
+ updated_credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
515
+ updated_credit_card.last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
516
+ updated_credit_card.expiration_date.should == "06/2013"
517
+ updated_credit_card.cardholder_name.should == "New Holder"
518
+ end
519
+
520
+ it "verifies the update if options[verify_card]=true" do
521
+ customer = Braintree::Customer.create!
522
+ credit_card = Braintree::CreditCard.create!(
523
+ :cardholder_name => "Original Holder",
524
+ :customer_id => customer.id,
525
+ :cvv => "123",
526
+ :number => Braintree::Test::CreditCardNumbers::Visa,
527
+ :expiration_date => "05/2012"
528
+ )
529
+ update_result = credit_card.update(
530
+ :cardholder_name => "New Holder",
531
+ :cvv => "456",
532
+ :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::MasterCard,
533
+ :expiration_date => "06/2013",
534
+ :options => {:verify_card => true}
535
+ )
536
+ update_result.success?.should == false
537
+ update_result.credit_card_verification.status.should == "processor_declined"
538
+ end
539
+
540
+ it "can update the billing address" do
541
+ customer = Braintree::Customer.create!
542
+ credit_card = Braintree::CreditCard.create!(
543
+ :cardholder_name => "Original Holder",
544
+ :customer_id => customer.id,
545
+ :cvv => "123",
546
+ :number => Braintree::Test::CreditCardNumbers::Visa,
547
+ :expiration_date => "05/2012",
548
+ :billing_address => {
549
+ :first_name => "Old First Name",
550
+ :last_name => "Old Last Name",
551
+ :company => "Old Company",
552
+ :street_address => "123 Old St",
553
+ :extended_address => "Apt Old",
554
+ :locality => "Old City",
555
+ :region => "Old State",
556
+ :postal_code => "12345",
557
+ :country_name => "Canada"
558
+ }
559
+ )
560
+ result = credit_card.update(
561
+ :options => {:verify_card => false},
562
+ :billing_address => {
563
+ :first_name => "New First Name",
564
+ :last_name => "New Last Name",
565
+ :company => "New Company",
566
+ :street_address => "123 New St",
567
+ :extended_address => "Apt New",
568
+ :locality => "New City",
569
+ :region => "New State",
570
+ :postal_code => "56789",
571
+ :country_name => "United States of America"
572
+ }
573
+ )
574
+ result.success?.should == true
575
+ address = result.credit_card.billing_address
576
+ address.should == credit_card.billing_address # making sure credit card instance was updated
577
+ address.first_name.should == "New First Name"
578
+ address.last_name.should == "New Last Name"
579
+ address.company.should == "New Company"
580
+ address.street_address.should == "123 New St"
581
+ address.extended_address.should == "Apt New"
582
+ address.locality.should == "New City"
583
+ address.region.should == "New State"
584
+ address.postal_code.should == "56789"
585
+ address.country_name.should == "United States of America"
586
+ end
587
+
588
+ it "returns an error response if invalid" do
589
+ customer = Braintree::Customer.create!
590
+ credit_card = Braintree::CreditCard.create!(
591
+ :cardholder_name => "Original Holder",
592
+ :customer_id => customer.id,
593
+ :number => Braintree::Test::CreditCardNumbers::Visa,
594
+ :expiration_date => "05/2012"
595
+ )
596
+ update_result = credit_card.update(
597
+ :cardholder_name => "New Holder",
598
+ :number => "invalid",
599
+ :expiration_date => "05/2014"
600
+ )
601
+ update_result.success?.should == false
602
+ update_result.errors.for(:credit_card).on(:number)[0].message.should == "Credit card number must be 12-19 digits."
603
+ end
604
+ end
605
+
606
+ describe "update!" do
607
+ it "updates the credit card and returns true if valid" do
608
+ customer = Braintree::Customer.create!
609
+ credit_card = Braintree::CreditCard.create!(
610
+ :cardholder_name => "Original Holder",
611
+ :customer_id => customer.id,
612
+ :number => Braintree::Test::CreditCardNumbers::Visa,
613
+ :expiration_date => "05/2012"
614
+ )
615
+ credit_card.update!(
616
+ :cardholder_name => "New Holder",
617
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
618
+ :expiration_date => "06/2013"
619
+ ).should == credit_card
620
+ credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
621
+ credit_card.last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
622
+ credit_card.expiration_date.should == "06/2013"
623
+ credit_card.cardholder_name.should == "New Holder"
624
+ credit_card.updated_at.between?(Time.now - 5, Time.now).should == true
625
+ end
626
+
627
+ it "raises a ValidationsFailed if invalid" do
628
+ customer = Braintree::Customer.create!
629
+ credit_card = Braintree::CreditCard.create!(
630
+ :cardholder_name => "Original Holder",
631
+ :customer_id => customer.id,
632
+ :number => Braintree::Test::CreditCardNumbers::Visa,
633
+ :expiration_date => "05/2012"
634
+ )
635
+ expect do
636
+ credit_card.update!(
637
+ :cardholder_name => "New Holder",
638
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
639
+ :expiration_date => "invalid/date"
640
+ )
641
+ end.to raise_error(Braintree::ValidationsFailed)
642
+ end
643
+ end
644
+
645
+ def create_credit_card_via_tr(regular_params, tr_params = {})
646
+ response = nil
647
+ Net::HTTP.start("localhost", 3000) do |http|
648
+ request = Net::HTTP::Post.new("/" + Braintree::CreditCard.create_credit_card_url.split("/", 4)[3])
649
+ request.add_field "Content-Type", "application/x-www-form-urlencoded"
650
+ tr_data = Braintree::TransparentRedirect.create_credit_card_data({:redirect_url => "http://example.com"}.merge(tr_params))
651
+ request.body = Braintree::Util.hash_to_query_string({:tr_data => tr_data}.merge(regular_params))
652
+ response = http.request(request)
653
+ end
654
+ if response.code.to_i == 303
655
+ query_string = response["Location"].split("?", 2).last
656
+ else
657
+ raise "did not receive a valid tr response: #{response.body[0,1000].inspect}"
658
+ end
659
+ end
660
+
661
+ def update_credit_card_via_tr(regular_params, tr_params = {})
662
+ response = nil
663
+ Net::HTTP.start("localhost", 3000) do |http|
664
+ request = Net::HTTP::Post.new("/" + Braintree::CreditCard.update_credit_card_url.split("/", 4)[3])
665
+ request.add_field "Content-Type", "application/x-www-form-urlencoded"
666
+ tr_data = Braintree::TransparentRedirect.update_credit_card_data({:redirect_url => "http://example.com"}.merge(tr_params))
667
+ request.body = Braintree::Util.hash_to_query_string({:tr_data => tr_data}.merge(regular_params))
668
+ response = http.request(request)
669
+ end
670
+ if response.code.to_i == 303
671
+ query_string = response["Location"].split("?", 2).last
672
+ else
673
+ raise "did not receive a valid tr response: #{response.body[0,1000].inspect}"
674
+ end
675
+ end
676
+ end