braintree 2.4.0 → 2.5.1

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 (66) hide show
  1. data/README.rdoc +4 -0
  2. data/lib/braintree.rb +43 -32
  3. data/lib/braintree/add_on.rb +4 -0
  4. data/lib/braintree/address.rb +18 -72
  5. data/lib/braintree/address_gateway.rb +76 -0
  6. data/lib/braintree/advanced_search.rb +31 -13
  7. data/lib/braintree/base_module.rb +6 -0
  8. data/lib/braintree/configuration.rb +57 -39
  9. data/lib/braintree/credit_card.rb +75 -129
  10. data/lib/braintree/credit_card_gateway.rb +133 -0
  11. data/lib/braintree/credit_card_verification.rb +8 -0
  12. data/lib/braintree/customer.rb +70 -123
  13. data/lib/braintree/customer_gateway.rb +121 -0
  14. data/lib/braintree/digest.rb +2 -2
  15. data/lib/braintree/discount.rb +4 -0
  16. data/lib/braintree/error_codes.rb +50 -5
  17. data/lib/braintree/error_result.rb +4 -18
  18. data/lib/braintree/errors.rb +1 -2
  19. data/lib/braintree/exceptions.rb +11 -16
  20. data/lib/braintree/gateway.rb +39 -0
  21. data/lib/braintree/http.rb +30 -26
  22. data/lib/braintree/modification.rb +23 -0
  23. data/lib/braintree/resource_collection.rb +1 -1
  24. data/lib/braintree/subscription.rb +29 -129
  25. data/lib/braintree/subscription_gateway.rb +122 -0
  26. data/lib/braintree/subscription_search.rb +6 -7
  27. data/lib/braintree/successful_result.rb +1 -12
  28. data/lib/braintree/test/credit_card_numbers.rb +4 -2
  29. data/lib/braintree/test/transaction_amounts.rb +3 -0
  30. data/lib/braintree/transaction.rb +83 -243
  31. data/lib/braintree/transaction/credit_card_details.rb +4 -4
  32. data/lib/braintree/transaction_gateway.rb +124 -0
  33. data/lib/braintree/transaction_search.rb +5 -3
  34. data/lib/braintree/transparent_redirect.rb +19 -112
  35. data/lib/braintree/transparent_redirect_gateway.rb +105 -0
  36. data/lib/braintree/util.rb +4 -0
  37. data/lib/braintree/validation_error.rb +1 -0
  38. data/lib/braintree/validation_error_collection.rb +5 -23
  39. data/lib/braintree/version.rb +2 -2
  40. data/lib/braintree/xml/parser.rb +1 -1
  41. data/lib/braintree/xml/rexml.rb +2 -2
  42. data/spec/integration/braintree/advanced_search_spec.rb +532 -0
  43. data/spec/integration/braintree/credit_card_spec.rb +5 -8
  44. data/spec/integration/braintree/http_spec.rb +53 -39
  45. data/spec/integration/braintree/subscription_spec.rb +678 -213
  46. data/spec/integration/braintree/transaction_search_spec.rb +318 -43
  47. data/spec/integration/braintree/transaction_spec.rb +134 -3
  48. data/spec/integration/braintree/transparent_redirect_spec.rb +1 -1
  49. data/spec/spec_helper.rb +55 -4
  50. data/spec/unit/braintree/address_spec.rb +8 -8
  51. data/spec/unit/braintree/base_module_spec.rb +1 -1
  52. data/spec/unit/braintree/configuration_spec.rb +34 -29
  53. data/spec/unit/braintree/credit_card_spec.rb +14 -12
  54. data/spec/unit/braintree/credit_card_verification_spec.rb +16 -0
  55. data/spec/unit/braintree/customer_spec.rb +10 -8
  56. data/spec/unit/braintree/digest_spec.rb +8 -17
  57. data/spec/unit/braintree/error_result_spec.rb +12 -2
  58. data/spec/unit/braintree/http_spec.rb +2 -2
  59. data/spec/unit/braintree/subscription_search_spec.rb +77 -0
  60. data/spec/unit/braintree/subscription_spec.rb +16 -8
  61. data/spec/unit/braintree/transaction_spec.rb +17 -12
  62. data/spec/unit/braintree/transparent_redirect_spec.rb +12 -12
  63. data/spec/unit/braintree/util_spec.rb +24 -0
  64. data/spec/unit/braintree/xml/parser_spec.rb +1 -1
  65. data/spec/unit/braintree_spec.rb +1 -1
  66. metadata +16 -5
@@ -807,13 +807,7 @@ describe Braintree::CreditCard do
807
807
  end
808
808
 
809
809
  describe "self.expired" do
810
- it "finds expired payment methods, paginated" do
811
- collection = Braintree::CreditCard.expired
812
- collection.maximum_size.should > 0
813
- collection.all? { |pm| pm.expired?.should == true }
814
- end
815
-
816
- it "can iterate over all items" do
810
+ it "can iterate over all items, and make sure they are all expired" do
817
811
  customer = Braintree::Customer.all.first
818
812
 
819
813
  (110 - Braintree::CreditCard.expired.maximum_size).times do
@@ -827,7 +821,10 @@ describe Braintree::CreditCard do
827
821
  collection = Braintree::CreditCard.expired
828
822
  collection.maximum_size.should > 100
829
823
 
830
- credit_card_ids = collection.map {|c| c.token }.uniq.compact
824
+ credit_card_ids = collection.map do |c|
825
+ c.expired?.should == true
826
+ c.token
827
+ end.uniq.compact
831
828
  credit_card_ids.size.should == collection.maximum_size
832
829
  end
833
830
  end
@@ -7,7 +7,7 @@ describe Braintree::Http do
7
7
  original_key = Braintree::Configuration.public_key
8
8
  Braintree::Configuration.public_key = "invalid_public_key"
9
9
  expect do
10
- Braintree::Http.get "/customers"
10
+ Braintree::Configuration.instantiate.http.get "/customers"
11
11
  end.to raise_error(Braintree::AuthenticationError)
12
12
  ensure
13
13
  Braintree::Configuration.public_key = original_key
@@ -16,7 +16,7 @@ describe Braintree::Http do
16
16
 
17
17
  it "raises an AuthorizationError if authorization fails" do
18
18
  expect do
19
- Braintree::Http.get "/users"
19
+ Braintree::Configuration.instantiate.http.get "/users"
20
20
  end.to raise_error(Braintree::AuthorizationError)
21
21
  end
22
22
  end
@@ -73,47 +73,43 @@ describe Braintree::Http do
73
73
  end
74
74
 
75
75
  it "sets the User-Agent header using the default user agent" do
76
- response = Braintree::Http.get("/test/headers")
76
+ response = Braintree::Configuration.instantiate.http.get "/test/headers"
77
77
  response[:headers][:HTTP_USER_AGENT].should == "Braintree Ruby Gem #{Braintree::Version::String}"
78
78
  end
79
79
 
80
80
  it "sets the User-Agent header using a customer user agent" do
81
81
  Braintree::Configuration.custom_user_agent = "ActiveMerchant 1.2.3"
82
- response = Braintree::Http.get("/test/headers")
82
+ response = Braintree::Configuration.instantiate.http.get "/test/headers"
83
83
  response[:headers][:HTTP_USER_AGENT].should == "Braintree Ruby Gem #{Braintree::Version::String} (ActiveMerchant 1.2.3)"
84
84
  end
85
85
  end
86
86
 
87
87
  describe "ssl verification" do
88
88
  it "rejects when the certificate isn't verified by our certificate authority (self-signed)" do
89
- begin
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)
89
+ config = Braintree::Configuration.instantiate
90
+ config.stub(:ssl?).and_return(true)
91
+ config.stub(:port).and_return(8443)
92
+
93
+ start_ssl_server do
94
+ expect do
95
+ config.http._http_do(Net::HTTP::Get, "/login")
96
+ end.to raise_error(Braintree::SSLCertificateError, /Preverify: false, Error: self signed certificate/)
99
97
  end
100
98
  end
101
99
 
102
100
  it "rejets when the certificate is signed by a different (but valid) root CA" do
103
101
  # Random CA root file from a different certificate authority
