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,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