freemium-ajb 0.0.4
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.
- data/.coveralls.yml +1 -0
- data/.gitignore +27 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.md +20 -0
- data/README.md +1 -0
- data/app/mailers/freemium_mailer.rb +36 -0
- data/app/views/subscription_mailer/admin_report.text.erb +4 -0
- data/app/views/subscription_mailer/expiration_notice.text.erb +1 -0
- data/app/views/subscription_mailer/expiration_warning.text.erb +1 -0
- data/app/views/subscription_mailer/invoice.text.erb +5 -0
- data/freemium.gemspec +29 -0
- data/lib/freemium.rb +25 -0
- data/lib/freemium/configuration.rb +27 -0
- data/lib/freemium/coupon.rb +37 -0
- data/lib/freemium/coupon_redemption.rb +59 -0
- data/lib/freemium/credit_card.rb +222 -0
- data/lib/freemium/engine.rb +7 -0
- data/lib/freemium/gateways/base.rb +65 -0
- data/lib/freemium/gateways/brain_tree.rb +175 -0
- data/lib/freemium/gateways/test.rb +36 -0
- data/lib/freemium/rates.rb +33 -0
- data/lib/freemium/response.rb +24 -0
- data/lib/freemium/subscription.rb +384 -0
- data/lib/freemium/subscription_change.rb +20 -0
- data/lib/freemium/subscription_plan.rb +26 -0
- data/lib/freemium/testing/app/controllers/application_controller.rb +7 -0
- data/lib/freemium/testing/application.rb +46 -0
- data/lib/freemium/testing/config/database.yml +11 -0
- data/lib/freemium/testing/config/routes.rb +3 -0
- data/lib/freemium/transaction.rb +15 -0
- data/lib/freemium/version.rb +3 -0
- data/lib/generators/freemium/install/install_generator.rb +58 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_coupon_redemptions.rb +18 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_coupons.rb +28 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_credit_cards.rb +14 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_subscription_changes.rb +21 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_subscription_plans.rb +14 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_subscriptions.rb +31 -0
- data/lib/generators/freemium/install/templates/db/migrate/create_transactions.rb +17 -0
- data/lib/generators/freemium/install/templates/freemium.rb +16 -0
- data/lib/generators/freemium/install/templates/models/coupon.rb +3 -0
- data/lib/generators/freemium/install/templates/models/coupon_redemption.rb +3 -0
- data/lib/generators/freemium/install/templates/models/credit_card.rb +3 -0
- data/lib/generators/freemium/install/templates/models/subscription.rb +3 -0
- data/lib/generators/freemium/install/templates/models/subscription_change.rb +3 -0
- data/lib/generators/freemium/install/templates/models/subscription_plan.rb +3 -0
- data/lib/generators/freemium/install/templates/models/transaction.rb +3 -0
- data/lib/generators/views/USAGE +3 -0
- data/lib/generators/views/views_generator.rb +39 -0
- data/lib/tasks/freemium.rake +17 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/mailers.rb +1 -0
- data/spec/dummy/app/models/models.rb +31 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +45 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +21 -0
- data/spec/dummy/config/environment.rb +6 -0
- data/spec/dummy/config/environments/development.rb +26 -0
- data/spec/dummy/config/environments/production.rb +49 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/freemium.rb +16 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mem_db.rb +12 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/schema.rb +90 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/credit_cards.yml +11 -0
- data/spec/fixtures/subscription_plans.yml +15 -0
- data/spec/fixtures/subscriptions.yml +28 -0
- data/spec/fixtures/users.yml +16 -0
- data/spec/lib/tasks/run_billing_rake_spec.rb +14 -0
- data/spec/models/coupon_redemption_spec.rb +287 -0
- data/spec/models/credit_card_spec.rb +124 -0
- data/spec/models/manual_billing_spec.rb +165 -0
- data/spec/models/subscription_plan_spec.rb +46 -0
- data/spec/models/subscription_spec.rb +386 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/helpers.rb +18 -0
- data/spec/support/shared_contexts/rake.rb +19 -0
- metadata +270 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Subscription do
|
4
|
+
fixtures :users, :subscriptions, :subscription_plans, :credit_cards
|
5
|
+
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Freemium.configuration.gateway = Freemium::Gateways::Test.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should find billable" do
|
12
|
+
# making a one-off fixture set, basically
|
13
|
+
create_billable_subscription # this subscription should be billable
|
14
|
+
create_billable_subscription(:paid_through => Date.today) # this subscription should be billable
|
15
|
+
create_billable_subscription(:coupon => Coupon.create!(:description => "Complimentary", :discount_percentage => 100)) # should NOT be billable because it's free
|
16
|
+
create_billable_subscription(:subscription_plan => subscription_plans(:free)) # should NOT be billable because it's free
|
17
|
+
create_billable_subscription(:paid_through => Date.today + 1) # should NOT be billable because it's paid far enough out
|
18
|
+
s = create_billable_subscription # should be billable because it's past due
|
19
|
+
s.update_attribute :expire_on, Date.today + 1
|
20
|
+
|
21
|
+
expirable = Subscription.send(:find_billable)
|
22
|
+
expirable.all? { |subscription| subscription.paid? }.should be_true, "free subscriptions aren't billable"
|
23
|
+
expirable.all? { |subscription| !subscription.in_trial? }.should be_true, "subscriptions that have been paid are no longer in the trial period"
|
24
|
+
expirable.all? { |subscription| subscription.paid_through <= Date.today }.should be_true, "subscriptions paid through tomorrow aren't billable yet"
|
25
|
+
expirable.size.should eql(3)
|
26
|
+
|
27
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
28
|
+
Transaction.new(
|
29
|
+
:billing_key => s.billing_key,
|
30
|
+
:amount => s.rate,
|
31
|
+
:success => false
|
32
|
+
)
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not change expire_on on failure overdue payment" do
|
37
|
+
subscription = create_billable_subscription # should NOT be billable because it's already expiring
|
38
|
+
expire_on = Date.today + 2
|
39
|
+
paid_through = subscription.paid_through
|
40
|
+
subscription.update_attribute :expire_on, expire_on
|
41
|
+
subscription.reload
|
42
|
+
subscription.expire_on.should eql(expire_on)
|
43
|
+
expirable = Subscription.send(:find_billable)
|
44
|
+
expirable.size.should eql(1), "Subscriptions in their grace period should be retried"
|
45
|
+
|
46
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
47
|
+
Transaction.new(
|
48
|
+
:billing_key => subscription.billing_key,
|
49
|
+
:amount => subscription.rate,
|
50
|
+
:success => false
|
51
|
+
)
|
52
|
+
)
|
53
|
+
|
54
|
+
lambda do
|
55
|
+
transaction = subscription.charge!
|
56
|
+
subscription.expire_on.should eql(expire_on), "Billing failed on existing overdue account but the expire_on date was changed"
|
57
|
+
end.should_not raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should change expire_on on success overdue payment" do
|
61
|
+
subscription = create_billable_subscription # should NOT be billable because it's already expiring
|
62
|
+
expire_on = Date.today + 2
|
63
|
+
paid_through = subscription.paid_through
|
64
|
+
subscription.update_attribute :expire_on, expire_on
|
65
|
+
|
66
|
+
expirable = Subscription.send(:find_billable)
|
67
|
+
expirable.size.should eql(1), "Subscriptions in their grace period should be retried"
|
68
|
+
|
69
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
70
|
+
Transaction.new(
|
71
|
+
:billing_key => subscription.billing_key,
|
72
|
+
:amount => subscription.rate,
|
73
|
+
:success => true
|
74
|
+
)
|
75
|
+
)
|
76
|
+
|
77
|
+
assert_nothing_raised do
|
78
|
+
transaction = subscription.charge!
|
79
|
+
transaction.subscription.paid_through.to_s.should eql((paid_through >> 1).to_s), "extended by a month"
|
80
|
+
subscription.expire_on.should be_nil, "Billing succeeded on existing overdue account but the expire_on date was not reset"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should charge a subscription" do
|
85
|
+
subscription = Subscription.first
|
86
|
+
subscription.coupon = Coupon.create!(:description => "Complimentary", :discount_percentage => 30)
|
87
|
+
subscription.save!
|
88
|
+
|
89
|
+
paid_through = subscription.paid_through
|
90
|
+
|
91
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
92
|
+
Transaction.new(
|
93
|
+
:billing_key => subscription.billing_key,
|
94
|
+
:amount => subscription.rate,
|
95
|
+
:success => true
|
96
|
+
)
|
97
|
+
)
|
98
|
+
|
99
|
+
lambda do
|
100
|
+
transaction = subscription.charge!
|
101
|
+
transaction.subscription.paid_through.to_s.should eql((paid_through >> 1).to_s)#, "extended by a month"
|
102
|
+
end.should_not raise_error
|
103
|
+
|
104
|
+
subscription = subscription.reload
|
105
|
+
subscription.transactions.empty?.should be_false
|
106
|
+
subscription.transactions.last.should be_true
|
107
|
+
subscription.transactions.last.success?.should be_true
|
108
|
+
subscription.transactions.last.message?.should_not be_nil
|
109
|
+
((Time.now - 1.minute) < subscription.last_transaction_at).should be_true
|
110
|
+
Transaction.since(Date.today).empty?.should be_false
|
111
|
+
subscription.transactions.last.amount.should eql(subscription.rate)
|
112
|
+
subscription.reload.paid_through.to_s.should eql((paid_through >> 1).to_s), "extended by a month"
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
it "should charge an aborted subscription" do
|
117
|
+
subscription = Subscription.first
|
118
|
+
subscription.coupon = Coupon.create!(:description => "Complimentary", :discount_percentage => 30)
|
119
|
+
subscription.save!
|
120
|
+
|
121
|
+
paid_through = subscription.paid_through
|
122
|
+
subscription.transactions.empty?.should be_true
|
123
|
+
|
124
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
125
|
+
Transaction.new(
|
126
|
+
:billing_key => subscription.billing_key,
|
127
|
+
:amount => subscription.rate,
|
128
|
+
:success => true
|
129
|
+
)
|
130
|
+
)
|
131
|
+
|
132
|
+
subscription.should_receive(:receive_payment).and_raise(RuntimeError)
|
133
|
+
subscription.charge!
|
134
|
+
subscription.reload.transactions.empty?.should be_false
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not charge a subscription" do
|
138
|
+
subscription = Subscription.first
|
139
|
+
paid_through = subscription.paid_through
|
140
|
+
Freemium.configuration.gateway.stub!(:charge).and_return(
|
141
|
+
Transaction.new(
|
142
|
+
:billing_key => subscription.billing_key,
|
143
|
+
:amount => subscription.rate,
|
144
|
+
:success => false
|
145
|
+
)
|
146
|
+
)
|
147
|
+
|
148
|
+
subscription.expire_on.should be_nil
|
149
|
+
lambda { subscription.charge! }.should_not raise_error
|
150
|
+
subscription.reload.paid_through.should eql(paid_through), "not extended"
|
151
|
+
subscription.expire_on.should_not be_nil
|
152
|
+
subscription.transactions.last.success?.should be_false
|
153
|
+
end
|
154
|
+
|
155
|
+
protected
|
156
|
+
|
157
|
+
def create_billable_subscription(options = {})
|
158
|
+
Subscription.create!({
|
159
|
+
:subscription_plan => subscription_plans(:premium),
|
160
|
+
:subscribable => User.new(:name => 'a'),
|
161
|
+
:paid_through => Date.today - 1,
|
162
|
+
:credit_card => CreditCard.sample
|
163
|
+
}.merge(options))
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SubscriptionPlan do
|
4
|
+
fixtures :users, :subscriptions, :subscription_plans, :credit_cards
|
5
|
+
|
6
|
+
it "should have associations" do
|
7
|
+
[subscriptions(:bobs_subscription)].should == (subscription_plans(:basic).subscriptions)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have rate intervals" do
|
11
|
+
plan = SubscriptionPlan.new(:rate_cents => 3041)
|
12
|
+
plan.daily_rate.should eql(Money.new(99))
|
13
|
+
plan.monthly_rate.should eql(Money.new(3041))
|
14
|
+
plan.yearly_rate.should eql(Money.new(36492))
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create plan" do
|
18
|
+
plan = create_plan
|
19
|
+
plan.new_record?.should be_false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have errors" do
|
23
|
+
[:name, :rate_cents].each do |field|
|
24
|
+
plan = create_plan(field => nil)
|
25
|
+
plan.new_record?.should be_true
|
26
|
+
plan.should have(1).errors_on(field)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should serialize features" do
|
31
|
+
plan = create_plan
|
32
|
+
plan.features.should == {}
|
33
|
+
plan2 = create_plan(features: {foo: 1})
|
34
|
+
plan2.features[:foo].should == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def create_plan(options = {})
|
40
|
+
SubscriptionPlan.create({
|
41
|
+
:name => 'super-duper-ultra-premium',
|
42
|
+
:key => 'super-duper-ultra-premium',
|
43
|
+
:rate_cents => 99995
|
44
|
+
}.merge(options))
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Subscription do
|
4
|
+
fixtures :users, :subscriptions, :subscription_plans, :credit_cards
|
5
|
+
|
6
|
+
def build_subscription(options = {})
|
7
|
+
Subscription.new({
|
8
|
+
:subscription_plan => subscription_plans(:free),
|
9
|
+
:subscribable => users(:sue)
|
10
|
+
}.merge(options))
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_transaction_for(amount, subscription)
|
14
|
+
Transaction.create :amount => amount, :subscription => subscription, :success => true, :billing_key => 12345
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_changed(subscribable, reason, original_plan, new_plan)
|
18
|
+
changes = SubscriptionChange.where(["subscribable_id = ? AND subscribable_type = ?", subscribable.id, subscribable.class.to_s]).last
|
19
|
+
changes.should_not be_nil
|
20
|
+
changes.reason.should eql(reason.to_s)
|
21
|
+
changes.original_subscription_plan.should eql(original_plan)
|
22
|
+
changes.new_subscription_plan.should eq(new_plan)
|
23
|
+
changes.original_rate_cents.should eql(original_plan ? original_plan.rate.cents : 0)
|
24
|
+
changes.new_rate_cents.should eql(new_plan ? new_plan.rate.cents : 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should create free subscription" do
|
28
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:free))
|
29
|
+
subscription.save!
|
30
|
+
|
31
|
+
subscription.should_not be_new_record
|
32
|
+
subscription.reload.started_on.should eql(Date.today)
|
33
|
+
subscription.in_trial?.should be_false
|
34
|
+
subscription.paid_through.should be_nil
|
35
|
+
subscription.paid?.should be_false
|
36
|
+
|
37
|
+
#TODO understand what is that
|
38
|
+
assert_changed(subscription.subscribable, :new, nil, subscription_plans(:free))
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should create paid subscription" do
|
42
|
+
Freemium.configuration.days_free_trial = 30
|
43
|
+
|
44
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:basic), :credit_card => CreditCard.sample)
|
45
|
+
subscription.save!
|
46
|
+
|
47
|
+
subscription.should_not be_new_record
|
48
|
+
subscription.reload.started_on.should eql(Date.today)
|
49
|
+
subscription.in_trial?.should be_true
|
50
|
+
subscription.paid_through.should_not be_nil
|
51
|
+
subscription.paid_through.should eql(Date.today + Freemium.configuration.days_free_trial)
|
52
|
+
subscription.paid?.should be_true
|
53
|
+
subscription.billing_key.should_not be_nil
|
54
|
+
|
55
|
+
assert_changed(subscription.subscribable, :new, nil, subscription_plans(:basic))
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be upgraded from free" do
|
59
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:free))
|
60
|
+
subscription.save!
|
61
|
+
|
62
|
+
new_date = Date.today + 10.days
|
63
|
+
Date.stub!(:today => new_date)
|
64
|
+
|
65
|
+
subscription.in_trial?.should be_false
|
66
|
+
subscription.subscription_plan = subscription_plans(:basic)
|
67
|
+
subscription.credit_card = CreditCard.sample
|
68
|
+
subscription.save!
|
69
|
+
|
70
|
+
subscription.reload.started_on.should eql(new_date)
|
71
|
+
subscription.paid_through.should_not be_nil
|
72
|
+
subscription.in_trial?.should be_false
|
73
|
+
subscription.paid_through.should eql(new_date)
|
74
|
+
subscription.paid?.should be_true
|
75
|
+
subscription.billing_key.should_not be_nil
|
76
|
+
|
77
|
+
assert_changed(subscription.subscribable, :upgrade, subscription_plans(:free), subscription_plans(:basic))
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should be downgraded" do
|
81
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:basic), :credit_card => CreditCard.sample)
|
82
|
+
subscription.save!
|
83
|
+
|
84
|
+
new_date = Date.today + 10.days
|
85
|
+
Date.stub!(:today => new_date)
|
86
|
+
|
87
|
+
subscription.subscription_plan = subscription_plans(:free)
|
88
|
+
subscription.save!
|
89
|
+
|
90
|
+
subscription.reload.started_on.should eql(new_date)
|
91
|
+
subscription.paid_through.should be_nil
|
92
|
+
subscription.paid?.should be_false
|
93
|
+
subscription.billing_key.should be_nil
|
94
|
+
subscription.credit_card.should be_nil
|
95
|
+
|
96
|
+
assert_changed(subscription.subscribable, :downgrade, subscription_plans(:basic), subscription_plans(:free))
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should have associations" do
|
100
|
+
assert_equal users(:bob), subscriptions(:bobs_subscription).subscribable
|
101
|
+
assert_equal subscription_plans(:basic), subscriptions(:bobs_subscription).subscription_plan
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should have remaining_days" do
|
105
|
+
assert_equal 20, subscriptions(:bobs_subscription).remaining_days
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should have remaining_value" do
|
109
|
+
assert_equal Money.new(840), subscriptions(:bobs_subscription).remaining_value
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
## Upgrade / Downgrade service credits
|
114
|
+
##
|
115
|
+
|
116
|
+
it "should upgrade credit" do
|
117
|
+
subscription = subscriptions(:bobs_subscription)
|
118
|
+
new_plan = subscription_plans(:premium)
|
119
|
+
|
120
|
+
subscription.remaining_value.cents.should > 0
|
121
|
+
expected_paid_through = Date.today + (subscription.remaining_value.cents / new_plan.daily_rate.cents)
|
122
|
+
subscription.subscription_plan = subscription_plans(:premium)
|
123
|
+
subscription.save!
|
124
|
+
|
125
|
+
subscription.paid_through.should eql(expected_paid_through)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should upgrade no credit for free trial" do
|
129
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:premium), :credit_card => CreditCard.sample)
|
130
|
+
subscription.save!
|
131
|
+
|
132
|
+
subscription.paid_through.should eql(Date.today + Freemium.configuration.days_free_trial)
|
133
|
+
subscription.in_trial?.should be_true
|
134
|
+
|
135
|
+
subscription.subscription_plan = subscription_plans(:basic)
|
136
|
+
subscription.save!
|
137
|
+
|
138
|
+
subscription.paid_through.should eql(Date.today)
|
139
|
+
subscription.in_trial?.should be_false
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
## Validations
|
144
|
+
##
|
145
|
+
|
146
|
+
it "should test missing fields" do
|
147
|
+
[:subscription_plan, :subscribable].each do |field|
|
148
|
+
subscription = build_subscription(field => nil)
|
149
|
+
subscription.save
|
150
|
+
|
151
|
+
subscription.should be_new_record
|
152
|
+
subscription.should have(1).errors_on(field)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
## Receiving payment
|
158
|
+
##
|
159
|
+
|
160
|
+
it "should receive monthly payment" do
|
161
|
+
subscription = subscriptions(:bobs_subscription)
|
162
|
+
paid_through = subscription.paid_through
|
163
|
+
subscription.credit(subscription_plans(:basic).rate)
|
164
|
+
subscription.save!
|
165
|
+
|
166
|
+
subscription.paid_through.to_s.should eql((paid_through >> 1).to_s) #extended by one month
|
167
|
+
subscription.transactions.should_not be_nil
|
168
|
+
end
|
169
|
+
|
170
|
+
its "should receive quarterly payment" do
|
171
|
+
subscription = subscriptions(:bobs_subscription)
|
172
|
+
paid_through = subscription.paid_through
|
173
|
+
subscription.credit(subscription_plans(:basic).rate * 3)
|
174
|
+
subscription.save!
|
175
|
+
subscription.paid_through.to_s.should eql((paid_through >> 3).to_s) #extended by three months
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should receive partial payment" do
|
179
|
+
subscription = subscriptions(:bobs_subscription)
|
180
|
+
paid_through = subscription.paid_through
|
181
|
+
subscription.credit(subscription_plans(:basic).rate * 0.5)
|
182
|
+
subscription.save!
|
183
|
+
subscription.paid_through.to_s.should eql((paid_through + 15).to_s) #extended by 15 days
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should send invoice when receiving payment" do
|
187
|
+
subscription = subscriptions(:bobs_subscription)
|
188
|
+
ActionMailer::Base.deliveries = []
|
189
|
+
transaction = create_transaction_for(subscription_plans(:basic).rate, subscription)
|
190
|
+
subscription.receive_payment!(transaction)
|
191
|
+
ActionMailer::Base.deliveries.size.should eql(1)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should save transaction message when receiving payment" do
|
195
|
+
subscription = subscriptions(:bobs_subscription)
|
196
|
+
transaction = create_transaction_for(subscription_plans(:basic).rate, subscription)
|
197
|
+
subscription.receive_payment!(transaction)
|
198
|
+
transaction.reload.message.should match(/^now paid through/)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should receive payment though invoice has delivered with error" do
|
202
|
+
subscription = subscriptions(:bobs_subscription)
|
203
|
+
paid_through = subscription.paid_through
|
204
|
+
transaction = create_transaction_for(subscription_plans(:basic).rate, subscription)
|
205
|
+
Freemium.configuration.mailer.should_receive(:invoice).and_raise(RuntimeError)
|
206
|
+
subscription.receive_payment!(transaction)
|
207
|
+
subscription = subscription.reload
|
208
|
+
subscription.paid_through.to_s.should eql((paid_through >> 1).to_s) #extended by one month
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
## Requiring Credit Cards ...
|
213
|
+
##
|
214
|
+
|
215
|
+
it "should require credit card for pay plan" do
|
216
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:premium))
|
217
|
+
subscription.stub!(:credit_card => nil)
|
218
|
+
subscription.should have(1).errors_on(:credit_card)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should not require credit card for free_plan" do
|
222
|
+
subscription = build_subscription
|
223
|
+
subscription.should have(0).errors_on(:credit_card)
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
## Expiration
|
228
|
+
##
|
229
|
+
|
230
|
+
it "should expire instance" do
|
231
|
+
Freemium.configuration.expired_plan = subscription_plans(:free)
|
232
|
+
Freemium.configuration.gateway.should_receive(:cancel).once.and_return(nil)
|
233
|
+
ActionMailer::Base.deliveries = []
|
234
|
+
subscriptions(:bobs_subscription).expire!
|
235
|
+
|
236
|
+
ActionMailer::Base.deliveries.size.should eql(1) #notice is sent to user
|
237
|
+
subscriptions(:bobs_subscription).reload.subscription_plan.should eql(subscription_plans(:free)) #subscription is downgraded to free
|
238
|
+
subscriptions(:bobs_subscription).billing_key.should be_nil #billing key is thrown away
|
239
|
+
subscriptions(:bobs_subscription).reload.billing_key.should be_nil #billing key is thrown away
|
240
|
+
|
241
|
+
assert_changed(subscriptions(:bobs_subscription).subscribable, :expiration, subscription_plans(:basic), subscription_plans(:free))
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should expire instance with expired_plan_key = nil" do
|
245
|
+
Freemium.configuration.expired_plan = nil
|
246
|
+
Freemium.configuration.gateway.should_receive(:cancel).once.and_return(nil)
|
247
|
+
ActionMailer::Base.deliveries = []
|
248
|
+
subscriptions(:bobs_subscription).expire!
|
249
|
+
|
250
|
+
ActionMailer::Base.deliveries.size.should eql(1) #notice is sent to user
|
251
|
+
subscriptions(:bobs_subscription).subscription_plan.should eql(subscription_plans(:basic)) #subscription was not changed
|
252
|
+
subscriptions(:bobs_subscription).billing_key.should be_nil #billing key is thrown away
|
253
|
+
subscriptions(:bobs_subscription).reload.billing_key.should be_nil #billing key is thrown away
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should expire class" do
|
257
|
+
Freemium.configuration.expired_plan = subscription_plans(:free)
|
258
|
+
Freemium.configuration.expired_plan.should eql(subscription_plans(:free))
|
259
|
+
Freemium.configuration.expired_plan.should_not be_nil
|
260
|
+
subscriptions(:bobs_subscription).update_attributes(:paid_through => Date.today - 4, :expire_on => Date.today)
|
261
|
+
ActionMailer::Base.deliveries = []
|
262
|
+
|
263
|
+
subscriptions(:bobs_subscription).subscription_plan.should eql(subscription_plans(:basic))
|
264
|
+
|
265
|
+
Freemium.configuration.expired_plan.should eql(subscription_plans(:free))
|
266
|
+
Subscription.find_expired.each(&:expire!)
|
267
|
+
|
268
|
+
subscriptions(:bobs_subscription).expire!
|
269
|
+
subscriptions(:bobs_subscription).reload.subscription_plan.should eql(subscription_plans(:free))
|
270
|
+
subscriptions(:bobs_subscription).reload.started_on.should eql(Date.today)
|
271
|
+
ActionMailer::Base.deliveries.size.should > 0
|
272
|
+
|
273
|
+
assert_changed(subscriptions(:bobs_subscription).subscribable, :expiration, subscription_plans(:basic), subscription_plans(:free))
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should expire after grace " do
|
277
|
+
subscriptions(:bobs_subscription).expire_on.should be_nil
|
278
|
+
subscriptions(:bobs_subscription).paid_through = Date.today - 2
|
279
|
+
ActionMailer::Base.deliveries = []
|
280
|
+
|
281
|
+
subscriptions(:bobs_subscription).expire_after_grace!
|
282
|
+
|
283
|
+
ActionMailer::Base.deliveries.size.should eql(1)
|
284
|
+
subscriptions(:bobs_subscription).reload.expire_on.should eql(Date.today + Freemium.configuration.days_grace)
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should expire after grace with remaining period" do
|
288
|
+
subscriptions(:bobs_subscription).paid_through = Date.today + 1
|
289
|
+
subscriptions(:bobs_subscription).expire_after_grace!
|
290
|
+
|
291
|
+
subscriptions(:bobs_subscription).reload.expire_on.should eql(Date.today + 1 + Freemium.configuration.days_grace)
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should test grace and expiration" do
|
295
|
+
Freemium.configuration.days_grace.should eql(3)
|
296
|
+
|
297
|
+
subscription = Subscription.new(:paid_through => Date.today + 5)
|
298
|
+
subscription.in_grace?.should be_false
|
299
|
+
subscription.expired?.should be_false
|
300
|
+
|
301
|
+
# a subscription that's pastdue but hasn't been flagged to expire yet.
|
302
|
+
# this could happen if a billing process skips, in which case the subscriber
|
303
|
+
# should still get a full grace period beginning from the failed attempt at billing.
|
304
|
+
# even so, the subscription is "in grace", even if the grace period hasn't officially started.
|
305
|
+
subscription = Subscription.new(:paid_through => Date.today - 5)
|
306
|
+
subscription.in_grace?.should be_true
|
307
|
+
subscription.expired?.should be_false
|
308
|
+
|
309
|
+
# expires tomorrow
|
310
|
+
subscription = Subscription.new(:paid_through => Date.today - 5, :expire_on => Date.today + 1)
|
311
|
+
subscription.remaining_days_of_grace.should eql(0)
|
312
|
+
subscription.in_grace?.should be_true
|
313
|
+
subscription.expired?.should be_false
|
314
|
+
|
315
|
+
# expires today
|
316
|
+
subscription = Subscription.new(:paid_through => Date.today - 5, :expire_on => Date.today)
|
317
|
+
subscription.remaining_days_of_grace.should eql(-1)
|
318
|
+
subscription.in_grace?.should be_false
|
319
|
+
subscription.expired?.should be_true
|
320
|
+
end
|
321
|
+
|
322
|
+
##
|
323
|
+
## Deleting (possibly from a cascading delete, such as User.find(5).delete)
|
324
|
+
##
|
325
|
+
|
326
|
+
it "should delete canceles in gateway" do
|
327
|
+
Freemium.configuration.gateway.should_receive(:cancel).once.and_return(nil)
|
328
|
+
subscriptions(:bobs_subscription).destroy
|
329
|
+
|
330
|
+
assert_changed(subscriptions(:bobs_subscription).subscribable, :cancellation, subscription_plans(:basic), nil)
|
331
|
+
end
|
332
|
+
|
333
|
+
##
|
334
|
+
## The Subscription#credit_card= shortcut
|
335
|
+
##
|
336
|
+
it "should add credit card" do
|
337
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:premium))
|
338
|
+
cc = CreditCard.sample
|
339
|
+
response = Freemium::Response.new(true)
|
340
|
+
response.billing_key = "alphabravo"
|
341
|
+
Freemium.configuration.gateway.should_receive(:store).with(cc).and_return(response)
|
342
|
+
|
343
|
+
subscription.credit_card = cc
|
344
|
+
lambda { subscription.save! }.should_not raise_error
|
345
|
+
subscription.billing_key.should eql("alphabravo")
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should update a credit card" do
|
349
|
+
subscription = Subscription.where("billing_key IS NOT NULL").first
|
350
|
+
cc = CreditCard.sample
|
351
|
+
response = Freemium::Response.new(true)
|
352
|
+
response.billing_key = "new code"
|
353
|
+
Freemium.configuration.gateway.should_receive(:update).with(subscription.billing_key, cc).and_return(response)
|
354
|
+
|
355
|
+
subscription.credit_card = cc
|
356
|
+
lambda { subscription.save! }.should_not raise_error
|
357
|
+
subscription.billing_key.should eql("new code") #catches any change to the billing key
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should update an expired credit card" do
|
361
|
+
subscription = Subscription.where("billing_key IS NOT NULL").first
|
362
|
+
cc = CreditCard.sample
|
363
|
+
response = Freemium::Response.new(true)
|
364
|
+
Freemium.configuration.gateway.should_receive(:update).with(subscription.billing_key, cc).and_return(response)
|
365
|
+
|
366
|
+
subscription.expire_on = Time.now
|
367
|
+
subscription.save.should be_true
|
368
|
+
subscription.reload.expire_on.should_not be_nil
|
369
|
+
|
370
|
+
subscription.credit_card = cc
|
371
|
+
lambda { subscription.save! }.should_not raise_error
|
372
|
+
#subscription.expire_on.should be_nil
|
373
|
+
#subscription.reload.expire_on.should be_nil
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should fail to add credit card" do
|
377
|
+
subscription = build_subscription(:subscription_plan => subscription_plans(:premium))
|
378
|
+
cc = CreditCard.sample
|
379
|
+
response = Freemium::Response.new(false)
|
380
|
+
Freemium.configuration.gateway.should_receive(:store).and_return(response)
|
381
|
+
|
382
|
+
subscription.credit_card = cc
|
383
|
+
lambda { subscription.save! }.should raise_error(Freemium::CreditCardStorageError)
|
384
|
+
end
|
385
|
+
|
386
|
+
end
|