104
- begin
105
- original_ca_file = Braintree::Configuration.ca_file
106
- Braintree::Configuration.stub(:ca_file).and_return(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ssl", "geotrust_global.crt")))
107
- use_ssl = Braintree::Configuration.ssl?
108
- Braintree::Configuration.stub(:ssl?).and_return(true)
109
- Braintree::Configuration.stub(:port).and_return(8443)
110
-
111
- start_ssl_server do
112
- expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to raise_error(Braintree::SSLCertificateError, /Preverify: false, Error: self signed certificate/)
113
- end
114
- ensure
115
- Braintree::Configuration.stub(:ssl?).and_return(use_ssl)
116
- Braintree::Configuration.stub(:ca_file).and_return(original_ca_file)
102
+ config = Braintree::Configuration.instantiate
103
+ config.stub(:ca_file).and_return(
104
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ssl", "geotrust_global.crt"))
105
+ )
106
+ config.stub(:ssl?).and_return(true)
107
+ config.stub(:port).and_return(8443)
108
+
109
+ start_ssl_server do
110
+ expect do
111
+ config.http._http_do(Net::HTTP::Get, "/login")
112
+ end.to raise_error(Braintree::SSLCertificateError, /Preverify: false, Error: self signed certificate/)
117
113
  end
118
114
  end
119
115
 
@@ -123,7 +119,9 @@ describe Braintree::Http do
123
119
  Braintree::Configuration.environment = :qa
124
120
  Braintree::Configuration.stub(:base_merchant_path).and_return("/")
125
121
 
126
- expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
122
+ expect do
123
+ Braintree::Configuration.instantiate.http._http_do(Net::HTTP::Get, "/login")
124
+ end.to_not raise_error
127
125
  ensure
128
126
  Braintree::Configuration.environment = original_env
129
127
  end
@@ -135,7 +133,9 @@ describe Braintree::Http do
135
133
  Braintree::Configuration.environment = :sandbox
136
134
  Braintree::Configuration.stub(:base_merchant_path).and_return("/")
137
135
 
138
- expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
136
+ expect do
137
+ Braintree::Configuration.instantiate.http._http_do(Net::HTTP::Get, "/login")
138
+ end.to_not raise_error
139
139
  ensure
140
140
  Braintree::Configuration.environment = original_env
141
141
  end
@@ -147,7 +147,9 @@ describe Braintree::Http do
147
147
  Braintree::Configuration.environment = :production
148
148
  Braintree::Configuration.stub(:base_merchant_path).and_return("/")
149
149
 
150
- expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to_not raise_error
150
+ expect do
151
+ Braintree::Configuration.instantiate.http._http_do(Net::HTTP::Get, "/login")
152
+ end.to_not raise_error
151
153
  ensure
152
154
  Braintree::Configuration.environment = original_env
153
155
  end
@@ -157,11 +159,13 @@ describe Braintree::Http do
157
159
  begin
158
160
  original_env = Braintree::Configuration.environment
159
161
  Braintree::Configuration.environment = :qa
160
- Braintree::Configuration.stub(:base_merchant_path).and_return("/")
161
- original_ca_file = Braintree::Configuration.ca_file
162
- Braintree::Configuration.stub(:ca_file).and_return(nil)
162
+ config = Braintree::Configuration.instantiate
163
+ config.stub(:base_merchant_path).and_return("/")
164
+ config.stub(:ca_file).and_return(nil)
163
165
 
164
- expect { Braintree::Http._http_do(Net::HTTP::Get, "/login") }.to raise_error(Braintree::SSLCertificateError)
166
+ expect do
167
+ config.http._http_do(Net::HTTP::Get, "/login")
168
+ end.to raise_error(Braintree::SSLCertificateError)
165
169
  ensure
166
170
  Braintree::Configuration.environment = original_env
167
171
  end
@@ -172,18 +176,24 @@ describe Braintree::Http do
172
176
  describe "self._verify_ssl_certificate" do
173
177
  it "raises if preverify is false" do
174
178
  context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
175
- expect { Braintree::Http._verify_ssl_certificate(false, context) }.to raise_error(Braintree::SSLCertificateError)
179
+ expect do
180
+ Braintree::Configuration.instantiate.http._verify_ssl_certificate(false, context)
181
+ end.to raise_error(Braintree::SSLCertificateError)
176
182
  end
177
183
 
178
184
  it "raise if ssl_context doesn't have an error code of 0" do
179
185
  context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
180
186
  context.error = 19 # ca_file incorrect, self-signed
181
- expect { Braintree::Http._verify_ssl_certificate(true, context) }.to raise_error(Braintree::SSLCertificateError)
187
+ expect do
188
+ Braintree::Configuration.instantiate.http._verify_ssl_certificate(true, context)
189
+ end.to raise_error(Braintree::SSLCertificateError)
182
190
  end
183
191
 
184
192
  it "doesn't raise if there is no error" do
185
193
  context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
186
- expect { Braintree::Http._verify_ssl_certificate(true, context) }.to_not raise_error
194
+ expect do
195
+ Braintree::Configuration.instantiate.http._verify_ssl_certificate(true, context)
196
+ end.to_not raise_error
187
197
  end
188
198
 
189
199
  it "logs when there is an error" do
@@ -194,7 +204,9 @@ describe Braintree::Http do
194
204
  utc_or_gmt = Time.now.utc.strftime("%Z")
195
205
  context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
196
206
  context.error = 19
197
- expect { Braintree::Http._verify_ssl_certificate(false, context) }.to raise_error(Braintree::SSLCertificateError)
207
+ expect do
208
+ Braintree::Configuration.instantiate.http._verify_ssl_certificate(false, context)
209
+ end.to raise_error(Braintree::SSLCertificateError)
198
210
  output.string.should include("SSL Verification failed -- Preverify: false, Error: self signed certificate in certificate chain (19)")
199
211
  ensure
200
212
  Braintree::Configuration.logger = old_logger
@@ -208,7 +220,9 @@ describe Braintree::Http do
208
220
  Braintree::Configuration.logger = Logger.new(output)
209
221
  utc_or_gmt = Time.now.utc.strftime("%Z")
210
222
  context = OpenSSL::X509::StoreContext.new(OpenSSL::X509::Store.new)
211
- expect { Braintree::Http._verify_ssl_certificate(true, context) }.to_not raise_error(Braintree::SSLCertificateError)
223
+ expect do
224
+ Braintree::Configuration.instantiate.http._verify_ssl_certificate(true, context)
225
+ end.to_not raise_error(Braintree::SSLCertificateError)
212
226
  output.string.should == ""
213
227
  ensure
214
228
  Braintree::Configuration.logger = old_logger
@@ -1,21 +1,6 @@
1
1
  require File.dirname(__FILE__) + "/../spec_helper"
2
2
 
3
3
  describe Braintree::Subscription do
4
- TrialPlan = {
5
- :description => "Plan for integration tests -- with trial",
6
- :id => "integration_trial_plan",
7
- :price => BigDecimal.new("43.21"),
8
- :trial_period => true,
9
- :trial_duration => 2,
10
- :trial_duration_unit => Braintree::Subscription::TrialDurationUnit::Day
11
- }
12
-
13
- TriallessPlan = {
14
- :description => "Plan for integration tests -- without a trial",
15
- :id => "integration_trialless_plan",
16
- :price => BigDecimal.new("12.34"),
17
- :trial_period => false
18
- }
19
4
 
20
5
  before(:each) do
21
6
  @credit_card = Braintree::Customer.create!(
@@ -30,7 +15,7 @@ describe Braintree::Subscription do
30
15
  it "is successful with a miniumum of params" do
31
16
  result = Braintree::Subscription.create(
32
17
  :payment_method_token => @credit_card.token,
33
- :plan_id => TriallessPlan[:id]
18
+ :plan_id => SpecHelper::TriallessPlan[:id]
34
19
  )
35
20
 
36
21
  date_format = /^\d{4}\D\d{1,2}\D\d{1,2}$/
@@ -45,6 +30,7 @@ describe Braintree::Subscription do
45
30
  result.subscription.billing_period_end_date.should match(date_format)
46
31
 
47
32
  result.subscription.failure_count.should == 0
33
+ result.subscription.next_bill_amount.should == "12.34"
48
34
  result.subscription.payment_method_token.should == @credit_card.token
49
35
  end
50
36
 
@@ -52,7 +38,7 @@ describe Braintree::Subscription do
52
38
  new_id = rand(36**9).to_s(36)
53
39
  result = Braintree::Subscription.create(
54
40
  :payment_method_token => @credit_card.token,
55
- :plan_id => TriallessPlan[:id],
41
+ :plan_id => SpecHelper::TrialPlan[:id],
56
42
  :id => new_id
57
43
  )
58
44
 
@@ -61,11 +47,72 @@ describe Braintree::Subscription do
61
47
  result.subscription.id.should == new_id
62
48
  end
63
49
 
50
+ context "billing_day_of_month" do
51
+ it "inherits from the plan if not provided" do
52
+ result = Braintree::Subscription.create(
53
+ :payment_method_token => @credit_card.token,
54
+ :plan_id => SpecHelper::BillingDayOfMonthPlan[:id]
55
+ )
56
+
57
+ result.success?.should == true
58
+ result.subscription.billing_day_of_month.should == 5
59
+ end
60
+
61
+ it "allows overriding" do
62
+ result = Braintree::Subscription.create(
63
+ :payment_method_token => @credit_card.token,
64
+ :plan_id => SpecHelper::BillingDayOfMonthPlan[:id],
65
+ :billing_day_of_month => 25
66
+ )
67
+
68
+ result.success?.should == true
69
+ result.subscription.billing_day_of_month.should == 25
70
+ end
71
+
72
+ it "allows overriding with start_immediately" do
73
+ result = Braintree::Subscription.create(
74
+ :payment_method_token => @credit_card.token,
75
+ :plan_id => SpecHelper::BillingDayOfMonthPlan[:id],
76
+ :options => {
77
+ :start_immediately => true
78
+ }
79
+ )
80
+
81
+ result.success?.should == true
82
+ result.subscription.transactions.size.should == 1
83
+ end
84
+ end
85
+
86
+ context "first_billing_date" do
87
+ it "allows specifying" do
88
+ result = Braintree::Subscription.create(
89
+ :payment_method_token => @credit_card.token,
90
+ :plan_id => SpecHelper::BillingDayOfMonthPlan[:id],
91
+ :first_billing_date => Date.today + 3
92
+ )
93
+
94
+ result.success?.should == true
95
+ result.subscription.first_billing_date.should == (Date.today + 3).to_s
96
+ result.subscription.status.should == Braintree::Subscription::Status::Pending
97
+ end
98
+
99
+ it "returns an error if the date is in the past" do
100
+ result = Braintree::Subscription.create(
101
+ :payment_method_token => @credit_card.token,
102
+ :plan_id => SpecHelper::BillingDayOfMonthPlan[:id],
103
+ :first_billing_date => Date.today - 3
104
+ )
105
+
106
+ result.success?.should == false
107
+ result.errors.for(:subscription).on(:first_billing_date).first.code.should == Braintree::ErrorCodes::Subscription::FirstBillingDateCannotBeInThePast
108
+ end
109
+ end
110
+
64
111
  context "merchant_account_id" do
65
112
  it "defaults to the default merchant account if no merchant_account_id is provided" do
66
113
  result = Braintree::Subscription.create(
67
114
  :payment_method_token => @credit_card.token,
68
- :plan_id => TriallessPlan[:id]
115
+ :plan_id => SpecHelper::TrialPlan[:id]
69
116
  )
70
117
 
71
118
  result.success?.should == true
@@ -75,7 +122,7 @@ describe Braintree::Subscription do
75
122
  it "allows setting the merchant_account_id" do
76
123
  result = Braintree::Subscription.create(
77
124
  :payment_method_token => @credit_card.token,
78
- :plan_id => TriallessPlan[:id],
125
+ :plan_id => SpecHelper::TrialPlan[:id],
79
126
  :merchant_account_id => SpecHelper::NonDefaultMerchantAccountId
80
127
  )
81
128
 
@@ -84,12 +131,36 @@ describe Braintree::Subscription do
84
131
  end
85
132
  end
86
133
 
134
+ context "number_of_billing_cycles" do
135
+ it "sets the number of billing cycles on the subscription when provided" do
136
+ result = Braintree::Subscription.create(
137
+ :payment_method_token => @credit_card.token,
138
+ :plan_id => SpecHelper::TrialPlan[:id],
139
+ :number_of_billing_cycles => 10
140
+ )
141
+
142
+ result.success?.should == true
143
+ result.subscription.number_of_billing_cycles.should == 10
144
+ end
145
+
146
+ it "sets the number of billing cycles to nil if :never_expires => true" do
147
+ result = Braintree::Subscription.create(
148
+ :payment_method_token => @credit_card.token,
149
+ :plan_id => SpecHelper::TrialPlan[:id],
150
+ :never_expires => true
151
+ )
152
+
153
+ result.success?.should == true
154
+ result.subscription.number_of_billing_cycles.should == nil
155
+ end
156
+ end
157
+
87
158
  context "trial period" do
88
159
  context "defaults to the plan's trial period settings" do
89
160
  it "with no trial" do
90
161
  result = Braintree::Subscription.create(
91
162
  :payment_method_token => @credit_card.token,
92
- :plan_id => TriallessPlan[:id]
163
+ :plan_id => SpecHelper::TriallessPlan[:id]
93
164
  )
94
165
 
95
166
  result.subscription.trial_period.should == false
@@ -100,7 +171,7 @@ describe Braintree::Subscription do
100
171
  it "with a trial" do
101
172
  result = Braintree::Subscription.create(
102
173
  :payment_method_token => @credit_card.token,
103
- :plan_id => TrialPlan[:id]
174
+ :plan_id => SpecHelper::TrialPlan[:id]
104
175
  )
105
176
 
106
177
  result.subscription.trial_period.should == true
@@ -111,7 +182,7 @@ describe Braintree::Subscription do
111
182
  it "can alter the trial period params" do
112
183
  result = Braintree::Subscription.create(
113
184
  :payment_method_token => @credit_card.token,
114
- :plan_id => TrialPlan[:id],
185
+ :plan_id => SpecHelper::TrialPlan[:id],
115
186
  :trial_duration => 5,
116
187
  :trial_duration_unit => Braintree::Subscription::TrialDurationUnit::Month
117
188
  )
@@ -124,7 +195,7 @@ describe Braintree::Subscription do
124
195
  it "can override the trial_period param" do
125
196
  result = Braintree::Subscription.create(
126
197
  :payment_method_token => @credit_card.token,
127
- :plan_id => TrialPlan[:id],
198
+ :plan_id => SpecHelper::TrialPlan[:id],
128
199
  :trial_period => false
129
200
  )
130
201
 
@@ -134,7 +205,7 @@ describe Braintree::Subscription do
134
205
  it "doesn't create a transaction if there's a trial period" do
135
206
  result = Braintree::Subscription.create(
136
207
  :payment_method_token => @credit_card.token,
137
- :plan_id => TrialPlan[:id]
208
+ :plan_id => SpecHelper::TrialPlan[:id]
138
209
  )
139
210
 
140
211
  result.subscription.transactions.size.should == 0
@@ -145,12 +216,12 @@ describe Braintree::Subscription do
145
216
  it "creates a transaction if no trial period" do
146
217
  result = Braintree::Subscription.create(
147
218
  :payment_method_token => @credit_card.token,
148
- :plan_id => TriallessPlan[:id]
219
+ :plan_id => SpecHelper::TriallessPlan[:id]
149
220
  )
150
221
 
151
222
  result.subscription.transactions.size.should == 1
152
223
  result.subscription.transactions.first.should be_a(Braintree::Transaction)
153
- result.subscription.transactions.first.amount.should == TriallessPlan[:price]
224
+ result.subscription.transactions.first.amount.should == SpecHelper::TriallessPlan[:price]
154
225
  result.subscription.transactions.first.type.should == Braintree::Transaction::Type::Sale
155
226
  result.subscription.transactions.first.subscription_id.should == result.subscription.id
156
227
  end
@@ -158,7 +229,7 @@ describe Braintree::Subscription do
158
229
  it "does not create the subscription and returns the transaction if the transaction is not successful" do
159
230
  result = Braintree::Subscription.create(
160
231
  :payment_method_token => @credit_card.token,
161
- :plan_id => TriallessPlan[:id],
232
+ :plan_id => SpecHelper::TriallessPlan[:id],
162
233
  :price => Braintree::Test::TransactionAmounts::Decline
163
234
  )
164
235
 
@@ -172,16 +243,16 @@ describe Braintree::Subscription do
172
243
  it "defaults to the plan's price" do
173
244
  result = Braintree::Subscription.create(
174
245
  :payment_method_token => @credit_card.token,
175
- :plan_id => TrialPlan[:id]
246
+ :plan_id => SpecHelper::TrialPlan[:id]
176
247
  )
177
248
 
178
- result.subscription.price.should == TrialPlan[:price]
249
+ result.subscription.price.should == SpecHelper::TrialPlan[:price]
179
250
  end
180
251
 
181
252
  it "can be overridden" do
182
253
  result = Braintree::Subscription.create(
183
254
  :payment_method_token => @credit_card.token,
184
- :plan_id => TrialPlan[:id],
255
+ :plan_id => SpecHelper::TrialPlan[:id],
185
256
  :price => 98.76
186
257
  )
187
258
 
@@ -194,7 +265,7 @@ describe Braintree::Subscription do
194
265
  it "has validation errors on id" do
195
266
  result = Braintree::Subscription.create(
196
267
  :payment_method_token => @credit_card.token,
197
- :plan_id => TrialPlan[:id],
268
+ :plan_id => SpecHelper::TrialPlan[:id],
198
269
  :id => "invalid token"
199
270
  )
200
271
  result.success?.should == false
@@ -205,14 +276,14 @@ describe Braintree::Subscription do
205
276
  duplicate_token = "duplicate_token_#{rand(36**8).to_s(36)}"
206
277
  result = Braintree::Subscription.create(
207
278
  :payment_method_token => @credit_card.token,
208
- :plan_id => TrialPlan[:id],
279
+ :plan_id => SpecHelper::TrialPlan[:id],
209
280
  :id => duplicate_token
210
281
  )
211
282
  result.success?.should == true
212
283
 
213
284
  result = Braintree::Subscription.create(
214
285
  :payment_method_token => @credit_card.token,
215
- :plan_id => TrialPlan[:id],
286
+ :plan_id => SpecHelper::TrialPlan[:id],
216
287
  :id => duplicate_token
217
288
  )
218
289
  result.success?.should == false
@@ -222,7 +293,7 @@ describe Braintree::Subscription do
222
293
  it "trial duration required" do
223
294
  result = Braintree::Subscription.create(
224
295
  :payment_method_token => @credit_card.token,
225
- :plan_id => TrialPlan[:id],
296
+ :plan_id => SpecHelper::TrialPlan[:id],
226
297
  :trial_period => true,
227
298
  :trial_duration => nil
228
299
  )
@@ -233,7 +304,7 @@ describe Braintree::Subscription do
233
304
  it "trial duration unit required" do
234
305
  result = Braintree::Subscription.create(
235
306
  :payment_method_token => @credit_card.token,
236
- :plan_id => TrialPlan[:id],
307
+ :plan_id => SpecHelper::TrialPlan[:id],
237
308
  :trial_period => true,
238
309
  :trial_duration => 2,
239
310
  :trial_duration_unit => nil
@@ -242,13 +313,218 @@ describe Braintree::Subscription do
242
313
  result.errors.for(:subscription).on(:trial_duration_unit)[0].message.should == "Trial Duration Unit is invalid."
243
314
  end
244
315
  end
316
+
317
+ context "add_ons and discounts" do
318
+ it "does not inherit the add_ons and discounts from the plan when do_not_inherit_add_ons_or_discounts is set" do
319
+ result = Braintree::Subscription.create(
320
+ :payment_method_token => @credit_card.token,
321
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id],
322
+ :options => {:do_not_inherit_add_ons_or_discounts => true}
323
+ )
324
+ result.success?.should == true
325
+
326
+ subscription = result.subscription
327
+
328
+ subscription.add_ons.size.should == 0
329
+ subscription.discounts.size.should == 0
330
+ end
331
+
332
+ it "inherits the add_ons and discounts from the plan when not specified" do
333
+ result = Braintree::Subscription.create(
334
+ :payment_method_token => @credit_card.token,
335
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id]
336
+ )
337
+ result.success?.should == true
338
+
339
+ subscription = result.subscription
340
+
341
+ subscription.add_ons.size.should == 2
342
+ add_ons = subscription.add_ons.sort_by { |add_on| add_on.id }
343
+
344
+ add_ons.first.id.should == "increase_10"
345
+ add_ons.first.amount.should == BigDecimal.new("10.00")
346
+ add_ons.first.quantity.should == 1
347
+ add_ons.first.number_of_billing_cycles.should be_nil
348
+ add_ons.first.never_expires?.should be_true
349
+
350
+ add_ons.last.id.should == "increase_20"
351
+ add_ons.last.amount.should == BigDecimal.new("20.00")
352
+ add_ons.last.quantity.should == 1
353
+ add_ons.last.number_of_billing_cycles.should be_nil
354
+ add_ons.last.never_expires?.should be_true
355
+
356
+ subscription.discounts.size.should == 2
357
+ discounts = subscription.discounts.sort_by { |discount| discount.id }
358
+
359
+ discounts.first.id.should == "discount_11"
360
+ discounts.first.amount.should == BigDecimal.new("11.00")
361
+ discounts.first.quantity.should == 1
362
+ discounts.first.number_of_billing_cycles.should be_nil
363
+ discounts.first.never_expires?.should be_true
364
+
365
+ discounts.last.id.should == "discount_7"
366
+ discounts.last.amount.should == BigDecimal.new("7.00")
367
+ discounts.last.quantity.should == 1
368
+ discounts.last.number_of_billing_cycles.should be_nil
369
+ discounts.last.never_expires?.should be_true
370
+ end
371
+
372
+ it "allows overriding of inherited add_ons and discounts" do
373
+ result = Braintree::Subscription.create(
374
+ :payment_method_token => @credit_card.token,
375
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id],
376
+ :add_ons => {
377
+ :update => [
378
+ {
379
+ :amount => BigDecimal.new("50.00"),
380
+ :existing_id => SpecHelper::AddOnIncrease10,
381
+ :quantity => 2,
382
+ :number_of_billing_cycles => 5
383
+ }
384
+ ]
385
+ },
386
+ :discounts => {
387
+ :update => [
388
+ {
389
+ :amount => BigDecimal.new("15.00"),
390
+ :existing_id => SpecHelper::Discount7,
391
+ :quantity => 3,
392
+ :never_expires => true
393
+ }
394
+ ]
395
+ }
396
+ )
397
+ result.success?.should == true
398
+
399
+ subscription = result.subscription
400
+
401
+ subscription.add_ons.size.should == 2
402
+ add_ons = subscription.add_ons.sort_by { |add_on| add_on.id }
403
+
404
+ add_ons.first.id.should == "increase_10"
405
+ add_ons.first.amount.should == BigDecimal.new("50.00")
406
+ add_ons.first.quantity.should == 2
407
+ add_ons.first.number_of_billing_cycles.should == 5
408
+ add_ons.first.never_expires?.should be_false
409
+
410
+ add_ons.last.id.should == "increase_20"
411
+ add_ons.last.amount.should == BigDecimal.new("20.00")
412
+ add_ons.last.quantity.should == 1
413
+
414
+ subscription.discounts.size.should == 2
415
+ discounts = subscription.discounts.sort_by { |discount| discount.id }
416
+
417
+ discounts.first.id.should == "discount_11"
418
+ discounts.first.amount.should == BigDecimal.new("11.00")
419
+ discounts.first.quantity.should == 1
420
+
421
+ discounts.last.id.should == "discount_7"
422
+ discounts.last.amount.should == BigDecimal.new("15.00")
423
+ discounts.last.quantity.should == 3
424
+ discounts.last.number_of_billing_cycles.should be_nil
425
+ discounts.last.never_expires?.should be_true
426
+ end
427
+
428
+ it "allows deleting of inherited add_ons and discounts" do
429
+ result = Braintree::Subscription.create(
430
+ :payment_method_token => @credit_card.token,
431
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id],
432
+ :add_ons => {
433
+ :remove => [SpecHelper::AddOnIncrease10]
434
+ },
435
+ :discounts => {
436
+ :remove => [SpecHelper::Discount7]
437
+ }
438
+ )
439
+ result.success?.should == true
440
+
441
+ subscription = result.subscription
442
+
443
+ subscription.add_ons.size.should == 1
444
+ subscription.add_ons.first.id.should == "increase_20"
445
+ subscription.add_ons.first.amount.should == BigDecimal.new("20.00")
446
+ subscription.add_ons.first.quantity.should == 1
447
+
448
+ subscription.discounts.size.should == 1
449
+ subscription.discounts.last.id.should == "discount_11"
450
+ subscription.discounts.last.amount.should == BigDecimal.new("11.00")
451
+ subscription.discounts.last.quantity.should == 1
452
+ end
453
+
454
+ it "allows adding new add_ons and discounts" do
455
+ result = Braintree::Subscription.create(
456
+ :payment_method_token => @credit_card.token,
457
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id],
458
+ :add_ons => {
459
+ :add => [{:inherited_from_id => SpecHelper::AddOnIncrease30}]
460
+ },
461
+ :discounts => {
462
+ :add => [{:inherited_from_id => SpecHelper::Discount15}]
463
+ }
464
+ )
465
+ result.success?.should == true
466
+ subscription = result.subscription
467
+
468
+ subscription.add_ons.size.should == 3
469
+ add_ons = subscription.add_ons.sort_by { |add_on| add_on.id }
470
+
471
+ add_ons[0].id.should == "increase_10"
472
+ add_ons[0].amount.should == BigDecimal.new("10.00")
473
+ add_ons[0].quantity.should == 1
474
+
475
+ add_ons[1].id.should == "increase_20"
476
+ add_ons[1].amount.should == BigDecimal.new("20.00")
477
+ add_ons[1].quantity.should == 1
478
+
479
+ add_ons[2].id.should == "increase_30"
480
+ add_ons[2].amount.should == BigDecimal.new("30.00")
481
+ add_ons[2].quantity.should == 1
482
+
483
+ subscription.discounts.size.should == 3
484
+ discounts = subscription.discounts.sort_by { |discount| discount.id }
485
+
486
+ discounts[0].id.should == "discount_11"
487
+ discounts[0].amount.should == BigDecimal.new("11.00")
488
+ discounts[0].quantity.should == 1
489
+
490
+ discounts[1].id.should == "discount_15"
491
+ discounts[1].amount.should == BigDecimal.new("15.00")
492
+ discounts[1].quantity.should == 1
493
+
494
+ discounts[2].id.should == "discount_7"
495
+ discounts[2].amount.should == BigDecimal.new("7.00")
496
+ discounts[2].quantity.should == 1
497
+ end
498
+
499
+ it "properly parses validation errors for arrays" do
500
+ result = Braintree::Subscription.create(
501
+ :payment_method_token => @credit_card.token,
502
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id],
503
+ :add_ons => {
504
+ :update => [
505
+ {
506
+ :existing_id => SpecHelper::AddOnIncrease10,
507
+ :amount => "invalid"
508
+ },
509
+ {
510
+ :existing_id => SpecHelper::AddOnIncrease20,
511
+ :quantity => -10,
512
+ }
513
+ ]
514
+ }
515
+ )
516
+ result.success?.should == false
517
+ result.errors.for(:subscription).for(:add_ons).for(:update).for_index(0).on(:amount)[0].code.should == Braintree::ErrorCodes::Subscription::Modification::AmountIsInvalid
518
+ result.errors.for(:subscription).for(:add_ons).for(:update).for_index(1).on(:quantity)[0].code.should == Braintree::ErrorCodes::Subscription::Modification::QuantityIsInvalid
519
+ end
520
+ end
245
521
  end
