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,664 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Customer do
4
+ describe "self.all" do
5
+ it "returns page 1 if page isn't specified" do
6
+ first_page = Braintree::Customer.all
7
+ first_page.current_page_number.should == 1
8
+ end
9
+
10
+ it "can get the next_page" do
11
+ first_page = Braintree::Customer.all
12
+ first_page.current_page_number.should == 1
13
+ second_page = first_page.next_page
14
+ second_page.current_page_number.should == 2
15
+ end
16
+ end
17
+
18
+ describe "self.delete" do
19
+ it "deletes the customer with the given id" do
20
+ create_result = Braintree::Customer.create(
21
+ :first_name => "Joe",
22
+ :last_name => "Cool"
23
+ )
24
+ create_result.success?.should == true
25
+ customer = create_result.customer
26
+
27
+ delete_result = Braintree::Customer.delete(customer.id)
28
+ delete_result.success?.should == true
29
+ expect do
30
+ Braintree::Customer.find(customer.id)
31
+ end.to raise_error(Braintree::NotFoundError)
32
+ end
33
+ end
34
+
35
+ describe "self.create" do
36
+ it "returns a successful result if successful" do
37
+ result = Braintree::Customer.create(
38
+ :first_name => "Bill",
39
+ :last_name => "Gates",
40
+ :company => "Microsoft",
41
+ :email => "bill@microsoft.com",
42
+ :phone => "312.555.1234",
43
+ :fax => "614.555.5678",
44
+ :website => "www.microsoft.com"
45
+ )
46
+ result.success?.should == true
47
+ result.customer.id.should =~ /^\d{6}$/
48
+ result.customer.first_name.should == "Bill"
49
+ result.customer.last_name.should == "Gates"
50
+ result.customer.company.should == "Microsoft"
51
+ result.customer.email.should == "bill@microsoft.com"
52
+ result.customer.phone.should == "312.555.1234"
53
+ result.customer.fax.should == "614.555.5678"
54
+ result.customer.website.should == "www.microsoft.com"
55
+ result.customer.created_at.between?(Time.now - 10, Time.now).should == true
56
+ result.customer.updated_at.between?(Time.now - 10, Time.now).should == true
57
+ end
58
+
59
+ it "can create without any attributes" do
60
+ result = Braintree::Customer.create
61
+ result.success?.should == true
62
+ end
63
+
64
+ it "returns an error response if invalid" do
65
+ result = Braintree::Customer.create(
66
+ :email => "@invalid.com"
67
+ )
68
+ result.success?.should == false
69
+ result.errors.for(:customer).on(:email)[0].message.should == "Email is an invalid format."
70
+ end
71
+
72
+ it "can create a customer and a payment method at the same time" do
73
+ result = Braintree::Customer.create(
74
+ :first_name => "Mike",
75
+ :last_name => "Jones",
76
+ :credit_card => {
77
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
78
+ :expiration_date => "05/2010",
79
+ :cvv => "100"
80
+ }
81
+ )
82
+ result.success?.should == true
83
+ result.customer.first_name.should == "Mike"
84
+ result.customer.last_name.should == "Jones"
85
+ result.customer.credit_cards[0].bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
86
+ result.customer.credit_cards[0].last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
87
+ result.customer.credit_cards[0].expiration_date.should == "05/2010"
88
+ end
89
+
90
+ it "verifies the card if credit_card[options][verify_card]=true" do
91
+ result = Braintree::Customer.create(
92
+ :first_name => "Mike",
93
+ :last_name => "Jones",
94
+ :credit_card => {
95
+ :number => Braintree::Test::CreditCardNumbers::FailsSandboxVerification::MasterCard,
96
+ :expiration_date => "05/2010",
97
+ :options => {:verify_card => true}
98
+ }
99
+ )
100
+ result.success?.should == false
101
+ result.credit_card_verification.status.should == "processor_declined"
102
+ end
103
+
104
+ it "can create a customer, payment method, and billing address at the same time" do
105
+ result = Braintree::Customer.create(
106
+ :first_name => "Mike",
107
+ :last_name => "Jones",
108
+ :credit_card => {
109
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
110
+ :expiration_date => "05/2010",
111
+ :billing_address => {
112
+ :street_address => "1 E Main St",
113
+ :extended_address => "Suite 3",
114
+ :locality => "Chicago",
115
+ :region => "Illinois",
116
+ :postal_code => "60622",
117
+ :country_name => "United States of America"
118
+ }
119
+ }
120
+ )
121
+ result.success?.should == true
122
+ result.customer.first_name.should == "Mike"
123
+ result.customer.last_name.should == "Jones"
124
+ result.customer.credit_cards[0].bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
125
+ result.customer.credit_cards[0].last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
126
+ result.customer.credit_cards[0].expiration_date.should == "05/2010"
127
+ result.customer.credit_cards[0].billing_address.id.should == result.customer.addresses[0].id
128
+ result.customer.addresses[0].id.should =~ /\w+/
129
+ result.customer.addresses[0].street_address.should == "1 E Main St"
130
+ result.customer.addresses[0].extended_address.should == "Suite 3"
131
+ result.customer.addresses[0].locality.should == "Chicago"
132
+ result.customer.addresses[0].region.should == "Illinois"
133
+ result.customer.addresses[0].postal_code.should == "60622"
134
+ result.customer.addresses[0].country_name.should == "United States of America"
135
+ end
136
+
137
+ it "returns nested errors if credit card and/or billing address are invalid" do
138
+ result = Braintree::Customer.create(
139
+ :email => "invalid",
140
+ :credit_card => {
141
+ :number => "invalidnumber",
142
+ :billing_address => {
143
+ :country_name => "invalid"
144
+ }
145
+ }
146
+ )
147
+ result.success?.should == false
148
+ result.errors.for(:customer).on(:email)[0].message.should == "Email is an invalid format."
149
+ result.errors.for(:customer).for(:credit_card).on(:number)[0].message.should == "Credit card number is invalid."
150
+ result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_name)[0].message.should == "Country name is not an accepted country."
151
+ end
152
+ end
153
+
154
+ describe "self.create!" do
155
+ it "returns the customer if successful" do
156
+ customer = Braintree::Customer.create!(
157
+ :first_name => "Jim",
158
+ :last_name => "Smith"
159
+ )
160
+ customer.id.should =~ /\d+/
161
+ customer.first_name.should == "Jim"
162
+ customer.last_name.should == "Smith"
163
+ end
164
+
165
+ it "can create without any attributes" do
166
+ customer = Braintree::Customer.create!
167
+ customer.id.should =~ /\d+/
168
+ end
169
+
170
+ it "raises an exception if not successful" do
171
+ expect do
172
+ Braintree::Customer.create!(:email => "@foo.com")
173
+ end.to raise_error(Braintree::ValidationsFailed)
174
+ end
175
+ end
176
+
177
+ describe "self.credit" do
178
+ it "creates a credit transaction for given customer id, returning a result object" do
179
+ customer = Braintree::Customer.create!(
180
+ :credit_card => {
181
+ :number => Braintree::Test::CreditCardNumbers::Visa,
182
+ :expiration_date => "05/2010"
183
+ }
184
+ )
185
+ result = Braintree::Customer.credit(customer.id, :amount => "100.00")
186
+ result.success?.should == true
187
+ result.transaction.amount.should == "100.00"
188
+ result.transaction.type.should == "credit"
189
+ result.transaction.customer_details.id.should == customer.id
190
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
191
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
192
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
193
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
194
+ end
195
+ end
196
+
197
+ describe "self.credit!" do
198
+ it "creates a credit transaction for given customer id, returning a result object" do
199
+ customer = Braintree::Customer.create!(
200
+ :credit_card => {
201
+ :number => Braintree::Test::CreditCardNumbers::Visa,
202
+ :expiration_date => "05/2010"
203
+ }
204
+ )
205
+ transaction = Braintree::Customer.credit!(customer.id, :amount => "100.00")
206
+ transaction.amount.should == "100.00"
207
+ transaction.type.should == "credit"
208
+ transaction.customer_details.id.should == customer.id
209
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
210
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
211
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
212
+ transaction.credit_card_details.expiration_date.should == "05/2010"
213
+ end
214
+ end
215
+
216
+ describe "self.sale" do
217
+ it "creates a sale transaction for given customer id, returning a result object" do
218
+ customer = Braintree::Customer.create!(
219
+ :credit_card => {
220
+ :number => Braintree::Test::CreditCardNumbers::Visa,
221
+ :expiration_date => "05/2010"
222
+ }
223
+ )
224
+ result = Braintree::Customer.sale(customer.id, :amount => "100.00")
225
+ result.success?.should == true
226
+ result.transaction.amount.should == "100.00"
227
+ result.transaction.type.should == "sale"
228
+ result.transaction.customer_details.id.should == customer.id
229
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
230
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
231
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
232
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
233
+ end
234
+ end
235
+
236
+ describe "self.sale!" do
237
+ it "creates a sale transaction for given customer id, returning the transaction" do
238
+ customer = Braintree::Customer.create!(
239
+ :credit_card => {
240
+ :number => Braintree::Test::CreditCardNumbers::Visa,
241
+ :expiration_date => "05/2010"
242
+ }
243
+ )
244
+ transaction = Braintree::Customer.sale!(customer.id, :amount => "100.00")
245
+ transaction.amount.should == "100.00"
246
+ transaction.type.should == "sale"
247
+ transaction.customer_details.id.should == customer.id
248
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
249
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
250
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
251
+ transaction.credit_card_details.expiration_date.should == "05/2010"
252
+ end
253
+ end
254
+
255
+
256
+ describe "sale" do
257
+ it "creates a sale transaction using the customer, returning a result object" do
258
+ customer = Braintree::Customer.create!(
259
+ :credit_card => {
260
+ :number => Braintree::Test::CreditCardNumbers::Visa,
261
+ :expiration_date => "05/2010"
262
+ }
263
+ )
264
+ result = customer.sale(
265
+ :amount => "100.00"
266
+ )
267
+ result.success?.should == true
268
+ result.transaction.amount.should == "100.00"
269
+ result.transaction.type.should == "sale"
270
+ result.transaction.customer_details.id.should == customer.id
271
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
272
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
273
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
274
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
275
+ end
276
+ end
277
+
278
+ describe "sale!" do
279
+ it "returns the created sale tranaction if valid" do
280
+ customer = Braintree::Customer.create!(
281
+ :credit_card => {
282
+ :number => Braintree::Test::CreditCardNumbers::Visa,
283
+ :expiration_date => "05/2010"
284
+ }
285
+ )
286
+ transaction = customer.sale!(:amount => "100.00")
287
+ transaction.amount.should == "100.00"
288
+ transaction.type.should == "sale"
289
+ transaction.customer_details.id.should == customer.id
290
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
291
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
292
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
293
+ transaction.credit_card_details.expiration_date.should == "05/2010"
294
+ end
295
+ end
296
+
297
+ describe "transactions" do
298
+ it "finds transactions for the customer" do
299
+ customer = Braintree::Customer.create!(
300
+ :credit_card => {
301
+ :number => Braintree::Test::CreditCardNumbers::Visa,
302
+ :expiration_date => "05/2010"
303
+ }
304
+ )
305
+ transaction = customer.sale!(:amount => "100.00")
306
+ collection = customer.transactions
307
+ collection.current_page_number.should == 1
308
+ collection.total_items.should == 1
309
+ collection[0].should == transaction
310
+ end
311
+ end
312
+
313
+ describe "credit" do
314
+ it "creates a credit transaction using the customer, returning a result object" do
315
+ customer = Braintree::Customer.create!(
316
+ :credit_card => {
317
+ :number => Braintree::Test::CreditCardNumbers::Visa,
318
+ :expiration_date => "05/2010"
319
+ }
320
+ )
321
+ result = customer.credit(
322
+ :amount => "100.00"
323
+ )
324
+ result.success?.should == true
325
+ result.transaction.amount.should == "100.00"
326
+ result.transaction.type.should == "credit"
327
+ result.transaction.customer_details.id.should == customer.id
328
+ result.transaction.credit_card_details.token.should == customer.credit_cards[0].token
329
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
330
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
331
+ result.transaction.credit_card_details.expiration_date.should == "05/2010"
332
+ end
333
+ end
334
+
335
+ describe "credit!" do
336
+ it "returns the created credit tranaction if valid" do
337
+ customer = Braintree::Customer.create!(
338
+ :credit_card => {
339
+ :number => Braintree::Test::CreditCardNumbers::Visa,
340
+ :expiration_date => "05/2010"
341
+ }
342
+ )
343
+ transaction = customer.credit!(:amount => "100.00")
344
+ transaction.amount.should == "100.00"
345
+ transaction.type.should == "credit"
346
+ transaction.customer_details.id.should == customer.id
347
+ transaction.credit_card_details.token.should == customer.credit_cards[0].token
348
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
349
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
350
+ transaction.credit_card_details.expiration_date.should == "05/2010"
351
+ end
352
+ end
353
+
354
+ describe "create_from_transparent_redirect" do
355
+ it "returns a successful result if successful" do
356
+ params = {
357
+ :customer => {
358
+ :first_name => "John",
359
+ :last_name => "Doe",
360
+ :company => "Doe Co",
361
+ :email => "john@doe.com",
362
+ :phone => "312.555.2323",
363
+ :fax => "614.555.5656",
364
+ :website => "www.johndoe.com"
365
+ }
366
+ }
367
+ query_string_response = create_customer_via_tr(params)
368
+ result = Braintree::Customer.create_from_transparent_redirect(query_string_response)
369
+ result.success?.should == true
370
+ customer = result.customer
371
+ customer.first_name.should == "John"
372
+ customer.last_name.should == "Doe"
373
+ customer.company.should == "Doe Co"
374
+ customer.email.should == "john@doe.com"
375
+ customer.phone.should == "312.555.2323"
376
+ customer.fax.should == "614.555.5656"
377
+ customer.website.should == "www.johndoe.com"
378
+ end
379
+
380
+ it "can pass any attribute through tr_data" do
381
+ customer_id = "customer_#{rand(1_000_000)}"
382
+ tr_data_params = {
383
+ :customer => {
384
+ :id => customer_id,
385
+ :first_name => "John",
386
+ :last_name => "Doe",
387
+ :company => "Doe Co",
388
+ :email => "john@doe.com",
389
+ :phone => "312.555.2323",
390
+ :fax => "614.555.5656",
391
+ :website => "www.johndoe.com"
392
+ }
393
+ }
394
+ query_string_response = create_customer_via_tr({}, tr_data_params)
395
+ result = Braintree::Customer.create_from_transparent_redirect(query_string_response)
396
+ result.success?.should == true
397
+ customer = result.customer
398
+ customer.id.should == customer_id
399
+ customer.first_name.should == "John"
400
+ customer.last_name.should == "Doe"
401
+ customer.company.should == "Doe Co"
402
+ customer.email.should == "john@doe.com"
403
+ customer.phone.should == "312.555.2323"
404
+ customer.fax.should == "614.555.5656"
405
+ customer.website.should == "www.johndoe.com"
406
+ end
407
+ end
408
+
409
+ describe "delete" do
410
+ it "deletes the customer" do
411
+ result = Braintree::Customer.create(
412
+ :first_name => "Joe",
413
+ :last_name => "Cool"
414
+ )
415
+ result.success?.should == true
416
+
417
+ customer = result.customer
418
+ customer.delete.success?.should == true
419
+ expect do
420
+ Braintree::Customer.find(customer.id)
421
+ end.to raise_error(Braintree::NotFoundError)
422
+ end
423
+ end
424
+
425
+
426
+ describe "self.find" do
427
+ it "finds the customer with the given id" do
428
+ result = Braintree::Customer.create(
429
+ :first_name => "Joe",
430
+ :last_name => "Cool"
431
+ )
432
+ result.success?.should == true
433
+
434
+ customer = Braintree::Customer.find(result.customer.id)
435
+ customer.id.should == result.customer.id
436
+ customer.first_name.should == "Joe"
437
+ customer.last_name.should == "Cool"
438
+ end
439
+
440
+ it "raises a NotFoundError exception if customer cannot be found" do
441
+ expect do
442
+ Braintree::Customer.find("invalid-id")
443
+ end.to raise_error(Braintree::NotFoundError, 'customer with id "invalid-id" not found')
444
+ end
445
+ end
446
+
447
+ describe "self.update" do
448
+ it "updates the customer with the given id if successful" do
449
+ customer = Braintree::Customer.create!(
450
+ :first_name => "Joe",
451
+ :last_name => "Cool"
452
+ )
453
+ result = Braintree::Customer.update(
454
+ customer.id,
455
+ :first_name => "Mr. Joe",
456
+ :last_name => "Super Cool"
457
+ )
458
+ result.success?.should == true
459
+ result.customer.id.should == customer.id
460
+ result.customer.first_name.should == "Mr. Joe"
461
+ result.customer.last_name.should == "Super Cool"
462
+ end
463
+
464
+ it "returns an error response if invalid" do
465
+ customer = Braintree::Customer.create!(:email => "valid@email.com")
466
+ result = Braintree::Customer.update(
467
+ customer.id,
468
+ :email => "@invalid.com"
469
+ )
470
+ result.success?.should == false
471
+ result.errors.for(:customer).on(:email)[0].message.should == "Email is an invalid format."
472
+ end
473
+ end
474
+
475
+ describe "self.update!" do
476
+ it "returns the updated customer if successful" do
477
+ customer = Braintree::Customer.create!(
478
+ :first_name => "Joe",
479
+ :last_name => "Cool"
480
+ )
481
+ updated_customer = Braintree::Customer.update!(
482
+ customer.id,
483
+ :first_name => "Mr. Joe",
484
+ :last_name => "Super Cool"
485
+ )
486
+ updated_customer.first_name.should == "Mr. Joe"
487
+ updated_customer.last_name.should == "Super Cool"
488
+ updated_customer.updated_at.between?(Time.now - 5, Time.now).should == true
489
+ end
490
+
491
+ it "raises an error if unsuccessful" do
492
+ customer = Braintree::Customer.create!(:email => "valid@email.com")
493
+ expect do
494
+ Braintree::Customer.update!(customer.id, :email => "@invalid.com")
495
+ end.to raise_error(Braintree::ValidationsFailed)
496
+ end
497
+ end
498
+
499
+ describe "update" do
500
+ it "updates the customer" do
501
+ customer = Braintree::Customer.create!(
502
+ :first_name => "Joe",
503
+ :last_name => "Cool"
504
+ )
505
+ update_result = customer.update(
506
+ :first_name => "Mr. Joe",
507
+ :last_name => "Super Cool"
508
+ )
509
+ update_result.success?.should == true
510
+ update_result.customer.should == customer
511
+ updated_customer = update_result.customer
512
+ updated_customer.first_name.should == "Mr. Joe"
513
+ updated_customer.last_name.should == "Super Cool"
514
+ end
515
+
516
+ it "returns an error response if invalid" do
517
+ customer = Braintree::Customer.create!(
518
+ :email => "valid@email.com"
519
+ )
520
+ result = customer.update(
521
+ :email => "@invalid.com"
522
+ )
523
+ result.success?.should == false
524
+ result.errors.for(:customer).on(:email)[0].message.should == "Email is an invalid format."
525
+ end
526
+ end
527
+
528
+ describe "update!" do
529
+ it "returns the customer and updates the customer if successful" do
530
+ customer = Braintree::Customer.create!(
531
+ :first_name => "Joe",
532
+ :last_name => "Cool"
533
+ )
534
+ customer.update!(
535
+ :first_name => "Mr. Joe",
536
+ :last_name => "Super Cool"
537
+ ).should == customer
538
+ customer.first_name.should == "Mr. Joe"
539
+ customer.last_name.should == "Super Cool"
540
+ customer.updated_at.between?(Time.now - 5, Time.now).should == true
541
+ end
542
+
543
+ it "raises an error if unsuccessful" do
544
+ customer = Braintree::Customer.create!(
545
+ :email => "valid@email.com"
546
+ )
547
+ expect do
548
+ customer.update!(:email => "@invalid.com")
549
+ end.to raise_error(Braintree::ValidationsFailed)
550
+ end
551
+ end
552
+
553
+ describe "update_from_transparent_redirect" do
554
+ it "returns a successful result if successful" do
555
+ result = Braintree::Customer.create(
556
+ :first_name => "Old First",
557
+ :last_name => "Old Last",
558
+ :company => "Old Company",
559
+ :email => "old@email.com",
560
+ :phone => "000.111.2222",
561
+ :fax => "000.222.3333",
562
+ :website => "old.website.com"
563
+ )
564
+ result.success?.should == true
565
+ original_customer = result.customer
566
+ params = {
567
+ :customer => {
568
+ :first_name => "New First",
569
+ :last_name => "New Last",
570
+ :company => "New Company",
571
+ :email => "new@email.com",
572
+ :phone => "888.111.2222",
573
+ :fax => "999.222.3333",
574
+ :website => "new.website.com"
575
+ }
576
+ }
577
+ tr_data_params = {
578
+ :customer_id => original_customer.id
579
+ }
580
+ query_string_response = update_customer_via_tr(params, tr_data_params)
581
+ result = Braintree::Customer.update_from_transparent_redirect(query_string_response)
582
+ result.success?.should == true
583
+ customer = result.customer
584
+ customer.id.should == original_customer.id
585
+ customer.first_name.should == "New First"
586
+ customer.last_name.should == "New Last"
587
+ customer.company.should == "New Company"
588
+ customer.email.should == "new@email.com"
589
+ customer.phone.should == "888.111.2222"
590
+ customer.fax.should == "999.222.3333"
591
+ customer.website.should == "new.website.com"
592
+ end
593
+
594
+ it "can pass any attribute through tr_data" do
595
+ original_customer = Braintree::Customer.create!(
596
+ :first_name => "Old First",
597
+ :last_name => "Old Last",
598
+ :company => "Old Company",
599
+ :email => "old@email.com",
600
+ :phone => "000.111.2222",
601
+ :fax => "000.222.3333",
602
+ :website => "old.website.com"
603
+ )
604
+ new_customer_id = "customer_#{rand(1_000_000)}"
605
+ tr_data_params = {
606
+ :customer_id => original_customer.id,
607
+ :customer => {
608
+ :id => new_customer_id,
609
+ :first_name => "New First",
610
+ :last_name => "New Last",
611
+ :company => "New Company",
612
+ :email => "new@email.com",
613
+ :phone => "888.111.2222",
614
+ :fax => "999.222.3333",
615
+ :website => "new.website.com"
616
+ }
617
+ }
618
+ query_string_response = update_customer_via_tr({}, tr_data_params)
619
+ result = Braintree::Customer.update_from_transparent_redirect(query_string_response)
620
+ result.success?.should == true
621
+ customer = result.customer
622
+ customer.id.should == new_customer_id
623
+ customer.first_name.should == "New First"
624
+ customer.last_name.should == "New Last"
625
+ customer.company.should == "New Company"
626
+ customer.email.should == "new@email.com"
627
+ customer.phone.should == "888.111.2222"
628
+ customer.fax.should == "999.222.3333"
629
+ customer.website.should == "new.website.com"
630
+ end
631
+ end
632
+
633
+ def create_customer_via_tr(regular_params, tr_data_params = {})
634
+ response = nil
635
+ Net::HTTP.start(Braintree::Configuration.server, Braintree::Configuration.port) do |http|
636
+ request = Net::HTTP::Post.new("/" + Braintree::Customer.create_customer_url.split("/", 4)[3])
637
+ request.add_field "Content-Type", "application/x-www-form-urlencoded"
638
+ params = {
639
+ :tr_data => Braintree::TransparentRedirect.create_customer_data(
640
+ {:redirect_url => "http://testing.com"}.merge(tr_data_params)
641
+ )
642
+ }.merge(regular_params)
643
+ request.body = Braintree::Util.hash_to_query_string(params)
644
+ response = http.request(request)
645
+ end
646
+ query_string = response["Location"].split("?", 2).last
647
+ query_string
648
+ end
649
+
650
+ def update_customer_via_tr(regular_params, tr_data_params = {})
651
+ raise "need a customer_id (of the customer to update) in tr_data_params" unless tr_data_params[:customer_id]
652
+ response = nil
653
+ Net::HTTP.start(Braintree::Configuration.server, Braintree::Configuration.port) do |http|
654
+ request = Net::HTTP::Post.new("/" + Braintree::Customer.update_customer_url.split("/", 4)[3])
655
+ request.add_field "Content-Type", "application/x-www-form-urlencoded"
656
+ tr_data = Braintree::TransparentRedirect.update_customer_data(
657
+ {:redirect_url => "http://testing.com"}.merge(tr_data_params)
658
+ )
659
+ request.body = Braintree::Util.hash_to_query_string({ :tr_data => tr_data }.merge(regular_params))
660
+ response = http.request(request)
661
+ end
662
+ query_string = response["Location"].split("?", 2).last
663
+ end
664
+ end