stripe_saas 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.asc +1 -1
- data/Rakefile +1 -13
- data/app/assets/javascripts/stripe_saas/application.js +1 -1
- data/app/concerns/stripe_saas/plan.rb +22 -3
- data/app/concerns/stripe_saas/plan_feature.rb +4 -4
- data/app/concerns/stripe_saas/subscription.rb +1 -2
- data/lib/generators/stripe_saas/install_generator.rb +1 -1
- data/lib/generators/stripe_saas/templates/app/models/plan_feature.rb +2 -0
- data/lib/stripe_saas/engine.rb +4 -0
- data/lib/stripe_saas/version.rb +1 -1
- data/spec/dummy/app/assets/javascripts/application.js +1 -1
- data/spec/dummy/app/models/feature.rb +8 -0
- data/spec/dummy/app/models/plan.rb +4 -2
- data/spec/dummy/app/models/plan_feature.rb +6 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150102001930_create_plans.rb +0 -1
- data/spec/dummy/db/migrate/20151220161809_create_features.rb +14 -0
- data/spec/dummy/db/migrate/20151220161817_create_plan_features.rb +12 -0
- data/spec/dummy/db/schema.rb +21 -2
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +3215 -0
- data/spec/models/feature_spec.rb +36 -0
- data/spec/models/plan_feature_spec.rb +89 -0
- data/spec/models/plan_spec.rb +137 -0
- data/spec/models/subscription_spec.rb +73 -0
- data/spec/spec_helper.rb +11 -3
- metadata +20 -9
- data/spec/concerns/plan_spec.rb +0 -50
- data/spec/dummy/log/development.log +0 -170
- data/spec/integration/navigation_test.rb +0 -9
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Feature, type: :model do
|
4
|
+
|
5
|
+
it { is_expected.to have_many(:plan_features) }
|
6
|
+
it { is_expected.to have_many(:plans) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
@feature = Feature.find_or_create_by(name: 'signals')
|
10
|
+
@feature.update({
|
11
|
+
description: "Inbound Signals",
|
12
|
+
feature_type: :number,
|
13
|
+
display_order: 1
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#feature_type' do
|
18
|
+
it 'correctly assigns the feature type and unit given a symbol' do
|
19
|
+
expect(@feature.feature_type).to eq('number')
|
20
|
+
expect(@feature.unit).to eq('Number')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'throws an error given an invalid feature type' do
|
24
|
+
feature = Feature.new
|
25
|
+
|
26
|
+
expect { feature.feature_type = :foo }.to raise_error(ArgumentError, "foo is not a valid feature type")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#to_s' do
|
31
|
+
it 'returns the feature\'s name' do
|
32
|
+
expect(@feature.to_s).to eq('signals')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe PlanFeature, type: :model do
|
4
|
+
|
5
|
+
it { is_expected.to belong_to(:feature) }
|
6
|
+
it { is_expected.to belong_to(:plan) }
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
@number_feature = Feature.find_or_create_by(name: 'number_feature')
|
10
|
+
@number_feature.update({
|
11
|
+
description: "Data Retention",
|
12
|
+
feature_type: :number,
|
13
|
+
unit: "months",
|
14
|
+
display_order: 1
|
15
|
+
})
|
16
|
+
|
17
|
+
@boolean_feature = Feature.find_or_create_by(name: 'boolean_feature')
|
18
|
+
@boolean_feature.update({
|
19
|
+
description: "My boolean feature",
|
20
|
+
feature_type: :boolean,
|
21
|
+
display_order: 2
|
22
|
+
})
|
23
|
+
|
24
|
+
@another_number_feature = Feature.find_or_create_by(name: 'another_number_feature')
|
25
|
+
@another_number_feature.update({
|
26
|
+
description: "Data Retention",
|
27
|
+
feature_type: :number,
|
28
|
+
unit: "month",
|
29
|
+
use_unit: true,
|
30
|
+
display_order: 3
|
31
|
+
})
|
32
|
+
|
33
|
+
@plan = Plan.find_or_create_by(stripe_id: 'my_plan')
|
34
|
+
@plan.update({
|
35
|
+
name: 'My Plan',
|
36
|
+
price: 0.0,
|
37
|
+
interval: 'month',
|
38
|
+
interval_count: 1,
|
39
|
+
statement_descriptor: 'My Awesome Plan',
|
40
|
+
trial_period_days: 30,
|
41
|
+
display_order: 1
|
42
|
+
})
|
43
|
+
|
44
|
+
@plan.add_feature(:number_feature, 100)
|
45
|
+
@plan.add_feature(:boolean_feature, true)
|
46
|
+
@plan.add_feature(:another_number_feature, 314)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#value=' do
|
50
|
+
it 'correctly marshalls the given type to a string for storage' do
|
51
|
+
boolean_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'boolean_feature'})
|
52
|
+
number_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'number_feature'})
|
53
|
+
|
54
|
+
expect(boolean_plan_feature['value']).to eq('true')
|
55
|
+
expect(number_plan_feature['value']).to eq('100')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#value' do
|
60
|
+
it 'correctly un-marshalls to the correct data type' do
|
61
|
+
boolean_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'boolean_feature'})
|
62
|
+
number_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'number_feature'})
|
63
|
+
|
64
|
+
expect(boolean_plan_feature.value).to eq(true)
|
65
|
+
expect(number_plan_feature.value).to eq(100)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#to_s' do
|
70
|
+
it 'returns the qty and description for non-boolean features' do
|
71
|
+
number_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'number_feature'})
|
72
|
+
|
73
|
+
expect(number_plan_feature.to_s).to eq('100 Data Retention')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns the description for boolean features' do
|
77
|
+
boolean_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'boolean_feature'})
|
78
|
+
|
79
|
+
expect(boolean_plan_feature.to_s).to eq('boolean_feature')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns the qty and description for non-boolean features' do
|
83
|
+
number_plan_feature = @plan.plan_features.joins(:feature).find_by(features: { name: 'another_number_feature'})
|
84
|
+
|
85
|
+
expect(number_plan_feature.to_s).to eq('314 Months Data Retention')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Plan, type: :model do
|
4
|
+
|
5
|
+
it { is_expected.to have_many(:subscriptions) }
|
6
|
+
it { is_expected.to have_many(:plan_features) }
|
7
|
+
it { is_expected.to have_many(:features) }
|
8
|
+
|
9
|
+
describe '#is_upgrade_from?' do
|
10
|
+
|
11
|
+
it 'returns true if the price is higher' do
|
12
|
+
plan = Plan.new(price: 123.23)
|
13
|
+
cheaper_plan = Plan.new(price: 61.61)
|
14
|
+
|
15
|
+
expect(plan.is_upgrade_from?(cheaper_plan)).to be true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns true if the price is the same' do
|
19
|
+
plan = Plan.new(price: 123.23)
|
20
|
+
|
21
|
+
expect(plan.is_upgrade_from?(plan)).to be true
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns false if the price is the same or higher' do
|
25
|
+
plan = Plan.new(price: 61.61)
|
26
|
+
more_expensive_plan = Plan.new(price: 123.23)
|
27
|
+
|
28
|
+
expect(plan.is_upgrade_from?(more_expensive_plan)).to be false
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'handles a nil value gracefully' do
|
32
|
+
plan = Plan.new(price: 123.23)
|
33
|
+
cheaper_plan = Plan.new
|
34
|
+
|
35
|
+
expect(plan.is_upgrade_from?(cheaper_plan)).to be true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'metadata' do
|
40
|
+
it 'can set plan JSON metadata as a hash' do
|
41
|
+
plan = Plan.new(price: 0.0)
|
42
|
+
plan.metadata = { 'foo': 'bar' }
|
43
|
+
|
44
|
+
expect(plan.metadata).to eq({'foo' => 'bar'})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#free?' do
|
49
|
+
it 'returns whether the plan is a free plan' do
|
50
|
+
plan = Plan.new(price: 0.0)
|
51
|
+
expect(plan).to be_free
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#is_downgrade_from?' do
|
56
|
+
it 'is the opposite of #is_upgrade_from?' do
|
57
|
+
plan = Plan.new(price: 123.23)
|
58
|
+
cheaper_plan = Plan.new
|
59
|
+
more_expensive_plan = Plan.new(price: 123.23)
|
60
|
+
|
61
|
+
expect(plan.is_downgrade_from?(cheaper_plan)).to be false
|
62
|
+
expect(plan.is_downgrade_from?(more_expensive_plan)).to be false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'features' do
|
67
|
+
before(:all) do
|
68
|
+
@number_feature = Feature.find_or_create_by(name: 'number_feature')
|
69
|
+
@number_feature.update({
|
70
|
+
description: "My numeric feature",
|
71
|
+
feature_type: :number,
|
72
|
+
unit: "some_unit",
|
73
|
+
display_order: 1
|
74
|
+
})
|
75
|
+
|
76
|
+
@boolean_feature = Feature.find_or_create_by(name: 'boolean_feature')
|
77
|
+
@boolean_feature.update({
|
78
|
+
description: "My boolean feature",
|
79
|
+
feature_type: :boolean,
|
80
|
+
display_order: 2
|
81
|
+
})
|
82
|
+
|
83
|
+
@plan = Plan.find_or_create_by(stripe_id: 'my_plan')
|
84
|
+
@plan.update({
|
85
|
+
name: 'My Plan',
|
86
|
+
price: 0.0,
|
87
|
+
interval: 'month',
|
88
|
+
interval_count: 1,
|
89
|
+
statement_descriptor: 'My Awesome Plan',
|
90
|
+
trial_period_days: 30,
|
91
|
+
display_order: 1
|
92
|
+
})
|
93
|
+
|
94
|
+
@plan.add_feature(:number_feature, 100)
|
95
|
+
@plan.add_feature(:boolean_feature, true)
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#add_feature' do
|
99
|
+
it 'adds a PlanFeature to a Plan' do
|
100
|
+
expect(@plan.features.map(&:name)).to include('boolean_feature', 'number_feature')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#has_feature?' do
|
105
|
+
it 'determines if a plan as certain feature' do
|
106
|
+
expect(@plan.has_feature?('boolean_feature')).to be true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#feature_value' do
|
111
|
+
it 'returns the value of a PlanFeature' do
|
112
|
+
expect(@plan.feature_value('number_feature')).to eq(100)
|
113
|
+
expect(@plan.feature_value('boolean_feature')).to be true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#allows?' do
|
118
|
+
it 'returns whether a feature is enabled' do
|
119
|
+
expect(@plan.allows?('number_feature')).to be true
|
120
|
+
expect(@plan.allows?('boolean_feature')).to be true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#boolean_plan_features' do
|
125
|
+
it 'returns the plan features of boolean type' do
|
126
|
+
expect(@plan.boolean_plan_features.map { |pf| pf.feature.name }).to contain_exactly('boolean_feature')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#non_boolean_plan_features' do
|
131
|
+
it 'returns the plan features that are not of boolean type' do
|
132
|
+
expect(@plan.non_boolean_plan_features.map { |pf| pf.feature.name }).to contain_exactly('number_feature')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Subscription, type: :model do
|
4
|
+
|
5
|
+
it { is_expected.to belong_to(:plan) }
|
6
|
+
|
7
|
+
let(:user) { User.new({email: 'bsbodden@integrallis.com'}) }
|
8
|
+
|
9
|
+
let(:less_expensive_plan) { Plan.new({
|
10
|
+
stripe_id: 'free_plan',
|
11
|
+
name: 'My Plan',
|
12
|
+
price: 0.0,
|
13
|
+
interval: 'month',
|
14
|
+
interval_count: 1,
|
15
|
+
statement_descriptor: 'Cheaper Awesome Plan',
|
16
|
+
trial_period_days: 30,
|
17
|
+
display_order: 1
|
18
|
+
})}
|
19
|
+
|
20
|
+
let(:plan) { Plan.new({
|
21
|
+
stripe_id: 'my_plan',
|
22
|
+
name: 'My Plan',
|
23
|
+
price: 10.0,
|
24
|
+
interval: 'month',
|
25
|
+
interval_count: 1,
|
26
|
+
statement_descriptor: 'My Awesome Plan',
|
27
|
+
trial_period_days: 30,
|
28
|
+
display_order: 1
|
29
|
+
})}
|
30
|
+
|
31
|
+
let(:more_expensive_plan) { Plan.new({
|
32
|
+
stripe_id: 'another_plan',
|
33
|
+
name: 'Another Plan',
|
34
|
+
price: 100.0,
|
35
|
+
interval: 'month',
|
36
|
+
interval_count: 1,
|
37
|
+
statement_descriptor: 'More Expensive Awesome Plan',
|
38
|
+
trial_period_days: 30,
|
39
|
+
display_order: 2
|
40
|
+
})}
|
41
|
+
|
42
|
+
let(:subscription) { Subscription.new(user: user, plan: plan) }
|
43
|
+
|
44
|
+
describe '#subscription_owner' do
|
45
|
+
it 'returns the owner of the subscription' do
|
46
|
+
expect(subscription.subscription_owner).to be(user)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#subscription_owner_email' do
|
51
|
+
it 'returns the owner of the subscription' do
|
52
|
+
expect(subscription.subscription_owner_email).to eq(user.email)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#subscription_owner_description' do
|
57
|
+
it 'returns a descriptive field for the owner of the subscription' do
|
58
|
+
expect(subscription.subscription_owner_description).to eq(user.email)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#describe_difference' do
|
63
|
+
it 'returns whether it would be an Upgrade to a given plan' do
|
64
|
+
expect(subscription.describe_difference(more_expensive_plan)).to eq('Upgrade')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns whether it would be a Downgrade to a given plan' do
|
68
|
+
expect(subscription.describe_difference(less_expensive_plan)).to eq('Downgrade')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
# ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
|
7
|
+
# require "bundler"
|
8
|
+
require "shoulda-matchers"
|
9
|
+
# Bundler.setup
|
4
10
|
|
5
11
|
RSpec.configure do |config|
|
12
|
+
config.include(Shoulda::Matchers::ActiveModel, type: :model)
|
13
|
+
config.include(Shoulda::Matchers::ActiveRecord, type: :model)
|
6
14
|
|
7
15
|
config.expect_with :rspec do |expectations|
|
8
16
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe_saas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Sam-Bodden
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -106,7 +106,8 @@ dependencies:
|
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: 3.4.1
|
109
|
-
description:
|
109
|
+
description: A Rails Engine that provides everything you need to Stripe enable your
|
110
|
+
app.
|
110
111
|
email:
|
111
112
|
- bsbodden@integrallis.com
|
112
113
|
executables: []
|
@@ -147,14 +148,15 @@ files:
|
|
147
148
|
- lib/stripe_saas/engine.rb
|
148
149
|
- lib/stripe_saas/version.rb
|
149
150
|
- lib/tasks/stripe_saas_tasks.rake
|
150
|
-
- spec/concerns/plan_spec.rb
|
151
151
|
- spec/dummy/README.rdoc
|
152
152
|
- spec/dummy/Rakefile
|
153
153
|
- spec/dummy/app/assets/javascripts/application.js
|
154
154
|
- spec/dummy/app/assets/stylesheets/application.css
|
155
155
|
- spec/dummy/app/controllers/application_controller.rb
|
156
156
|
- spec/dummy/app/helpers/application_helper.rb
|
157
|
+
- spec/dummy/app/models/feature.rb
|
157
158
|
- spec/dummy/app/models/plan.rb
|
159
|
+
- spec/dummy/app/models/plan_feature.rb
|
158
160
|
- spec/dummy/app/models/subscription.rb
|
159
161
|
- spec/dummy/app/models/user.rb
|
160
162
|
- spec/dummy/app/views/layouts/application.html.erb
|
@@ -188,15 +190,19 @@ files:
|
|
188
190
|
- spec/dummy/db/migrate/20150101233243_devise_create_users.rb
|
189
191
|
- spec/dummy/db/migrate/20150102001921_create_subscriptions.rb
|
190
192
|
- spec/dummy/db/migrate/20150102001930_create_plans.rb
|
193
|
+
- spec/dummy/db/migrate/20151220161809_create_features.rb
|
194
|
+
- spec/dummy/db/migrate/20151220161817_create_plan_features.rb
|
191
195
|
- spec/dummy/db/schema.rb
|
192
196
|
- spec/dummy/db/test.sqlite3
|
193
|
-
- spec/dummy/log/development.log
|
194
197
|
- spec/dummy/log/test.log
|
195
198
|
- spec/dummy/public/404.html
|
196
199
|
- spec/dummy/public/422.html
|
197
200
|
- spec/dummy/public/500.html
|
198
201
|
- spec/dummy/public/favicon.ico
|
199
|
-
- spec/
|
202
|
+
- spec/models/feature_spec.rb
|
203
|
+
- spec/models/plan_feature_spec.rb
|
204
|
+
- spec/models/plan_spec.rb
|
205
|
+
- spec/models/subscription_spec.rb
|
200
206
|
- spec/rails_helper.rb
|
201
207
|
- spec/spec_helper.rb
|
202
208
|
homepage: https://github.com/integrallis/stripe_saas
|
@@ -224,12 +230,13 @@ signing_key:
|
|
224
230
|
specification_version: 4
|
225
231
|
summary: Stripe Payments/Subscription Engine for Rails 4.
|
226
232
|
test_files:
|
227
|
-
- spec/concerns/plan_spec.rb
|
228
233
|
- spec/dummy/app/assets/javascripts/application.js
|
229
234
|
- spec/dummy/app/assets/stylesheets/application.css
|
230
235
|
- spec/dummy/app/controllers/application_controller.rb
|
231
236
|
- spec/dummy/app/helpers/application_helper.rb
|
237
|
+
- spec/dummy/app/models/feature.rb
|
232
238
|
- spec/dummy/app/models/plan.rb
|
239
|
+
- spec/dummy/app/models/plan_feature.rb
|
233
240
|
- spec/dummy/app/models/subscription.rb
|
234
241
|
- spec/dummy/app/models/user.rb
|
235
242
|
- spec/dummy/app/views/layouts/application.html.erb
|
@@ -263,9 +270,10 @@ test_files:
|
|
263
270
|
- spec/dummy/db/migrate/20150101233243_devise_create_users.rb
|
264
271
|
- spec/dummy/db/migrate/20150102001921_create_subscriptions.rb
|
265
272
|
- spec/dummy/db/migrate/20150102001930_create_plans.rb
|
273
|
+
- spec/dummy/db/migrate/20151220161809_create_features.rb
|
274
|
+
- spec/dummy/db/migrate/20151220161817_create_plan_features.rb
|
266
275
|
- spec/dummy/db/schema.rb
|
267
276
|
- spec/dummy/db/test.sqlite3
|
268
|
-
- spec/dummy/log/development.log
|
269
277
|
- spec/dummy/log/test.log
|
270
278
|
- spec/dummy/public/404.html
|
271
279
|
- spec/dummy/public/422.html
|
@@ -273,6 +281,9 @@ test_files:
|
|
273
281
|
- spec/dummy/public/favicon.ico
|
274
282
|
- spec/dummy/Rakefile
|
275
283
|
- spec/dummy/README.rdoc
|
276
|
-
- spec/
|
284
|
+
- spec/models/feature_spec.rb
|
285
|
+
- spec/models/plan_feature_spec.rb
|
286
|
+
- spec/models/plan_spec.rb
|
287
|
+
- spec/models/subscription_spec.rb
|
277
288
|
- spec/rails_helper.rb
|
278
289
|
- spec/spec_helper.rb
|