246
522
 
247
523
  describe "self.find" do
248
524
  it "finds a subscription" do
249
525
  result = Braintree::Subscription.create(
250
526
  :payment_method_token => @credit_card.token,
251
- :plan_id => TriallessPlan[:id]
527
+ :plan_id => SpecHelper::TrialPlan[:id]
252
528
  )
253
529
  result.success?.should == true
254
530
 
@@ -267,7 +543,7 @@ describe Braintree::Subscription do
267
543
  @subscription = Braintree::Subscription.create(
268
544
  :payment_method_token => @credit_card.token,
269
545
  :price => 54.32,
270
- :plan_id => TriallessPlan[:id]
546
+ :plan_id => SpecHelper::TriallessPlan[:id]
271
547
  ).subscription
272
548
  end
273
549
 
@@ -300,12 +576,12 @@ describe Braintree::Subscription do
300
576
  result = Braintree::Subscription.update(@subscription.id,
301
577
  :id => new_id,
302
578
  :price => 9999.88,
303
- :plan_id => TrialPlan[:id]
579
+ :plan_id => SpecHelper::TrialPlan[:id]
304
580
  )
305
581
 
306
582
  result.success?.should == true
307
583
  result.subscription.id.should =~ /#{new_id}/
308
- result.subscription.plan_id.should == TrialPlan[:id]
584
+ result.subscription.plan_id.should == SpecHelper::TrialPlan[:id]
309
585
  result.subscription.price.should == BigDecimal.new("9999.88")
