braintree 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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