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,201 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Http do
4
+ describe "self._handle_response" do
5
+ it "raises an AuthenticationError if authentication fails" do
6
+ begin
7
+ original_key = Braintree::Configuration.public_key
8
+ Braintree::Configuration.public_key = "invalid_public_key"
9
+ expect do
10
+ Braintree::Http.get "/customers"
11
+ end.to raise_error(Braintree::AuthenticationError)
12
+ ensure
13
+ Braintree::Configuration.public_key = original_key
14
+ end
15
+ end
16
+
17
+ it "raises an AuthorizationError if authorization fails" do
18
+ expect do
19
+ Braintree::Http.get "/users"
20
+ end.to raise_error(Braintree::AuthorizationError)
21
+ end
22
+ end
23
+
24
+ describe "self._http_do" do
25
+ it "logs one line of info to the logger" do
26
+ begin
27
+ old_logger = Braintree::Configuration.logger
28
+ now_in_utc = Time.utc(2009, 10, 10, 13, 55, 36)
29
+ SpecHelper.stub_time_dot_now(now_in_utc) do
30
+ output = StringIO.new
31
+ Braintree::Configuration.logger = Logger.new(output)
32
+ Braintree::Configuration.logger.level = Logger::INFO
33
+ Braintree::Customer.all
34
+ utc_or_gmt = Time.now.utc.strftime("%Z")
35
+ output.string.should include("[Braintree] [10/Oct/2009 13:55:36 #{utc_or_gmt}] GET /customers?page=1 200")
36
+ end
37
+ ensure
38
+ Braintree::Configuration.logger = old_logger
39
+ end
40
+ end
41
+
42
+ it "logs full request and response for debug logger" do
43
+ customer = Braintree::Customer.create.customer
44
+ begin
45
+ old_logger = Braintree::Configuration.logger
46
+ now_in_utc = Time.utc(2009, 10, 10, 13, 55, 36)
47
+ SpecHelper.stub_time_dot_now(now_in_utc) do
48
+ output = StringIO.new
49
+ Braintree::Configuration.logger = Logger.new(output)
50
+ Braintree::Configuration.logger.level = Logger::DEBUG
51
+ result = Braintree::CreditCard.create(
52
+ :customer_id => customer.id,
53
+ :cardholder_name => "Sam Jones",
54
+ :number => Braintree::Test::CreditCardNumbers::Visa,
55
+ :expiration_date => "05/2009"
56
+ )
57
+ result.success?.should == true
58
+ utc_or_gmt = Time.now.utc.strftime("%Z")
59
+ output.string.should include("[Braintree] [10/Oct/2009 13:55:36 #{utc_or_gmt}] POST /payment_methods")
60
+ output.string.should include("[Braintree] <cardholder-name>Sam Jones</cardholder-name>")
61
+ output.string.should include("[Braintree] <number>401288******1881</number>")
62
+ output.string.should include("[Braintree] [10/Oct/2009 13:55:36 #{utc_or_gmt}] 201 Created")
63
+ output.string.should match(/\[Braintree\] <token>\w+<\/token>/)
64
+ end
65
+ ensure
66
+ Braintree::Configuration.logger = old_logger
67
+ end
68
+ end
69
+
70
+ describe "ssl verification" do
71
+ it "rejects when the certificate isn't verified by our certificate authority (self-signed)" do
72
+ begin
73
+ use_ssl = Braintree::Configuration.ssl?
74
+ Braintree::Configuration.stub(:ssl?).and_return(true)
75
+ Braintree::Configuration.stub(:port).and_return(8443)
76
+
77
+ start_ssl_server do
78
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to raise_error(Braintree::SSLCertificateError, /Preverify: false, Error: self signed certificate/)
79
+ end
80
+ ensure
81
+ Braintree::Configuration.stub(:ssl?).and_return(use_ssl)
82
+ end
83
+ end
84
+
85
+ it "rejets when the certificate is signed by a different (but valid) root CA" do
86
+ # Random CA root file from a different certificate authority
87
+ begin
88
+ original_ca_file = Braintree::Configuration.ca_file
89
+ Braintree::Configuration.stub(:ca_file).and_return(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ssl", "geotrust_global.crt")))
90
+ use_ssl = Braintree::Configuration.ssl?
91
+ Braintree::Configuration.stub(:ssl?).and_return(true)
92
+ Braintree::Configuration.stub(:port).and_return(8443)
93
+
94
+ start_ssl_server do
95
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to raise_error(Braintree::SSLCertificateError, /Preverify: false, Error: self signed certificate/)
96
+ end
97
+ ensure
98
+ Braintree::Configuration.stub(:ssl?).and_return(use_ssl)
99
+ Braintree::Configuration.stub(:ca_file).and_return(original_ca_file)
100
+ end
101
+ end
102
+
103
+ it "accepts the certificate on the QA server" do
104
+ begin
105
+ original_env = Braintree::Configuration.environment
106
+ Braintree::Configuration.environment = :qa
107
+ Braintree::Configuration.stub(:base_merchant_path).and_return("/")
108
+
109
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
110
+ ensure
111
+ Braintree::Configuration.environment = original_env
112
+ end
113
+ end
114
+
115
+ it "accepts the certificate on the sandbox server" do
116
+ begin
117
+ original_env = Braintree::Configuration.environment
118
+ Braintree::Configuration.environment = :sandbox
119
+ Braintree::Configuration.stub(:base_merchant_path).and_return("/")
120
+
121
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
122
+ ensure
123
+ Braintree::Configuration.environment = original_env
124
+ end
125
+ end
126
+
127
+ xit "Patrick: waiting on a production box - accepts the certificate on the production server" do
128
+ begin
129
+ original_env = Braintree::Configuration.environment
130
+ Braintree::Configuration.environment = :production
131
+ Braintree::Configuration.stub(:base_merchant_path).and_return("/")
132
+
133
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
134
+ ensure
135
+ Braintree::Configuration.environment = original_env
136
+ end
137
+ end
138
+
139
+ it "raises an appropriate error if certificate fails validation" do
140
+ begin
141
+ original_env = Braintree::Configuration.environment
142
+ Braintree::Configuration.environment = :qa
143
+ Braintree::Configuration.stub(:base_merchant_path).and_return("/")
144
+ original_ca_file = Braintree::Configuration.ca_file
145
+ Braintree::Configuration.stub(:ca_file).and_return(nil)
146
+
147
+ expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to raise_error(Braintree::SSLCertificateError)
148
+ ensure
149
+ Braintree::Configuration.environment = original_env
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "self._verify_ssl_certificate" do
156
+ it "raises if preverify is false" do
157
+ context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
158
+ expect { Braintree::Http._verify_ssl_certificate(false, context) }.to raise_error(Braintree::SSLCertificateError)
159
+ end
160
+
161
+ it "raise if ssl_context doesn't have an error code of 0" do
162
+ context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
163
+ context.error = 19 # ca_file incorrect, self-signed
164
+ expect { Braintree::Http._verify_ssl_certificate(true, context) }.to raise_error(Braintree::SSLCertificateError)
165
+ end
166
+
167
+ it "doesn't raise if there is no error" do
168
+ context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
169
+ expect { Braintree::Http._verify_ssl_certificate(true, context) }.to_not raise_error
170
+ end
171
+
172
+ it "logs when there is an error" do
173
+ begin
174
+ old_logger = Braintree::Configuration.logger
175
+ output = StringIO.new
176
+ Braintree::Configuration.logger = Logger.new(output)
177
+ utc_or_gmt = Time.now.utc.strftime("%Z")
178
+ context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
179
+ context.error = 19
180
+ expect { Braintree::Http._verify_ssl_certificate(false, context) }.to raise_error(Braintree::SSLCertificateError)
181
+ output.string.should include("SSL Verification failed -- Preverify: false, Error: self signed certificate in certificate chain (19)")
182
+ ensure
183
+ Braintree::Configuration.logger = old_logger
184
+ end
185
+ end
186
+
187
+ it "doesn't log when there is not an error" do
188
+ begin
189
+ old_logger = Braintree::Configuration.logger
190
+ output = StringIO.new
191
+ Braintree::Configuration.logger = Logger.new(output)
192
+ utc_or_gmt = Time.now.utc.strftime("%Z")
193
+ context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
194
+ expect { Braintree::Http._verify_ssl_certificate(true, context) }.to_not raise_error(Braintree::SSLCertificateError)
195
+ output.string.should == ""
196
+ ensure
197
+ Braintree::Configuration.logger = old_logger
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + "/../../spec_helper"
2
+
3
+ describe Braintree::Test::TransactionAmounts do
4
+ describe "Authorize" do
5
+ it "creates a transaction with status authorized" do
6
+ transaction = Braintree::Transaction.sale!(
7
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
8
+ :credit_card => {
9
+ :number => Braintree::Test::CreditCardNumbers::Visa,
10
+ :expiration_date => "12/2012"
11
+ }
12
+ )
13
+ transaction.status.should == "authorized"
14
+ end
15
+ end
16
+
17
+ describe "Decline" do
18
+ it "creates a transaction with status processor_declined" do
19
+ transaction = Braintree::Transaction.sale!(
20
+ :amount => Braintree::Test::TransactionAmounts::Decline,
21
+ :credit_card => {
22
+ :number => Braintree::Test::CreditCardNumbers::Visa,
23
+ :expiration_date => "12/2012"
24
+ }
25
+ )
26
+ transaction.status.should == "processor_declined"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,900 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Transaction do
4
+ describe "self.create" do
5
+ it "returns a successful result if successful" do
6
+ result = Braintree::Transaction.create(
7
+ :type => "sale",
8
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
9
+ :credit_card => {
10
+ :number => Braintree::Test::CreditCardNumbers::Visa,
11
+ :expiration_date => "05/2009"
12
+ }
13
+ )
14
+ result.success?.should == true
15
+ result.transaction.id.should =~ /^\w{6}$/
16
+ result.transaction.type.should == "sale"
17
+ result.transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
18
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
19
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
20
+ result.transaction.credit_card_details.expiration_date.should == "05/2009"
21
+ end
22
+
23
+ it "returns an error result if validations fail" do
24
+ params = {
25
+ :transaction => {
26
+ :type => "sale",
27
+ :amount => nil,
28
+ :credit_card => {
29
+ :number => Braintree::Test::CreditCardNumbers::Visa,
30
+ :expiration_date => "05/2009"
31
+ }
32
+ }
33
+ }
34
+ result = Braintree::Transaction.create(params[:transaction])
35
+ result.success?.should == false
36
+ result.params.should == {:transaction => {:type => 'sale', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
37
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Amount is required."
38
+ end
39
+ end
40
+
41
+ describe "self.create!" do
42
+ it "returns the transaction if valid" do
43
+ transaction = Braintree::Transaction.create!(
44
+ :type => "sale",
45
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
46
+ :credit_card => {
47
+ :number => Braintree::Test::CreditCardNumbers::Visa,
48
+ :expiration_date => "05/2009"
49
+ }
50
+ )
51
+ transaction.id.should =~ /^\w{6}$/
52
+ transaction.type.should == "sale"
53
+ transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
54
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
55
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
56
+ transaction.credit_card_details.expiration_date.should == "05/2009"
57
+ end
58
+
59
+ it "raises a ValidationsFailed if invalid" do
60
+ expect do
61
+ Braintree::Transaction.create!(
62
+ :type => "sale",
63
+ :amount => nil,
64
+ :credit_card => {
65
+ :number => Braintree::Test::CreditCardNumbers::Visa,
66
+ :expiration_date => "05/2009"
67
+ }
68
+ )
69
+ end.to raise_error(Braintree::ValidationsFailed)
70
+ end
71
+ end
72
+
73
+ describe "self.sale" do
74
+ it "returns a successful result with type=sale if successful" do
75
+ result = Braintree::Transaction.sale(
76
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
77
+ :credit_card => {
78
+ :number => Braintree::Test::CreditCardNumbers::Visa,
79
+ :expiration_date => "05/2009"
80
+ }
81
+ )
82
+ result.success?.should == true
83
+ result.transaction.id.should =~ /^\w{6}$/
84
+ result.transaction.type.should == "sale"
85
+ result.transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
86
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
87
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
88
+ result.transaction.credit_card_details.expiration_date.should == "05/2009"
89
+ end
90
+
91
+ it "works when given all attributes" do
92
+ result = Braintree::Transaction.sale(
93
+ :amount => "100.00",
94
+ :order_id => "123",
95
+ :credit_card => {
96
+ :number => "5105105105105100",
97
+ :expiration_date => "05/2011",
98
+ :cvv => "123"
99
+ },
100
+ :customer => {
101
+ :first_name => "Dan",
102
+ :last_name => "Smith",
103
+ :company => "Braintree Payment Solutions",
104
+ :email => "dan@example.com",
105
+ :phone => "419-555-1234",
106
+ :fax => "419-555-1235",
107
+ :website => "http://braintreepaymentsolutions.com"
108
+ },
109
+ :billing => {
110
+ :first_name => "Carl",
111
+ :last_name => "Jones",
112
+ :company => "Braintree",
113
+ :street_address => "123 E Main St",
114
+ :extended_address => "Suite 403",
115
+ :locality => "Chicago",
116
+ :region => "IL",
117
+ :postal_code => "60622",
118
+ :country_name => "United States of America"
119
+ },
120
+ :shipping => {
121
+ :first_name => "Andrew",
122
+ :last_name => "Mason",
123
+ :company => "Braintree",
124
+ :street_address => "456 W Main St",
125
+ :extended_address => "Apt 2F",
126
+ :locality => "Bartlett",
127
+ :region => "IL",
128
+ :postal_code => "60103",
129
+ :country_name => "United States of America"
130
+ }
131
+ )
132
+ result.success?.should == true
133
+ transaction = result.transaction
134
+ transaction.id.should =~ /\A\w{6}\z/
135
+ transaction.type.should == "sale"
136
+ transaction.status.should == "authorized"
137
+ transaction.amount.should == "100.00"
138
+ transaction.order_id.should == "123"
139
+ transaction.processor_response_code.should == "1000"
140
+ transaction.created_at.between?(Time.now - 5, Time.now).should == true
141
+ transaction.updated_at.between?(Time.now - 5, Time.now).should == true
142
+ transaction.credit_card_details.bin.should == "510510"
143
+ transaction.credit_card_details.last_4.should == "5100"
144
+ transaction.credit_card_details.masked_number.should == "510510******5100"
145
+ transaction.credit_card_details.card_type.should == "MasterCard"
146
+ transaction.avs_error_response_code.should == nil
147
+ transaction.avs_postal_code_response_code.should == "M"
148
+ transaction.avs_street_address_response_code.should == "M"
149
+ transaction.customer_details.first_name.should == "Dan"
150
+ transaction.customer_details.last_name.should == "Smith"
151
+ transaction.customer_details.company.should == "Braintree Payment Solutions"
152
+ transaction.customer_details.email.should == "dan@example.com"
153
+ transaction.customer_details.phone.should == "419-555-1234"
154
+ transaction.customer_details.fax.should == "419-555-1235"
155
+ transaction.customer_details.website.should == "http://braintreepaymentsolutions.com"
156
+ transaction.billing_details.first_name.should == "Carl"
157
+ transaction.billing_details.last_name.should == "Jones"
158
+ transaction.billing_details.company.should == "Braintree"
159
+ transaction.billing_details.street_address.should == "123 E Main St"
160
+ transaction.billing_details.extended_address.should == "Suite 403"
161
+ transaction.billing_details.locality.should == "Chicago"
162
+ transaction.billing_details.region.should == "IL"
163
+ transaction.billing_details.postal_code.should == "60622"
164
+ transaction.billing_details.country_name.should == "United States of America"
165
+ transaction.shipping_details.first_name.should == "Andrew"
166
+ transaction.shipping_details.last_name.should == "Mason"
167
+ transaction.shipping_details.company.should == "Braintree"
168
+ transaction.shipping_details.street_address.should == "456 W Main St"
169
+ transaction.shipping_details.extended_address.should == "Apt 2F"
170
+ transaction.shipping_details.locality.should == "Bartlett"
171
+ transaction.shipping_details.region.should == "IL"
172
+ transaction.shipping_details.postal_code.should == "60103"
173
+ transaction.shipping_details.country_name.should == "United States of America"
174
+ end
175
+
176
+ it "can store customer and credit card in the vault" do
177
+ result = Braintree::Transaction.sale(
178
+ :amount => "100",
179
+ :customer => {
180
+ :first_name => "Adam",
181
+ :last_name => "Williams"
182
+ },
183
+ :credit_card => {
184
+ :number => "5105105105105100",
185
+ :expiration_date => "05/2012"
186
+ },
187
+ :options => {
188
+ :store_in_vault => true
189
+ }
190
+ )
191
+ result.success?.should == true
192
+ transaction = result.transaction
193
+ transaction.customer_details.id.should =~ /\A\d{6,7}\z/
194
+ transaction.vault_customer.id.should == transaction.customer_details.id
195
+ transaction.credit_card_details.token.should =~ /\A\w{4,5}\z/
196
+ transaction.vault_credit_card.token.should == transaction.credit_card_details.token
197
+ end
198
+
199
+ it "submits for settlement if given transaction[options][submit_for_settlement]" do
200
+ result = Braintree::Transaction.sale(
201
+ :amount => "100",
202
+ :credit_card => {
203
+ :number => "5105105105105100",
204
+ :expiration_date => "05/2012"
205
+ },
206
+ :options => {
207
+ :submit_for_settlement => true
208
+ }
209
+ )
210
+ result.success?.should == true
211
+ result.transaction.status.should == "submitted_for_settlement"
212
+ end
213
+
214
+ it "can specify the customer id and payment method token" do
215
+ customer_id = "customer_#{rand(1000000)}"
216
+ payment_mehtod_token = "credit_card_#{rand(1000000)}"
217
+ result = Braintree::Transaction.sale(
218
+ :amount => "100",
219
+ :customer => {
220
+ :id => customer_id,
221
+ :first_name => "Adam",
222
+ :last_name => "Williams"
223
+ },
224
+ :credit_card => {
225
+ :token => payment_mehtod_token,
226
+ :number => "5105105105105100",
227
+ :expiration_date => "05/2012"
228
+ },
229
+ :options => {
230
+ :store_in_vault => true
231
+ }
232
+ )
233
+ result.success?.should == true
234
+ transaction = result.transaction
235
+ transaction.customer_details.id.should == customer_id
236
+ transaction.vault_customer.id.should == customer_id
237
+ transaction.credit_card_details.token.should == payment_mehtod_token
238
+ transaction.vault_credit_card.token.should == payment_mehtod_token
239
+ end
240
+
241
+ it "returns an error result if validations fail" do
242
+ params = {
243
+ :transaction => {
244
+ :amount => nil,
245
+ :credit_card => {
246
+ :number => Braintree::Test::CreditCardNumbers::Visa,
247
+ :expiration_date => "05/2009"
248
+ }
249
+ }
250
+ }
251
+ result = Braintree::Transaction.sale(params[:transaction])
252
+ result.success?.should == false
253
+ result.params.should == {:transaction => {:type => 'sale', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
254
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Amount is required."
255
+ end
256
+ end
257
+
258
+ describe "self.sale!" do
259
+ it "returns the transaction if valid" do
260
+ transaction = Braintree::Transaction.sale!(
261
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
262
+ :credit_card => {
263
+ :number => Braintree::Test::CreditCardNumbers::Visa,
264
+ :expiration_date => "05/2009"
265
+ }
266
+ )
267
+ transaction.id.should =~ /^\w{6}$/
268
+ transaction.type.should == "sale"
269
+ transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
270
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
271
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
272
+ transaction.credit_card_details.expiration_date.should == "05/2009"
273
+ end
274
+
275
+ it "raises a ValidationsFailed if invalid" do
276
+ expect do
277
+ Braintree::Transaction.sale!(
278
+ :amount => nil,
279
+ :credit_card => {
280
+ :number => Braintree::Test::CreditCardNumbers::Visa,
281
+ :expiration_date => "05/2009"
282
+ }
283
+ )
284
+ end.to raise_error(Braintree::ValidationsFailed)
285
+ end
286
+ end
287
+
288
+ describe "self.submit_for_settlement" do
289
+ it "returns a successful result if successful" do
290
+ transaction = Braintree::Transaction.sale!(
291
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
292
+ :credit_card => {
293
+ :number => Braintree::Test::CreditCardNumbers::Visa,
294
+ :expiration_date => "06/2009"
295
+ }
296
+ )
297
+ result = Braintree::Transaction.submit_for_settlement(transaction.id)
298
+ result.success?.should == true
299
+ end
300
+
301
+ it "can submit a specific amount for settlement" do
302
+ transaction = Braintree::Transaction.sale!(
303
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
304
+ :credit_card => {
305
+ :number => Braintree::Test::CreditCardNumbers::Visa,
306
+ :expiration_date => "06/2009"
307
+ }
308
+ )
309
+ transaction.amount.should == "1000.00"
310
+ result = Braintree::Transaction.submit_for_settlement(transaction.id, "999.99")
311
+ result.success?.should == true
312
+ result.transaction.amount.should == "999.99"
313
+ result.transaction.status.should == "submitted_for_settlement"
314
+ result.transaction.updated_at.between?(Time.now - 5, Time.now).should == true
315
+ end
316
+
317
+ it "returns an error result if unsuccessful" do
318
+ transaction = Braintree::Transaction.sale!(
319
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
320
+ :credit_card => {
321
+ :number => Braintree::Test::CreditCardNumbers::Visa,
322
+ :expiration_date => "06/2009"
323
+ }
324
+ )
325
+ transaction.amount.should == "1000.00"
326
+ result = Braintree::Transaction.submit_for_settlement(transaction.id, "1000.01")
327
+ result.success?.should == false
328
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Settlement amount cannot be more than the authorized amount."
329
+ result.params[:transaction][:amount].should == "1000.01"
330
+ end
331
+ end
332
+
333
+ describe "self.submit_for_settlement!" do
334
+ it "returns the transaction if successful" do
335
+ original_transaction = Braintree::Transaction.sale!(
336
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
337
+ :credit_card => {
338
+ :number => Braintree::Test::CreditCardNumbers::Visa,
339
+ :expiration_date => "06/2009"
340
+ }
341
+ )
342
+ transaction = Braintree::Transaction.submit_for_settlement!(original_transaction.id)
343
+ transaction.status.should == "submitted_for_settlement"
344
+ transaction.id.should == original_transaction.id
345
+ end
346
+
347
+ it "raises a ValidationsFailed if unsuccessful" do
348
+ transaction = Braintree::Transaction.sale!(
349
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
350
+ :credit_card => {
351
+ :number => Braintree::Test::CreditCardNumbers::Visa,
352
+ :expiration_date => "06/2009"
353
+ }
354
+ )
355
+ transaction.amount.should == "1000.00"
356
+ expect do
357
+ Braintree::Transaction.submit_for_settlement!(transaction.id, "1000.01")
358
+ end.to raise_error(Braintree::ValidationsFailed)
359
+ end
360
+ end
361
+
362
+ describe "self.credit" do
363
+ it "returns a successful result with type=credit if successful" do
364
+ result = Braintree::Transaction.credit(
365
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
366
+ :credit_card => {
367
+ :number => Braintree::Test::CreditCardNumbers::Visa,
368
+ :expiration_date => "05/2009"
369
+ }
370
+ )
371
+ result.success?.should == true
372
+ result.transaction.id.should =~ /^\w{6}$/
373
+ result.transaction.type.should == "credit"
374
+ result.transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
375
+ result.transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
376
+ result.transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
377
+ result.transaction.credit_card_details.expiration_date.should == "05/2009"
378
+ end
379
+
380
+ it "returns an error result if validations fail" do
381
+ params = {
382
+ :transaction => {
383
+ :amount => nil,
384
+ :credit_card => {
385
+ :number => Braintree::Test::CreditCardNumbers::Visa,
386
+ :expiration_date => "05/2009"
387
+ }
388
+ }
389
+ }
390
+ result = Braintree::Transaction.credit(params[:transaction])
391
+ result.success?.should == false
392
+ result.params.should == {:transaction => {:type => 'credit', :amount => nil, :credit_card => {:expiration_date => "05/2009"}}}
393
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Amount is required."
394
+ end
395
+ end
396
+
397
+ describe "self.credit!" do
398
+ it "returns the transaction if valid" do
399
+ transaction = Braintree::Transaction.credit!(
400
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
401
+ :credit_card => {
402
+ :number => Braintree::Test::CreditCardNumbers::Visa,
403
+ :expiration_date => "05/2009"
404
+ }
405
+ )
406
+ transaction.id.should =~ /^\w{6}$/
407
+ transaction.type.should == "credit"
408
+ transaction.amount.should == Braintree::Test::TransactionAmounts::Authorize
409
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
410
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
411
+ transaction.credit_card_details.expiration_date.should == "05/2009"
412
+ end
413
+
414
+ it "raises a ValidationsFailed if invalid" do
415
+ expect do
416
+ Braintree::Transaction.credit!(
417
+ :amount => nil,
418
+ :credit_card => {
419
+ :number => Braintree::Test::CreditCardNumbers::Visa,
420
+ :expiration_date => "05/2009"
421
+ }
422
+ )
423
+ end.to raise_error(Braintree::ValidationsFailed)
424
+ end
425
+ end
426
+
427
+ describe "self.create_from_transparent_redirect" do
428
+ it "returns a successful result if successful" do
429
+ params = {
430
+ :transaction => {
431
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
432
+ :credit_card => {
433
+ :number => Braintree::Test::CreditCardNumbers::Visa,
434
+ :expiration_date => "05/2009"
435
+ }
436
+ }
437
+ }
438
+ tr_data_params = {
439
+ :transaction => {
440
+ :type => "sale"
441
+ }
442
+ }
443
+ query_string_response = create_transaction_via_tr(params, tr_data_params)
444
+ result = Braintree::Transaction.create_from_transparent_redirect(query_string_response)
445
+ result.success?.should == true
446
+ transaction = result.transaction
447
+ transaction.type.should == "sale"
448
+ transaction.amount.should == "1000.00"
449
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
450
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
451
+ transaction.credit_card_details.expiration_date.should == "05/2009"
452
+ end
453
+
454
+ it "returns an error result if validations fail" do
455
+ params = {
456
+ :transaction => {
457
+ :amount => "",
458
+ :credit_card => {
459
+ :number => Braintree::Test::CreditCardNumbers::Visa,
460
+ :expiration_date => "05/2009"
461
+ }
462
+ }
463
+ }
464
+ tr_data_params = {
465
+ :transaction => {
466
+ :type => "sale"
467
+ }
468
+ }
469
+ query_string_response = create_transaction_via_tr(params, tr_data_params)
470
+ result = Braintree::Transaction.create_from_transparent_redirect(query_string_response)
471
+ result.success?.should == false
472
+ result.params[:transaction].should == {:amount => "", :type => "sale", :credit_card => {:expiration_date => "05/2009"}}
473
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Amount is required."
474
+ end
475
+ end
476
+
477
+ describe "self.find" do
478
+ it "finds the transaction with the given id" do
479
+ result = Braintree::Transaction.create(
480
+ :type => "sale",
481
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
482
+ :credit_card => {
483
+ :number => Braintree::Test::CreditCardNumbers::Visa,
484
+ :expiration_date => "05/2009"
485
+ }
486
+ )
487
+ result.success?.should == true
488
+ created_transaction = result.transaction
489
+ found_transaction = Braintree::Transaction.find(created_transaction.id)
490
+ found_transaction.should == created_transaction
491
+ end
492
+
493
+ it "raises a NotFoundError exception if transaction cannot be found" do
494
+ expect do
495
+ Braintree::Transaction.find("invalid-id")
496
+ end.to raise_error(Braintree::NotFoundError, 'transaction with id "invalid-id" not found')
497
+ end
498
+ end
499
+
500
+ describe "self.void" do
501
+ it "returns a successful result if successful" do
502
+ transaction = Braintree::Transaction.sale!(
503
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
504
+ :credit_card => {
505
+ :number => Braintree::Test::CreditCardNumbers::Visa,
506
+ :expiration_date => "05/2009"
507
+ }
508
+ )
509
+ result = Braintree::Transaction.void(transaction.id)
510
+ result.success?.should == true
511
+ result.transaction.id.should == transaction.id
512
+ result.transaction.status.should == "voided"
513
+ end
514
+
515
+ it "returns an error result if unsuccessful" do
516
+ transaction = Braintree::Transaction.sale!(
517
+ :amount => Braintree::Test::TransactionAmounts::Decline,
518
+ :credit_card => {
519
+ :number => Braintree::Test::CreditCardNumbers::Visa,
520
+ :expiration_date => "05/2009"
521
+ }
522
+ )
523
+ result = Braintree::Transaction.void(transaction.id)
524
+ result.success?.should == false
525
+ result.errors.for(:transaction).on(:base)[0].message.should == "Transaction can only be voided if status is authorized or submitted_for_settlement."
526
+ end
527
+ end
528
+
529
+ describe "void!" do
530
+ it "returns the transaction if successful" do
531
+ transaction = Braintree::Transaction.sale!(
532
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
533
+ :credit_card => {
534
+ :number => Braintree::Test::CreditCardNumbers::Visa,
535
+ :expiration_date => "05/2009"
536
+ }
537
+ )
538
+ returned_transaction = Braintree::Transaction.void!(transaction.id)
539
+ returned_transaction.should == transaction
540
+ returned_transaction.status.should == "voided"
541
+ end
542
+
543
+ it "raises a ValidationsFailed if unsuccessful" do
544
+ transaction = Braintree::Transaction.sale!(
545
+ :amount => Braintree::Test::TransactionAmounts::Decline,
546
+ :credit_card => {
547
+ :number => Braintree::Test::CreditCardNumbers::Visa,
548
+ :expiration_date => "05/2009"
549
+ }
550
+ )
551
+ expect do
552
+ Braintree::Transaction.void!(transaction.id)
553
+ end.to raise_error(Braintree::ValidationsFailed)
554
+ end
555
+ end
556
+
557
+ describe "refund" do
558
+ it "returns a successful result if successful" do
559
+ transaction = find_transaction_to_refund
560
+ result = transaction.refund
561
+ result.success?.should == true
562
+ result.new_transaction.type.should == "credit"
563
+ end
564
+
565
+ it "returns an error result if unsuccessful" do
566
+ transaction = Braintree::Transaction.create!(
567
+ :type => "sale",
568
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
569
+ :credit_card => {
570
+ :number => Braintree::Test::CreditCardNumbers::Visa,
571
+ :expiration_date => "05/2009"
572
+ }
573
+ )
574
+ result = transaction.refund
575
+ result.success?.should == false
576
+ result.errors.for(:transaction).on(:base)[0].message.should == "Cannot refund a transaction unless it is settled."
577
+ end
578
+ end
579
+
580
+ describe "submit_for_settlement" do
581
+ it "returns a successful result if successful" do
582
+ transaction = Braintree::Transaction.sale!(
583
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
584
+ :credit_card => {
585
+ :number => Braintree::Test::CreditCardNumbers::Visa,
586
+ :expiration_date => "06/2009"
587
+ }
588
+ )
589
+ result = transaction.submit_for_settlement
590
+ result.success?.should == true
591
+ end
592
+
593
+ it "can submit a specific amount for settlement" do
594
+ transaction = Braintree::Transaction.sale!(
595
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
596
+ :credit_card => {
597
+ :number => Braintree::Test::CreditCardNumbers::Visa,
598
+ :expiration_date => "06/2009"
599
+ }
600
+ )
601
+ transaction.amount.should == "1000.00"
602
+ result = transaction.submit_for_settlement("999.99")
603
+ result.success?.should == true
604
+ transaction.amount.should == "999.99"
605
+ end
606
+
607
+ it "updates the transaction attributes" do
608
+ transaction = Braintree::Transaction.sale!(
609
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
610
+ :credit_card => {
611
+ :number => Braintree::Test::CreditCardNumbers::Visa,
612
+ :expiration_date => "06/2009"
613
+ }
614
+ )
615
+ transaction.amount.should == "1000.00"
616
+ result = transaction.submit_for_settlement("999.99")
617
+ result.success?.should == true
618
+ transaction.amount.should == "999.99"
619
+ transaction.status.should == "submitted_for_settlement"
620
+ transaction.updated_at.between?(Time.now - 5, Time.now).should == true
621
+ end
622
+
623
+ it "returns an error result if unsuccessful" do
624
+ transaction = Braintree::Transaction.sale!(
625
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
626
+ :credit_card => {
627
+ :number => Braintree::Test::CreditCardNumbers::Visa,
628
+ :expiration_date => "06/2009"
629
+ }
630
+ )
631
+ transaction.amount.should == "1000.00"
632
+ result = transaction.submit_for_settlement("1000.01")
633
+ result.success?.should == false
634
+ result.errors.for(:transaction).on(:amount)[0].message.should == "Settlement amount cannot be more than the authorized amount."
635
+ result.params[:transaction][:amount].should == "1000.01"
636
+ end
637
+ end
638
+
639
+ describe "submit_for_settlement!" do
640
+ it "returns the transaction if successful" do
641
+ original_transaction = Braintree::Transaction.sale!(
642
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
643
+ :credit_card => {
644
+ :number => Braintree::Test::CreditCardNumbers::Visa,
645
+ :expiration_date => "06/2009"
646
+ }
647
+ )
648
+ transaction = original_transaction.submit_for_settlement!
649
+ transaction.status.should == "submitted_for_settlement"
650
+ transaction.id.should == original_transaction.id
651
+ end
652
+
653
+ it "raises a ValidationsFailed if unsuccessful" do
654
+ transaction = Braintree::Transaction.sale!(
655
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
656
+ :credit_card => {
657
+ :number => Braintree::Test::CreditCardNumbers::Visa,
658
+ :expiration_date => "06/2009"
659
+ }
660
+ )
661
+ transaction.amount.should == "1000.00"
662
+ expect do
663
+ transaction.submit_for_settlement!("1000.01")
664
+ end.to raise_error(Braintree::ValidationsFailed)
665
+ end
666
+ end
667
+
668
+ describe "search" do
669
+ describe "advanced" do
670
+ it "pretty much works in one big fell swoop/hash" do
671
+ result = Braintree::Transaction.create(
672
+ :type => "sale",
673
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
674
+ :credit_card => {
675
+ :number => Braintree::Test::CreditCardNumbers::Visa,
676
+ :expiration_date => "05/2009"
677
+ },
678
+ :order_id => "123",
679
+ :customer => {
680
+ :company => "Apple",
681
+ :fax => "312-555-1234",
682
+ :first_name => "Steve",
683
+ :last_name => "Jobs",
684
+ :phone => "614-555-1234",
685
+ :website => "http://www.apple.com",
686
+ },
687
+ :billing => {
688
+ :country_name => "United States of America",
689
+ :extended_address => "Apt 1F",
690
+ :locality => "Chicago",
691
+ :postal_code => "60622",
692
+ :region => "Illinois",
693
+ :street_address => "1234 W North Ave",
694
+ },
695
+ :shipping => {
696
+ :country_name => "United States of America",
697
+ :extended_address => "Apt 123",
698
+ :locality => "Bartlett",
699
+ :postal_code => "60004",
700
+ :region => "Illinois",
701
+ :street_address => "123 Main St",
702
+ }
703
+ )
704
+ result.success?.should == true
705
+ expected_transaction = result.transaction
706
+ search_criteria = {
707
+ :billing_country_name => {:is => "United States of America"},
708
+ :billing_extended_address => {:is => "Apt 1F"},
709
+ :billing_locality => {:is => "Chicago"},
710
+ :billing_postal_code => {:is => "60622"},
711
+ :billing_region => {:is => "Illinois"},
712
+ :billing_street_address => {:is => "1234 W North Ave"},
713
+ :credit_card_number => {:is => Braintree::Test::CreditCardNumbers::Visa},
714
+ :customer_company => {:is => "Apple"},
715
+ :customer_fax => {:is => "312-555-1234"},
716
+ :customer_first_name => {:is => "Steve"},
717
+ :customer_last_name => {:is => "Jobs"},
718
+ :customer_phone => {:is => "614-555-1234"},
719
+ :customer_website => {:is => "http://www.apple.com"},
720
+ :expiration_date => {:is => "05/2009"},
721
+ :order_id => {:is => "123"},
722
+ :shipping_country_name => {:is => "United States of America"},
723
+ :shipping_extended_address => {:is => "Apt 123"},
724
+ :shipping_locality => {:is => "Bartlett"},
725
+ :shipping_postal_code => {:is => "60004"},
726
+ :shipping_region => {:is => "Illinois"},
727
+ :shipping_street_address => {:is => "123 Main St"},
728
+ }
729
+ search_results = Braintree::Transaction.search(search_criteria)
730
+ search_results.should include(expected_transaction)
731
+ end
732
+
733
+ it "properly parses the xml if only one transaction is found" do
734
+ transaction = Braintree::Transaction.create!(
735
+ :type => "sale",
736
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
737
+ :credit_card => {
738
+ :number => Braintree::Test::CreditCardNumbers::Visa,
739
+ :expiration_date => "05/2009"
740
+ }
741
+ )
742
+ search_results = Braintree::Transaction.search(:transaction_id => {:is => transaction.id})
743
+ search_results.total_items.should == 1
744
+ search_results[0].should == transaction
745
+ end
746
+ end
747
+
748
+ describe "basic" do
749
+ it "returns paged transactions matching the given search terms" do
750
+ transactions = Braintree::Transaction.search "1111"
751
+ transactions.total_items.should > 0
752
+ end
753
+
754
+ it "is paged" do
755
+ transactions = Braintree::Transaction.search "1111", :page => 2
756
+ transactions.current_page_number.should == 2
757
+ end
758
+
759
+ it "can traverse pages" do
760
+ transactions = Braintree::Transaction.search "1111", :page => 1
761
+ transactions.next_page.current_page_number.should == 2
762
+ end
763
+ end
764
+ end
765
+
766
+ describe "vault_credit_card" do
767
+ it "returns the Braintree::CreditCard if the transaction credit card is stored in the vault" do
768
+ customer = Braintree::Customer.create!(
769
+ :credit_card => {
770
+ :number => Braintree::Test::CreditCardNumbers::Visa,
771
+ :expiration_date => "05/2010"
772
+ }
773
+ )
774
+ transaction = customer.credit_cards[0].sale(:amount => "100.00").transaction
775
+ transaction.vault_credit_card.should == customer.credit_cards[0]
776
+ end
777
+
778
+ it "returns nil if the transaction credit card is not stored in the vault" do
779
+ transaction = Braintree::Transaction.create!(
780
+ :amount => "100.00",
781
+ :type => "sale",
782
+ :credit_card => {
783
+ :number => Braintree::Test::CreditCardNumbers::Visa,
784
+ :expiration_date => "05/2010"
785
+ }
786
+ )
787
+ transaction.vault_credit_card.should == nil
788
+ end
789
+ end
790
+
791
+ describe "vault_customer" do
792
+ it "returns the Braintree::Customer if the transaction customer is stored in the vault" do
793
+ customer = Braintree::Customer.create!(
794
+ :credit_card => {
795
+ :number => Braintree::Test::CreditCardNumbers::Visa,
796
+ :expiration_date => "05/2010"
797
+ }
798
+ )
799
+ transaction = customer.credit_cards[0].sale(:amount => "100.00").transaction
800
+ transaction.vault_customer.should == customer
801
+ end
802
+
803
+ it "returns nil if the transaction customer is not stored in the vault" do
804
+ transaction = Braintree::Transaction.create!(
805
+ :amount => "100.00",
806
+ :type => "sale",
807
+ :credit_card => {
808
+ :number => Braintree::Test::CreditCardNumbers::Visa,
809
+ :expiration_date => "05/2010"
810
+ }
811
+ )
812
+ transaction.vault_customer.should == nil
813
+ end
814
+ end
815
+
816
+ describe "void" do
817
+ it "returns a successful result if successful" do
818
+ result = Braintree::Transaction.create(
819
+ :type => "sale",
820
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
821
+ :credit_card => {
822
+ :number => Braintree::Test::CreditCardNumbers::Visa,
823
+ :expiration_date => "05/2009"
824
+ }
825
+ )
826
+ result.success?.should == true
827
+ transaction = result.transaction
828
+ transaction.status.should == "authorized"
829
+ void_result = transaction.void
830
+ void_result.success?.should == true
831
+ void_result.transaction.should == transaction
832
+ transaction.status.should == void_result.transaction.status
833
+ end
834
+
835
+ it "returns an error result if unsuccessful" do
836
+ transaction = Braintree::Transaction.sale!(
837
+ :amount => Braintree::Test::TransactionAmounts::Decline,
838
+ :credit_card => {
839
+ :number => Braintree::Test::CreditCardNumbers::Visa,
840
+ :expiration_date => "05/2009"
841
+ }
842
+ )
843
+ transaction.status.should == "processor_declined"
844
+ result = transaction.void
845
+ result.success?.should == false
846
+ result.errors.for(:transaction).on(:base)[0].message.should == "Transaction can only be voided if status is authorized or submitted_for_settlement."
847
+ end
848
+ end
849
+
850
+ describe "void!" do
851
+ it "returns the transaction if successful" do
852
+ transaction = Braintree::Transaction.sale!(
853
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
854
+ :credit_card => {
855
+ :number => Braintree::Test::CreditCardNumbers::Visa,
856
+ :expiration_date => "05/2009"
857
+ }
858
+ )
859
+ transaction.void!.should == transaction
860
+ transaction.status.should == "voided"
861
+ end
862
+
863
+ it "raises a ValidationsFailed if unsuccessful" do
864
+ transaction = Braintree::Transaction.sale!(
865
+ :amount => Braintree::Test::TransactionAmounts::Decline,
866
+ :credit_card => {
867
+ :number => Braintree::Test::CreditCardNumbers::Visa,
868
+ :expiration_date => "05/2009"
869
+ }
870
+ )
871
+ transaction.status.should == "processor_declined"
872
+ expect do
873
+ transaction.void!
874
+ end.to raise_error(Braintree::ValidationsFailed)
875
+ end
876
+ end
877
+
878
+ def create_transaction_via_tr(params, tr_data_params)
879
+ response = nil
880
+ Net::HTTP.start(Braintree::Configuration.server, Braintree::Configuration.port) do |http|
881
+ request = Net::HTTP::Post.new("/" + Braintree::Transaction.create_transaction_url.split("/", 4)[3])
882
+ request.add_field "Content-Type", "application/x-www-form-urlencoded"
883
+ params = {
884
+ :tr_data => Braintree::TransparentRedirect.transaction_data({:redirect_url => "http://testing.com"}.merge(tr_data_params))
885
+ }.merge(params)
886
+ request.body = Braintree::Util.hash_to_query_string(params)
887
+ response = http.request(request)
888
+ end
889
+ query_string = response["Location"].split("?", 2).last
890
+ query_string
891
+ end
892
+
893
+ def find_transaction_to_refund
894
+ settled_transactions = Braintree::Transaction.search "settled"
895
+ found = settled_transactions.detect do |t|
896
+ t.status == "settled" && !t.refunded?
897
+ end
898
+ found || raise("unfortunately your test is not as you intended because we could not find a settled transaction that hasn't already been refunded")
899
+ end
900
+ end