310
586
  end
311
587
 
@@ -319,6 +595,28 @@ describe Braintree::Subscription do
319
595
  result.subscription.transactions.size.should == @subscription.transactions.size + 1
320
596
  end
321
597
 
598
+ it "allows the user to force proration if there is a charge" do
599
+ result = Braintree::Subscription.update(@subscription.id,
600
+ :price => @subscription.price.to_f + 1,
601
+ :options => { :prorate_charges => true }
602
+ )
603
+
604
+ result.success?.should == true
605
+ result.subscription.price.to_f.should == @subscription.price.to_f + 1
606
+ result.subscription.transactions.size.should == @subscription.transactions.size + 1
607
+ end
608
+
609
+ it "allows the user to prevent proration if there is a charge" do
610
+ result = Braintree::Subscription.update(@subscription.id,
611
+ :price => @subscription.price.to_f + 1,
612
+ :options => { :prorate_charges => false }
613
+ )
614
+
615
+ result.success?.should == true
616
+ result.subscription.price.to_f.should == @subscription.price.to_f + 1
617
+ result.subscription.transactions.size.should == @subscription.transactions.size
618
+ end
619
+
322
620
  it "doesn't prorate if price decreases" do
323
621
  result = Braintree::Subscription.update(@subscription.id,
324
622
  :price => @subscription.price.to_f - 1
@@ -334,7 +632,7 @@ describe Braintree::Subscription do
334
632
  before(:each) do
335
633
  @subscription = Braintree::Subscription.create(
336
634
  :payment_method_token => @credit_card.token,
337
- :plan_id => TrialPlan[:id]
635
+ :plan_id => SpecHelper::TrialPlan[:id]
338
636
  ).subscription
339
637
  end
340
638
 
@@ -368,7 +666,7 @@ describe Braintree::Subscription do
368
666
  duplicate_id = "new_id_#{rand(36**6).to_s(36)}"
369
667
  duplicate = Braintree::Subscription.create(
370
668
  :payment_method_token => @credit_card.token,
371
- :plan_id => TrialPlan[:id],
669
+ :plan_id => SpecHelper::TrialPlan[:id],
372
670
  :id => duplicate_id
373
671
  )
374
672
  result = Braintree::Subscription.update(
@@ -383,7 +681,7 @@ describe Braintree::Subscription do
383
681
  subscription = Braintree::Subscription.create(
384
682
  :payment_method_token => @credit_card.token,
385
683
  :price => 54.32,
386
- :plan_id => TriallessPlan[:id]
684
+ :plan_id => SpecHelper::TriallessPlan[:id]
387
685
  ).subscription
388
686
 
389
687
  result = Braintree::Subscription.cancel(subscription.id)
@@ -396,15 +694,201 @@ describe Braintree::Subscription do
396
694
  result.errors.for(:subscription)[0].code.should == Braintree::ErrorCodes::Subscription::CannotEditCanceledSubscription
397
695
  end
398
696
  end
399
- end
400
697
 
698
+ context "number_of_billing_cycles" do
699
+ it "sets the number of billing cycles on the subscription when provided" do
700
+ subscription = Braintree::Subscription.create(
701
+ :payment_method_token => @credit_card.token,
702
+ :plan_id => SpecHelper::TriallessPlan[:id],
703
+ :number_of_billing_cycles => 10
704
+ ).subscription
705
+
706
+ result = Braintree::Subscription.update(
707
+ subscription.id,
708
+ :number_of_billing_cycles => 5
709
+ )
710
+
711
+ result.subscription.number_of_billing_cycles.should == 5
712
+ end
713
+
714
+ it "sets the number of billing cycles to nil if :never_expires => true" do
715
+ subscription = Braintree::Subscription.create(
716
+ :payment_method_token => @credit_card.token,
717
+ :plan_id => SpecHelper::TriallessPlan[:id],
718
+ :number_of_billing_cycles => 10
719
+ ).subscription
720
+
721
+ result = Braintree::Subscription.update(
722
+ subscription.id,
723
+ :never_expires => true
724
+ )
725
+
726
+ result.success?.should == true
727
+ result.subscription.number_of_billing_cycles.should == nil
728
+ result.subscription.never_expires?.should be_true
729
+ end
730
+ end
731
+
732
+ context "add_ons and discounts" do
733
+ it "can update add_ons and discounts" do
734
+ result = Braintree::Subscription.create(
735
+ :payment_method_token => @credit_card.token,
736
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id]
737
+ )
738
+ result.success?.should == true
739
+ subscription = result.subscription
740
+
741
+ result = Braintree::Subscription.update(
742
+ subscription.id,
743
+ :add_ons => {
744
+ :update => [
745
+ {
746
+ :existing_id => subscription.add_ons.first.id,
747
+ :amount => BigDecimal.new("99.99"),
748
+ :quantity => 12
749
+ }
750
+ ]
751
+ },
752
+ :discounts => {
753
+ :update => [
754
+ {
755
+ :existing_id => subscription.discounts.first.id,
756
+ :amount => BigDecimal.new("88.88"),
757
+ :quantity => 9
758
+ }
759
+ ]
760
+ }
761
+ )
762
+
763
+ subscription = result.subscription
764
+
765
+ subscription.add_ons.size.should == 2
766
+ add_ons = subscription.add_ons.sort_by { |add_on| add_on.id }
767
+
768
+ add_ons.first.amount.should == BigDecimal.new("99.99")
769
+ add_ons.first.quantity.should == 12
770
+
771
+ subscription.discounts.size.should == 2
772
+ discounts = subscription.discounts.sort_by { |discount| discount.id }
773
+
774
+ discounts.last.amount.should == BigDecimal.new("88.88")
775
+ discounts.last.quantity.should == 9
776
+ end
777
+
778
+ it "allows adding new add_ons and discounts" do
779
+ subscription = Braintree::Subscription.create(
780
+ :payment_method_token => @credit_card.token,
781
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id]
782
+ ).subscription
783
+
784
+ result = Braintree::Subscription.update(subscription.id,
785
+ :add_ons => {
786
+ :add => [{:inherited_from_id => SpecHelper::AddOnIncrease30}]
787
+ },
788
+ :discounts => {
789
+ :add => [{:inherited_from_id => SpecHelper::Discount15}]
790
+ }
791
+ )
792
+
793
+ result.success?.should == true
794
+ subscription = result.subscription
795
+
796
+ subscription.add_ons.size.should == 3
797
+ add_ons = subscription.add_ons.sort_by { |add_on| add_on.id }
798
+
799
+ add_ons[0].id.should == "increase_10"
800
+ add_ons[0].amount.should == BigDecimal.new("10.00")
801
+ add_ons[0].quantity.should == 1
802
+
803
+ add_ons[1].id.should == "increase_20"
804
+ add_ons[1].amount.should == BigDecimal.new("20.00")
805
+ add_ons[1].quantity.should == 1
806
+
807
+ add_ons[2].id.should == "increase_30"
808
+ add_ons[2].amount.should == BigDecimal.new("30.00")
809
+ add_ons[2].quantity.should == 1
810
+
811
+ subscription.discounts.size.should == 3
812
+ discounts = subscription.discounts.sort_by { |discount| discount.id }
813
+
814
+ discounts[0].id.should == "discount_11"
815
+ discounts[0].amount.should == BigDecimal.new("11.00")
816
+ discounts[0].quantity.should == 1
817
+
818
+ discounts[1].id.should == "discount_15"
819
+ discounts[1].amount.should == BigDecimal.new("15.00")
820
+ discounts[1].quantity.should == 1
821
+
822
+ discounts[2].id.should == "discount_7"
823
+ discounts[2].amount.should == BigDecimal.new("7.00")
824
+ discounts[2].quantity.should == 1
825
+ end
826
+
827
+ it "allows replacing entire set of add_ons and discounts" do
828
+ subscription = Braintree::Subscription.create(
829
+ :payment_method_token => @credit_card.token,
830
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id]
831
+ ).subscription
832
+
833
+ result = Braintree::Subscription.update(subscription.id,
834
+ :add_ons => {
835
+ :add => [{:inherited_from_id => SpecHelper::AddOnIncrease30}]
836
+ },
837
+ :discounts => {
838
+ :add => [{:inherited_from_id => SpecHelper::Discount15}]
839
+ },
840
+ :options => {:replace_all_add_ons_and_discounts => true}
841
+ )
842
+
843
+ result.success?.should == true
844
+ subscription = result.subscription
845
+
846
+ subscription.add_ons.size.should == 1
847
+
848
+ subscription.add_ons[0].amount.should == BigDecimal.new("30.00")
849
+ subscription.add_ons[0].quantity.should == 1
850
+
851
+ subscription.discounts.size.should == 1
852
+
853
+ subscription.discounts[0].amount.should == BigDecimal.new("15.00")
854
+ subscription.discounts[0].quantity.should == 1
855
+ end
856
+
857
+ it "allows deleting of add_ons and discounts" do
858
+ subscription = Braintree::Subscription.create(
859
+ :payment_method_token => @credit_card.token,
860
+ :plan_id => SpecHelper::AddOnDiscountPlan[:id]
861
+ ).subscription
862
+
863
+ result = Braintree::Subscription.update(subscription.id,
864
+ :add_ons => {
865
+ :remove => [SpecHelper::AddOnIncrease10]
866
+ },
867
+ :discounts => {
868
+ :remove => [SpecHelper::Discount7]
869
+ }
870
+ )
871
+ result.success?.should == true
872
+
873
+ subscription = result.subscription
874
+
875
+ subscription.add_ons.size.should == 1
876
+ subscription.add_ons.first.amount.should == BigDecimal.new("20.00")
877
+ subscription.add_ons.first.quantity.should == 1
878
+
879
+ subscription.discounts.size.should == 1
880
+ subscription.discounts.last.amount.should == BigDecimal.new("11.00")
881
+ subscription.discounts.last.quantity.should == 1
882
+ end
883
+ end
884
+ end
401
885
 
