freemium-ajb 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.md +20 -0
  9. data/README.md +1 -0
  10. data/app/mailers/freemium_mailer.rb +36 -0
  11. data/app/views/subscription_mailer/admin_report.text.erb +4 -0
  12. data/app/views/subscription_mailer/expiration_notice.text.erb +1 -0
  13. data/app/views/subscription_mailer/expiration_warning.text.erb +1 -0
  14. data/app/views/subscription_mailer/invoice.text.erb +5 -0
  15. data/freemium.gemspec +29 -0
  16. data/lib/freemium.rb +25 -0
  17. data/lib/freemium/configuration.rb +27 -0
  18. data/lib/freemium/coupon.rb +37 -0
  19. data/lib/freemium/coupon_redemption.rb +59 -0
  20. data/lib/freemium/credit_card.rb +222 -0
  21. data/lib/freemium/engine.rb +7 -0
  22. data/lib/freemium/gateways/base.rb +65 -0
  23. data/lib/freemium/gateways/brain_tree.rb +175 -0
  24. data/lib/freemium/gateways/test.rb +36 -0
  25. data/lib/freemium/rates.rb +33 -0
  26. data/lib/freemium/response.rb +24 -0
  27. data/lib/freemium/subscription.rb +384 -0
  28. data/lib/freemium/subscription_change.rb +20 -0
  29. data/lib/freemium/subscription_plan.rb +26 -0
  30. data/lib/freemium/testing/app/controllers/application_controller.rb +7 -0
  31. data/lib/freemium/testing/application.rb +46 -0
  32. data/lib/freemium/testing/config/database.yml +11 -0
  33. data/lib/freemium/testing/config/routes.rb +3 -0
  34. data/lib/freemium/transaction.rb +15 -0
  35. data/lib/freemium/version.rb +3 -0
  36. data/lib/generators/freemium/install/install_generator.rb +58 -0
  37. data/lib/generators/freemium/install/templates/db/migrate/create_coupon_redemptions.rb +18 -0
  38. data/lib/generators/freemium/install/templates/db/migrate/create_coupons.rb +28 -0
  39. data/lib/generators/freemium/install/templates/db/migrate/create_credit_cards.rb +14 -0
  40. data/lib/generators/freemium/install/templates/db/migrate/create_subscription_changes.rb +21 -0
  41. data/lib/generators/freemium/install/templates/db/migrate/create_subscription_plans.rb +14 -0
  42. data/lib/generators/freemium/install/templates/db/migrate/create_subscriptions.rb +31 -0
  43. data/lib/generators/freemium/install/templates/db/migrate/create_transactions.rb +17 -0
  44. data/lib/generators/freemium/install/templates/freemium.rb +16 -0
  45. data/lib/generators/freemium/install/templates/models/coupon.rb +3 -0
  46. data/lib/generators/freemium/install/templates/models/coupon_redemption.rb +3 -0
  47. data/lib/generators/freemium/install/templates/models/credit_card.rb +3 -0
  48. data/lib/generators/freemium/install/templates/models/subscription.rb +3 -0
  49. data/lib/generators/freemium/install/templates/models/subscription_change.rb +3 -0
  50. data/lib/generators/freemium/install/templates/models/subscription_plan.rb +3 -0
  51. data/lib/generators/freemium/install/templates/models/transaction.rb +3 -0
  52. data/lib/generators/views/USAGE +3 -0
  53. data/lib/generators/views/views_generator.rb +39 -0
  54. data/lib/tasks/freemium.rake +17 -0
  55. data/spec/dummy/Rakefile +7 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  57. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  58. data/spec/dummy/app/mailers/mailers.rb +1 -0
  59. data/spec/dummy/app/models/models.rb +31 -0
  60. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  61. data/spec/dummy/config.ru +4 -0
  62. data/spec/dummy/config/application.rb +45 -0
  63. data/spec/dummy/config/boot.rb +10 -0
  64. data/spec/dummy/config/database.yml +21 -0
  65. data/spec/dummy/config/environment.rb +6 -0
  66. data/spec/dummy/config/environments/development.rb +26 -0
  67. data/spec/dummy/config/environments/production.rb +49 -0
  68. data/spec/dummy/config/environments/test.rb +36 -0
  69. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  70. data/spec/dummy/config/initializers/freemium.rb +16 -0
  71. data/spec/dummy/config/initializers/inflections.rb +10 -0
  72. data/spec/dummy/config/initializers/mem_db.rb +12 -0
  73. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  74. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  75. data/spec/dummy/config/initializers/session_store.rb +8 -0
  76. data/spec/dummy/config/locales/en.yml +5 -0
  77. data/spec/dummy/config/routes.rb +58 -0
  78. data/spec/dummy/db/schema.rb +90 -0
  79. data/spec/dummy/script/rails +6 -0
  80. data/spec/fixtures/credit_cards.yml +11 -0
  81. data/spec/fixtures/subscription_plans.yml +15 -0
  82. data/spec/fixtures/subscriptions.yml +28 -0
  83. data/spec/fixtures/users.yml +16 -0
  84. data/spec/lib/tasks/run_billing_rake_spec.rb +14 -0
  85. data/spec/models/coupon_redemption_spec.rb +287 -0
  86. data/spec/models/credit_card_spec.rb +124 -0
  87. data/spec/models/manual_billing_spec.rb +165 -0
  88. data/spec/models/subscription_plan_spec.rb +46 -0
  89. data/spec/models/subscription_spec.rb +386 -0
  90. data/spec/spec_helper.rb +19 -0
  91. data/spec/support/helpers.rb +18 -0
  92. data/spec/support/shared_contexts/rake.rb +19 -0
  93. metadata +270 -0
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,11 @@
1
+ bobs_credit_card:
2
+ id: 1
3
+ expiration_date: <%= (Time.now + 3.years).to_s :db %>
4
+ display_number: xxxx-xxxx-xxxx-2222
5
+ card_type: master
6
+ steves_credit_card:
7
+ id: 2
8
+ expiration_date: <%= (Time.now + 3.years).to_s :db %>
9
+ display_number: xxxx-xxxx-xxxx-1111
10
+ card_type: visa
11
+
@@ -0,0 +1,15 @@
1
+ free:
2
+ id: 1
3
+ key: free
4
+ name: Free Access
5
+ rate_cents: 0
6
+ basic:
7
+ id: 2
8
+ key: basic
9
+ name: Basic
10
+ rate_cents: 1295
11
+ premium:
12
+ id: 3
13
+ key: premium
14
+ name: Premium
15
+ rate_cents: 2495
@@ -0,0 +1,28 @@
1
+ bobs_subscription:
2
+ id: 1
3
+ subscribable_id: 1
4
+ subscribable_type: User
5
+ subscription_plan_id: 2
6
+ credit_card_id: 1
7
+ paid_through: <%= (Date.today + 20).to_s :db %>
8
+ billing_key: tc00001
9
+ started_on: <%= (Date.today - 60).to_s :db %>
10
+ last_transaction_at: 2007-09-15 12:34:56
11
+ sues_subscription:
12
+ id: 2
13
+ subscribable_id: 2
14
+ subscribable_type: User
15
+ subscription_plan_id: 1
16
+ paid_through:
17
+ last_transaction_at:
18
+ started_on: <%= (Date.today - 60).to_s :db %>
19
+ steves_subscription:
20
+ id: 3
21
+ subscribable_id: 4
22
+ subscribable_type: User
23
+ subscription_plan_id: 3
24
+ credit_card_id: 1
25
+ paid_through: <%= (Date.today + 20).to_s :db %>
26
+ billing_key: tc00002
27
+ started_on: <%= (Date.today - 60).to_s :db %>
28
+ last_transaction_at: 2007-09-15 12:34:56
@@ -0,0 +1,16 @@
1
+ bob:
2
+ id: 1
3
+ name: Bob
4
+ email: bob@example.com
5
+ sue:
6
+ id: 2
7
+ name: Sue
8
+ email: sue@example.com
9
+ sally:
10
+ id: 3
11
+ name: Sally
12
+ email: sally@example.com
13
+ steve:
14
+ id: 4
15
+ name: Steve
16
+ email: steve@example.com
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe "freemium:run_billing" do
4
+ include_context "rake"
5
+
6
+ before do
7
+ end
8
+
9
+ # its(:prerequisites) { should include("environment") }
10
+
11
+ it "generates a registrations report" do
12
+ subject.invoke
13
+ end
14
+ end
@@ -0,0 +1,287 @@
1
+ require 'spec_helper'
2
+
3
+ describe CouponRedemption do
4
+ fixtures :users, :subscriptions, :subscription_plans, :credit_cards
5
+
6
+ before(:each) do
7
+ @subscription = subscriptions(:bobs_subscription)
8
+ @original_price = @subscription.rate
9
+ @coupon = Coupon.create(:description => "30% off", :discount_percentage => 30, :redemption_key => "30OFF")
10
+ end
11
+
12
+ it "should be applied" do
13
+ @subscription.paid_through = Date.today + 30
14
+ @original_remaining_value = @subscription.remaining_value
15
+ @original_daily_rate = @subscription.daily_rate
16
+ @subscription.coupon_key = nil
17
+
18
+ @subscription.coupon_redemptions.create(:coupon => @coupon).should be_true
19
+ @subscription.rate.cents.should eql(@coupon.discount(@original_price).cents)
20
+ @subscription.daily_rate.cents.should eql(@coupon.discount(@original_daily_rate).cents)
21
+ @subscription.remaining_value.cents.should eql((@coupon.discount(@original_daily_rate) * @subscription.remaining_days).cents)
22
+ end
23
+
24
+ it "should be applied using coupon accessor" do
25
+ @subscription = build_subscription(:coupon => @coupon, :credit_card => CreditCard.sample)
26
+ @subscription.save!
27
+
28
+ @subscription.coupon.should_not be_nil
29
+ @subscription.coupon_redemptions.first.coupon.should_not be_nil
30
+ @subscription.coupon_redemptions.first.subscription.should_not be_nil
31
+ @subscription.coupon_redemptions.empty?.should be_false
32
+ @subscription.rate.cents.should eql(@coupon.discount(@subscription.subscription_plan.rate).cents)
33
+ end
34
+
35
+ it "should be applied using coupon key accessor" do
36
+ @subscription = build_subscription(:coupon_key => @coupon.redemption_key, :credit_card => CreditCard.sample)
37
+ @subscription.save!
38
+
39
+ @subscription.coupon.should_not be_nil
40
+ @subscription.coupon_redemptions.first.coupon.should_not be_nil
41
+ @subscription.coupon_redemptions.first.subscription.should_not be_nil
42
+ @subscription.coupon_redemptions.empty?.should be_false
43
+ @subscription.rate.cents.should eql(@coupon.discount(@subscription.subscription_plan.rate).cents)
44
+ end
45
+
46
+ it "should be applied multiple" do
47
+ @coupon_1 = Coupon.new(:description => "10% off", :discount_percentage => 10)
48
+ @subscription.coupon_redemptions.create(:coupon => @coupon_1).should be_true
49
+
50
+ @coupon_2 = Coupon.new(:description => "30% off", :discount_percentage => 30)
51
+ @subscription.coupon_redemptions.create(:coupon => @coupon_2).should be_true
52
+
53
+ @coupon_3 = Coupon.new(:description => "20% off", :discount_percentage => 20)
54
+ @subscription.coupon_redemptions.create(:coupon => @coupon_3).should be_true
55
+
56
+ # Should use the highest discounted coupon
57
+ @subscription.rate.cents.should eql(@coupon_2.discount(@original_price).cents)
58
+ end
59
+
60
+ it "should be destroyed" do
61
+ @subscription.coupon_redemptions.create(:coupon => @coupon).should be_true
62
+ @subscription.rate.cents.should eql(@coupon.discount(@original_price).cents)
63
+
64
+ @coupon.destroy
65
+ @subscription.reload
66
+
67
+ @subscription.coupon_redemptions.empty?.should be_true
68
+ @subscription.rate.cents.should eql(@original_price.cents)
69
+ end
70
+
71
+ it "should test coupon duration" do
72
+ @subscription.coupon_redemptions.create(:coupon => @coupon).should be_true
73
+ @subscription.rate.cents.should eql(@coupon.discount(@original_price).cents)
74
+
75
+ @coupon.duration_in_months = 3
76
+ @coupon.save!
77
+
78
+ @subscription.rate({:date => (Date.today + 3.months - 1)}).cents.should eql(@coupon.discount(@original_price).cents)
79
+ @subscription.rate({:date => (Date.today + 3.months + 1)}).cents.should eql(@original_price.cents)
80
+
81
+ safe_date = Date.today + 3.months - 1
82
+ Date.stub!(:today => safe_date)
83
+ @subscription.rate.cents.should eql(@coupon.discount(@original_price).cents)
84
+
85
+ safe_date = Date.today + 1
86
+ Date.stub!(:today => safe_date)
87
+ @subscription.rate.cents.should eql(@coupon.discount(@original_price).cents)
88
+
89
+ safe_date = Date.today + 1
90
+ Date.stub!(:today => safe_date)
91
+ @subscription.rate.cents.should eql(@original_price.cents)
92
+ end
93
+
94
+ it "should be applied complimentary" do
95
+ @coupon.discount_percentage = 100
96
+
97
+ @subscription = build_subscription(:coupon => @coupon, :credit_card => CreditCard.sample, :subscription_plan => subscription_plans(:premium))
98
+
99
+ @subscription.save.should be_true
100
+ @subscription.coupon.should_not be_nil
101
+ @subscription.rate.cents.should eql(0)
102
+ @subscription.paid?.should be_false
103
+ end
104
+
105
+ ##
106
+ ## Plan-specific coupons
107
+ ##
108
+
109
+ it "should be applied only on new premium plan" do
110
+ set_coupon_to_premium_only
111
+
112
+ @subscription = build_subscription(:coupon => @coupon, :credit_card => CreditCard.sample,
113
+ :subscription_plan => subscription_plans(:premium))
114
+
115
+ @subscription.save.should be_true
116
+ @subscription.coupon.should_not be_nil
117
+
118
+ @subscription = build_subscription(:coupon => @coupon, :credit_card => CreditCard.sample,
119
+ :subscription_plan => subscription_plans(:basic))
120
+
121
+ @subscription.save.should be_false
122
+ @subscription.should have(1).errors_on(:coupon_redemptions)
123
+ end
124
+
125
+ it "should be applied only on existent premium plan" do
126
+ set_coupon_to_premium_only
127
+
128
+ @subscription.coupon = @coupon
129
+
130
+ @subscription.subscription_plan.should eql(subscription_plans(:basic))
131
+ @subscription.save.should be_false
132
+ @subscription.should have(1).errors_on(:coupon_redemptions)
133
+
134
+ @subscription.subscription_plan = subscription_plans(:premium)
135
+
136
+ @subscription.subscription_plan.should eql(subscription_plans(:premium))
137
+ @subscription.save.should be_true
138
+ @subscription.coupon.should_not be_nil
139
+ end
140
+
141
+ it "should automatically upgrade the plan, as long as discount percentage is 100%" do
142
+ hundred_coupon = Coupon.create(:description => "100% off", :discount_percentage => 100, :redemption_key => "100OFF")
143
+ hundred_coupon.subscription_plans << subscription_plans(:premium)
144
+
145
+ @subscription.coupon = hundred_coupon
146
+
147
+ @subscription.subscription_plan.should eql(subscription_plans(:premium))
148
+ @subscription.save.should be_true
149
+ @subscription.rate.cents.should eql(0)
150
+ end
151
+
152
+ it "should not automatically downgrade the plan, no matter what" do
153
+ @subscription.subscription_plan = subscription_plans(:premium)
154
+
155
+ hundred_coupon = Coupon.create(:description => "100% off", :discount_percentage => 100, :redemption_key => "100OFF")
156
+ hundred_coupon.subscription_plans << subscription_plans(:basic)
157
+
158
+ @subscription.coupon = hundred_coupon
159
+
160
+ @subscription.subscription_plan.should eql(subscription_plans(:premium))
161
+ @subscription.save.should be_false
162
+ @subscription.should have(1).errors_on(:coupon_redemptions)
163
+ end
164
+
165
+ it 'should remove the coupon when upgrading the subscription plan' do
166
+ @subscription.subscription_plan = subscription_plans(:free)
167
+
168
+ hundred_coupon = Coupon.create(:description => "100% off", :discount_percentage => 100, :redemption_key => "100OFF")
169
+ hundred_coupon.subscription_plans << subscription_plans(:basic)
170
+
171
+ @subscription.coupon = hundred_coupon
172
+
173
+ @subscription.subscription_plan.should eql(subscription_plans(:basic))
174
+ @subscription.save.should be_true
175
+ @subscription.rate.cents.should eql(0)
176
+
177
+ cc = CreditCard.sample
178
+ cc.save
179
+
180
+ @subscription.update_attributes(
181
+ subscription_plan_id: subscription_plans(:premium).id,
182
+ credit_card: cc
183
+ )
184
+
185
+ @subscription.reload
186
+
187
+ @subscription.credit_card.should eql(cc)
188
+ @subscription.rate.cents.should_not eql(0)
189
+ @subscription.paid_through.should_not eql(nil)
190
+ @subscription.coupon.should eql(nil)
191
+ end
192
+
193
+ ##
194
+ ## applying coupons
195
+ ##
196
+
197
+ it "should be applied to subscription" do
198
+ @subscription.coupon = @coupon
199
+ @subscription.should be_valid
200
+ @subscription.coupon.should_not be_nil
201
+ end
202
+
203
+ it "should validate coupon key" do
204
+ @subscription.coupon_key = @coupon.redemption_key + "xxxxx"
205
+
206
+ @subscription.should_not be_valid
207
+ @subscription.coupon.should be_nil
208
+ @subscription.should have(1).errors_on(:coupon)
209
+ end
210
+
211
+ it "should validate coupon by coupon plan" do
212
+ set_coupon_to_premium_only
213
+
214
+ @subscription.subscription_plan.should_not eql(subscription_plans(:premium))
215
+
216
+ @subscription.coupon = @coupon
217
+ @subscription.should_not be_valid
218
+ @subscription.should have(1).errors_on(:coupon_redemptions)
219
+ end
220
+
221
+ protected
222
+
223
+ def set_coupon_to_premium_only
224
+ @coupon.subscription_plans << subscription_plans(:premium)
225
+ @coupon.save!
226
+ end
227
+
228
+
229
+ public
230
+
231
+ ##
232
+ ## Validation Tests
233
+ ##
234
+
235
+ it "should validate coupon" do
236
+ s = CouponRedemption.new(:subscription => subscriptions(:bobs_subscription))
237
+ s.save.should be_false
238
+ s.should have(1).errors_on(:coupon)
239
+ end
240
+
241
+ it "should not be applied to unpaid subscription" do
242
+ subscriptions(:sues_subscription).paid?.should be_false
243
+ s = CouponRedemption.new(:subscription => subscriptions(:sues_subscription), :coupon => @coupon)
244
+ s.save.should be_false
245
+ s.should have(1).errors_on(:subscription)
246
+ end
247
+
248
+ it "should not be applied twice" do
249
+ s = CouponRedemption.new(:subscription => subscriptions(:bobs_subscription), :coupon => @coupon)
250
+ s.save.should be_true
251
+
252
+ s = CouponRedemption.new(:subscription => subscriptions(:bobs_subscription), :coupon => @coupon)
253
+ s.save.should be_false
254
+ s.should have(1).errors_on(:coupon_id)
255
+ end
256
+
257
+ it "should not be applied with redemption expired coupon" do
258
+ @coupon.redemption_expiration = Date.today-1
259
+ @coupon.save!
260
+
261
+ s = CouponRedemption.new(:subscription => subscriptions(:bobs_subscription), :coupon => @coupon)
262
+ s.save.should be_false
263
+ s.should have(1).errors_on(:coupon)
264
+ end
265
+
266
+ it "should not be applied with too many redemptions" do
267
+ @coupon.redemption_limit = 1
268
+ @coupon.save!
269
+
270
+ s = CouponRedemption.new(:subscription => subscriptions(:bobs_subscription), :coupon => @coupon)
271
+ s.save!
272
+
273
+ s = CouponRedemption.new(:subscription => subscriptions(:steves_subscription), :coupon => @coupon)
274
+ s.save.should be_false
275
+ s.should have(1).errors_on(:coupon)
276
+ end
277
+
278
+ protected
279
+
280
+ def build_subscription(options = {})
281
+ Subscription.new({
282
+ :subscription_plan => subscription_plans(:basic),
283
+ :subscribable => users(:sue)
284
+ }.merge(options))
285
+ end
286
+
287
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe CreditCard do
4
+ fixtures :users, :subscriptions, :subscription_plans, :credit_cards
5
+
6
+ before(:each) do
7
+ @subscription = Subscription.new(:subscription_plan => subscription_plans(:premium), :subscribable => users(:sally))
8
+ @credit_card = CreditCard.create(CreditCard.sample_params.merge(:subscription => @subscription))
9
+ Freemium.configuration.gateway = Freemium::Gateways::Test.new
10
+ Freemium.configuration.gateway.username = 'demo'
11
+ Freemium.configuration.gateway.password = 'password'
12
+
13
+ Freemium.configuration.gateway.stub!(:validate => Freemium::Response.new(true))
14
+ end
15
+
16
+ it "should create" do
17
+ @subscription.credit_card = @credit_card
18
+
19
+ @subscription.save.should be_true
20
+ @subscription = Subscription.find(@subscription.id)
21
+ @subscription.billing_key.should_not be_nil
22
+ @subscription.credit_card.display_number.should_not be_nil
23
+ @subscription.credit_card.card_type.should_not be_nil
24
+ @subscription.credit_card.expiration_date.should_not be_nil
25
+ end
26
+
27
+ it "should be created with billing validation failure" do
28
+ response = Freemium::Response.new(false, 'responsetext' => 'FAILED')
29
+ response.message = 'FAILED'
30
+ Freemium.configuration.gateway.stub!(:validate => response)
31
+
32
+ @subscription.credit_card = @credit_card
33
+
34
+ @subscription.save.should be_false
35
+ @subscription.should have(1).errors_on(:base)
36
+ end
37
+
38
+ it "should be updated" do
39
+ @subscription.credit_card = @credit_card
40
+
41
+ @subscription.save.should be_true
42
+ @subscription = Subscription.find(@subscription.id)
43
+ @subscription.billing_key.should_not be_nil
44
+
45
+ original_key = @subscription.billing_key
46
+ original_expiration = @subscription.credit_card.expiration_date
47
+
48
+ @subscription.credit_card = CreditCard.new(CreditCard.sample_params.merge(:zip_code => 95060, :number => "5431111111111111", :card_type => "master", :year => 2020))
49
+ @subscription.save.should be_true
50
+ @subscription = Subscription.find(@subscription.id)
51
+ @subscription.billing_key.should eql(original_key)
52
+ original_expiration.should < @subscription.credit_card.expiration_date
53
+ @subscription.credit_card.reload.zip_code.should eql("95060")
54
+ end
55
+
56
+ ##
57
+ ## Test Validations
58
+ ##
59
+
60
+ it "should validate card number" do
61
+ @credit_card.number = "foo"
62
+ @credit_card.should_not be_valid
63
+ @credit_card.save.should be_false
64
+ end
65
+
66
+ it "should validate expiration date of card" do
67
+ @credit_card.year = 2001
68
+ @credit_card.should_not be_valid
69
+ @credit_card.save.should be_false
70
+ end
71
+
72
+ it "should be changed" do
73
+ # We're overriding AR#changed? to include instance vars that aren't persisted to see if a new card is being set
74
+ @credit_card.changed?.should be_true #New card is changed
75
+ end
76
+
77
+ it "should be changed after reload" do
78
+ @credit_card.save!
79
+ @credit_card = CreditCard.find(@credit_card.id)
80
+ @credit_card.reload.changed?.should be_false #Saved card is NOT changed
81
+ end
82
+
83
+ it "should not be chanegd for existent card" do
84
+ credit_cards(:bobs_credit_card).changed?.should be_false
85
+ end
86
+
87
+ it "should be chnaged after update" do
88
+ credit_cards(:bobs_credit_card).number = "foo"
89
+ credit_cards(:bobs_credit_card).changed?.should be_true
90
+ end
91
+
92
+ it "should be valid" do
93
+ @credit_card.should be_valid #New card is valid
94
+ end
95
+
96
+ it "should be valid and unchanged for existent cards" do
97
+ # existing cards on file are valid ...
98
+ credit_cards(:bobs_credit_card).changed?.should be_false #Existing card has not changed
99
+ credit_cards(:bobs_credit_card).should be_valid #Existing card is valid
100
+ end
101
+
102
+ it "should validate number of existent card" do
103
+ # ... unless theres an attempt to update them
104
+ credit_cards(:bobs_credit_card).number = "foo"
105
+ credit_cards(:bobs_credit_card).should_not be_valid #Partially changed existing card is not valid
106
+ end
107
+
108
+ it "should validate card type of existent card" do
109
+ # ... unless theres an attempt to update them
110
+ credit_cards(:bobs_credit_card).card_type = "visa"
111
+ credit_cards(:bobs_credit_card).should_not be_valid #Partially changed existing card is not valid
112
+ end
113
+
114
+ it "should automatically determine card type" do
115
+ c = CreditCard.create(number: '4111111111111111', month: '2', year: '2013')
116
+ c.valid?
117
+ c.card_type.should eql(:visa)
118
+ end
119
+
120
+ it 'should not choke when there is no expiration date provided' do
121
+ c = CreditCard.new(number: '4111111111111111')
122
+ c.valid?.should eql(false)
123
+ end
124
+ end