402
886
  describe "self.cancel" do
403
887
  it "returns a success response with the updated subscription if valid" do
404
888
  subscription = Braintree::Subscription.create(
405
889
  :payment_method_token => @credit_card.token,
406
890
  :price => 54.32,
407
- :plan_id => TriallessPlan[:id]
891
+ :plan_id => SpecHelper::TriallessPlan[:id]
408
892
  ).subscription
409
893
 
410
894
  result = Braintree::Subscription.cancel(subscription.id)
@@ -422,7 +906,7 @@ describe Braintree::Subscription do
422
906
  subscription = Braintree::Subscription.create(
423
907
  :payment_method_token => @credit_card.token,
424
908
  :price => 54.32,
425
- :plan_id => TriallessPlan[:id]
909
+ :plan_id => SpecHelper::TriallessPlan[:id]
426
910
  ).subscription
427
911
 
428
912
  result = Braintree::Subscription.cancel(subscription.id)
@@ -436,212 +920,190 @@ describe Braintree::Subscription do
436
920
  end
437
921
 
438
922
  describe "self.search" do
439
- context "search_fields" do
440
- it "correctly returns a result with no matches" do
923
+ describe "id" do
924
+ it "works using the is operator" do
925
+ id = rand(36**8).to_s(36)
926
+ subscription1 = Braintree::Subscription.create(
927
+ :payment_method_token => @credit_card.token,
928
+ :plan_id => SpecHelper::TrialPlan[:id],
929
+ :id => "subscription1_#{id}"
930
+ ).subscription
931
+
932
+ subscription2 = Braintree::Subscription.create(
933
+ :payment_method_token => @credit_card.token,
934
+ :plan_id => SpecHelper::TrialPlan[:id],
935
+ :id => "subscription2_#{id}"
936
+ ).subscription
937
+
441
938
  collection = Braintree::Subscription.search do |search|
442
- search.plan_id.is "not_a_real_plan_id"
939
+ search.id.is "subscription1_#{id}"
443
940
  end
444
941
 
445
- collection.maximum_size.should == 0
942
+ collection.should include(subscription1)
943
+ collection.should_not include(subscription2)
446
944
  end
945
+ end
447
946
 
448
- context "is statement" do
449
- it "returns resource collection with matching results" do
450
- trialless_subscription = Braintree::Subscription.create(
451
- :payment_method_token => @credit_card.token,
452
- :plan_id => TriallessPlan[:id]
453
- ).subscription
454
-
455
- trial_subscription = Braintree::Subscription.create(
456
- :payment_method_token => @credit_card.token,
457
- :plan_id => TrialPlan[:id]
458
- ).subscription
947
+ describe "merchant_account_id" do
948
+ it "is searchable using the is or in operator" do
949
+ subscription1 = Braintree::Subscription.create(
950
+ :payment_method_token => @credit_card.token,
951
+ :plan_id => SpecHelper::TrialPlan[:id],
952
+ :merchant_account_id => SpecHelper::DefaultMerchantAccountId,
953
+ :price => "1"
954
+ ).subscription
459
955
 
460
- collection = Braintree::Subscription.search do |search|
461
- search.plan_id.is TriallessPlan[:id]
462
- end
956
+ subscription2 = Braintree::Subscription.create(
957
+ :payment_method_token => @credit_card.token,
958
+ :plan_id => SpecHelper::TrialPlan[:id],
959
+ :merchant_account_id => SpecHelper::NonDefaultMerchantAccountId,
960
+ :price => "1"
961
+ ).subscription
463
962
 
464
- collection.should include(trialless_subscription)
465
- collection.should_not include(trial_subscription)
963
+ collection = Braintree::Subscription.search do |search|
964
+ search.merchant_account_id.is SpecHelper::DefaultMerchantAccountId
965
+ search.price.is "1"
466
966
  end
467
- end
468
967
 
469
- context "is_not statement" do
470
- it "returns resource collection without matching results" do
471
- trialless_subscription = Braintree::Subscription.create(
472
- :payment_method_token => @credit_card.token,
473
- :plan_id => TriallessPlan[:id]
474
- ).subscription
968
+ collection.should include(subscription1)
969
+ collection.should_not include(subscription2)
475
970
 
476
- trial_subscription = Braintree::Subscription.create(
477
- :payment_method_token => @credit_card.token,
478
- :plan_id => TrialPlan[:id]
479
- ).subscription
480
-
481
- collection = Braintree::Subscription.search do |search|
482
- search.plan_id.is_not TriallessPlan[:id]
483
- end
484
-
485
- collection.should_not include(trialless_subscription)
486
- collection.should include(trial_subscription)
971
+ collection = Braintree::Subscription.search do |search|
972
+ search.merchant_account_id.in [SpecHelper::DefaultMerchantAccountId, SpecHelper::NonDefaultMerchantAccountId]
973
+ search.price.is "1"
487
974
  end
488
- end
489
-
490
- context "ends_with statement" do
491
- it "returns resource collection with matching results" do
492
- trialless_subscription = Braintree::Subscription.create(
493
- :payment_method_token => @credit_card.token,
494
- :plan_id => TriallessPlan[:id]
495
- ).subscription
496
-
497
- trial_subscription = Braintree::Subscription.create(
498
- :payment_method_token => @credit_card.token,
499
- :plan_id => TrialPlan[:id]
500
- ).subscription
501
975
 
502
- collection = Braintree::Subscription.search do |search|
503
- search.plan_id.ends_with "trial_plan"
504
- end
505
-
506
- collection.should include(trial_subscription)
507
- collection.should_not include(trialless_subscription)
508
- end
976
+ collection.should include(subscription1)
977
+ collection.should include(subscription2)
509
978
  end
979
+ end
510
980
 
511
- context "starts_with statement" do
512
- it "returns resource collection with matching results" do
513
- trialless_subscription = Braintree::Subscription.create(
514
- :payment_method_token => @credit_card.token,
515
- :plan_id => TriallessPlan[:id]
516
- ).subscription
517
-
518
- trial_subscription = Braintree::Subscription.create(
519
- :payment_method_token => @credit_card.token,
520
- :plan_id => TrialPlan[:id]
521
- ).subscription
981
+ describe "plan_id" do
982
+ it "works using the is operator" do
983
+ trialless_subscription = Braintree::Subscription.create(
984
+ :payment_method_token => @credit_card.token,
985
+ :plan_id => SpecHelper::TriallessPlan[:id],
986
+ :price => "2"
987
+ ).subscription
522
988
 
523
- collection = Braintree::Subscription.search do |search|
524
- search.plan_id.starts_with "integration_trial_p"
525
- end
989
+ trial_subscription = Braintree::Subscription.create(
990
+ :payment_method_token => @credit_card.token,
991
+ :plan_id => SpecHelper::TrialPlan[:id],
992
+ :price => "2"
993
+ ).subscription
526
994
 
527
- collection.should include(trial_subscription)
528
- collection.should_not include(trialless_subscription)
995
+ collection = Braintree::Subscription.search do |search|
996
+ search.plan_id.is SpecHelper::TriallessPlan[:id]
997
+ search.price.is "2"
529
998
  end
530
- end
531
-
532
- context "contains statement" do
533
- it "returns resource collection with matching results" do
534
- trialless_subscription = Braintree::Subscription.create(
535
- :payment_method_token => @credit_card.token,
536
- :plan_id => TriallessPlan[:id]
537
- ).subscription
538
-
539
- trial_subscription = Braintree::Subscription.create(
540
- :payment_method_token => @credit_card.token,
541
- :plan_id => TrialPlan[:id]
542
- ).subscription
543
999
 
544
- collection = Braintree::Subscription.search do |search|
545
- search.plan_id.contains "trial_p"
546
- end
547
-
548
- collection.should include(trial_subscription)
549
- collection.should_not include(trialless_subscription)
550
- end
1000
+ collection.should include(trialless_subscription)
1001
+ collection.should_not include(trial_subscription)
551
1002
  end
552
1003
  end
553
1004
 
554
- context "multiple_value_fields" do
555
- context "in" do
556
- it "matches all values if none are specified" do
557
- subscription1 = Braintree::Subscription.create(
558
- :payment_method_token => @credit_card.token,
559
- :plan_id => TriallessPlan[:id]
560
- ).subscription
561
-
562
- subscription2 = Braintree::Subscription.create(
563
- :payment_method_token => @credit_card.token,
564
- :plan_id => TriallessPlan[:id]
565
- ).subscription
566
-
567
- Braintree::Subscription.cancel(subscription2.id)
1005
+ describe "price" do
1006
+ it "works using the is operator" do
1007
+ subscription_500 = Braintree::Subscription.create(
1008
+ :payment_method_token => @credit_card.token,
1009
+ :plan_id => SpecHelper::TrialPlan[:id],
1010
+ :price => "5.00"
1011
+ ).subscription
568
1012
 
569
- collection = Braintree::Subscription.search do |search|
570
- search.plan_id.is TriallessPlan[:id]
571
- end
1013
+ subscription_501 = Braintree::Subscription.create(
1014
+ :payment_method_token => @credit_card.token,
1015
+ :plan_id => SpecHelper::TrialPlan[:id],
1016
+ :price => "5.01"
1017
+ ).subscription
572
1018
 
573
- collection.should include(subscription1)
574
- collection.should include(subscription2)
1019
+ collection = Braintree::Subscription.search do |search|
1020
+ search.price.is "5.00"
575
1021
  end
576
1022
 
577
- it "returns only matching results" do
578
- subscription1 = Braintree::Subscription.create(
579
- :payment_method_token => @credit_card.token,
580
- :plan_id => TriallessPlan[:id]
581
- ).subscription
1023
+ collection.should include(subscription_500)
1024
+ collection.should_not include(subscription_501)
1025
+ end
1026
+ end
582
1027
 
583
- subscription2 = Braintree::Subscription.create(
584
- :payment_method_token => @credit_card.token,
585
- :plan_id => TriallessPlan[:id]
586
- ).subscription
1028
+ describe "days_past_due" do
1029
+ it "is backwards-compatible for 'is'" do
1030
+ active_subscription = Braintree::Subscription.create(
1031
+ :payment_method_token => @credit_card.token,
1032
+ :plan_id => SpecHelper::TrialPlan[:id],
1033
+ :price => "6"
1034
+ ).subscription
587
1035
 
588
- Braintree::Subscription.cancel(subscription2.id)
1036
+ past_due_subscription = Braintree::Subscription.create(
1037
+ :payment_method_token => @credit_card.token,
1038
+ :plan_id => SpecHelper::TrialPlan[:id],
1039
+ :price => "6"
1040
+ ).subscription
589
1041
 
590
- collection = Braintree::Subscription.search do |search|
591
- search.status.in Braintree::Subscription::Status::Active
592
- end
1042
+ SpecHelper.make_past_due(past_due_subscription, 5)
593
1043
 
594
- collection.should include(subscription1)
595
- collection.should_not include(subscription2)
1044
+ collection = Braintree::Subscription.search do |search|
1045
+ search.price.is "6.00"
1046
+ search.days_past_due.is 5
596
1047
  end
597
1048
 
598
- it "returns only matching results given an argument list" do
599
- subscription1 = Braintree::Subscription.create(
600
- :payment_method_token => @credit_card.token,
601
- :plan_id => TriallessPlan[:id]
602
- ).subscription
603
-
604
- subscription2 = Braintree::Subscription.create(
605
- :payment_method_token => @credit_card.token,
606
- :plan_id => TriallessPlan[:id]
607
- ).subscription
608
-
609
- Braintree::Subscription.cancel(subscription2.id)
1049
+ collection.should include(past_due_subscription)
1050
+ collection.should_not include(active_subscription)
1051
+ collection.each do |s|
1052
+ s.status.should == Braintree::Subscription::Status::PastDue
1053
+ end
1054
+ end
610
1055
 
611
- collection = Braintree::Subscription.search do |search|
612
- search.status.in Braintree::Subscription::Status::Active, Braintree::Subscription::Status::Canceled
613
- end
1056
+ it "passes a smoke test" do
1057
+ subscription = Braintree::Subscription.create(
1058
+ :payment_method_token => @credit_card.token,
1059
+ :plan_id => SpecHelper::TrialPlan[:id]
1060
+ ).subscription
614
1061
 
615
- collection.should include(subscription1)
616
- collection.should include(subscription2)
1062
+ collection = Braintree::Subscription.search do |search|
1063
+ search.days_past_due.between 1, 20
617
1064
  end
618
1065
 
619
- it "returns only matching results given an array" do
620
- subscription1 = Braintree::Subscription.create(
621
- :payment_method_token => @credit_card.token,
622
- :plan_id => TriallessPlan[:id]
623
- ).subscription
1066
+ collection.should_not include(subscription)
1067
+ collection.each do |s|
1068
+ s.days_past_due.should >= 1
1069
+ s.days_past_due.should <= 20
1070
+ end
1071
+ end
1072
+ end
624
1073
 
625
- subscription2 = Braintree::Subscription.create(
626
- :payment_method_token => @credit_card.token,
627
- :plan_id => TriallessPlan[:id]
628
- ).subscription
1074
+ describe "billing_cycles_remaining" do
1075
+ it "passes a smoke test" do
1076
+ subscription_5 = Braintree::Subscription.create(
1077
+ :payment_method_token => @credit_card.token,
1078
+ :plan_id => SpecHelper::TrialPlan[:id],
1079
+ :number_of_billing_cycles => 5
1080
+ ).subscription
629
1081
 
630
- Braintree::Subscription.cancel(subscription2.id)
1082
+ subscription_9 = Braintree::Subscription.create(
1083
+ :payment_method_token => @credit_card.token,
1084
+ :plan_id => SpecHelper::TriallessPlan[:id],
1085
+ :number_of_billing_cycles => 10
1086
+ ).subscription
631
1087
 
632
- collection = Braintree::Subscription.search do |search|
633
- search.status.in [Braintree::Subscription::Status::Active, Braintree::Subscription::Status::Canceled]
634
- end
1088
+ subscription_15 = Braintree::Subscription.create(
1089
+ :payment_method_token => @credit_card.token,
1090
+ :plan_id => SpecHelper::TriallessPlan[:id],
1091
+ :number_of_billing_cycles => 15
1092
+ ).subscription
635
1093
 
636
- collection.should include(subscription1)
637
- collection.should include(subscription2)
1094
+ collection = Braintree::Subscription.search do |search|
1095
+ search.billing_cycles_remaining.between 5, 10
638
1096
  end
1097
+
1098
+ collection.should include(subscription_5)
1099
+ collection.should include(subscription_9)
1100
+ collection.should_not include(subscription_15)
639
1101
  end
640
1102
  end
641
1103
 
642
1104
  it "returns multiple results" do
643
1105
  (110 - Braintree::Subscription.search.maximum_size).times do
644
- Braintree::Subscription.create(:payment_method_token => @credit_card.token, :plan_id => TriallessPlan[:id])
1106
+ Braintree::Subscription.create(:payment_method_token => @credit_card.token, :plan_id => SpecHelper::TrialPlan[:id])
645
1107
  end
646
1108
 
647
1109
  collection = Braintree::Subscription.search
@@ -650,14 +1112,15 @@ describe Braintree::Subscription do
650
1112
  subscriptions_ids = collection.map {|t| t.id }.uniq.compact
651
1113
  subscriptions_ids.size.should == collection.maximum_size
652
1114
  end
653
-
654
1115
  end
655
1116
 
656
1117
  describe "self.retry_charge" do
657
1118
  it "is successful with only subscription id" do
658
- subscription = Braintree::Subscription.search do |search|
659
- search.status.in Braintree::Subscription::Status::PastDue
660
- end.first
1119
+ subscription = Braintree::Subscription.create(
1120
+ :payment_method_token => @credit_card.token,
1121
+ :plan_id => SpecHelper::TriallessPlan[:id]
1122
+ ).subscription
1123
+ SpecHelper.make_past_due(subscription)
661
1124
 
662
1125
  result = Braintree::Subscription.retry_charge(subscription.id)
663
1126
 
@@ -671,9 +1134,11 @@ describe Braintree::Subscription do
671
1134
  end
672
1135
 
673
1136
  it "is successful with subscription id and amount" do
674
- subscription = Braintree::Subscription.search do |search|
675
- search.status.in Braintree::Subscription::Status::PastDue
676
- end.first
1137
+ subscription = Braintree::Subscription.create(
1138
+ :payment_method_token => @credit_card.token,
1139
+ :plan_id => SpecHelper::TriallessPlan[:id]
1140
+ ).subscription
1141
+ SpecHelper.make_past_due(subscription)
677
1142
 
678
1143
  result = Braintree::Subscription.retry_charge(subscription.id, Braintree::Test::TransactionAmounts::Authorize)
679
1144