paid_up 0.11.7 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -13
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +4 -3
- data/Gemfile +29 -24
- data/README.md +22 -1
- data/Rakefile +6 -5
- data/VERSION +1 -1
- data/app/controllers/paid_up/paid_up_controller.rb +16 -9
- data/app/controllers/paid_up/plans_controller.rb +2 -0
- data/app/controllers/paid_up/subscriptions_controller.rb +58 -49
- data/app/helpers/paid_up/features_helper.rb +35 -34
- data/app/helpers/paid_up/paid_up_helper.rb +10 -8
- data/app/helpers/paid_up/plans_helper.rb +75 -55
- data/app/helpers/paid_up/subscriptions_helper.rb +17 -13
- data/app/models/paid_up/ability.rb +53 -46
- data/app/models/paid_up/plan.rb +36 -34
- data/app/models/paid_up/plan_feature_setting.rb +2 -0
- data/app/models/paid_up/unlimited.rb +2 -0
- data/app/views/paid_up/features/_abilities_table.html.haml +1 -45
- data/app/views/paid_up/features/_boolean_state.html.haml +6 -0
- data/app/views/paid_up/features/_setting_state.html.haml +13 -0
- data/app/views/paid_up/subscriptions/index.html.haml +2 -2
- data/config/initializers/stripe.rb +2 -0
- data/config/locales/en.yml +4 -1
- data/config/routes.rb +3 -1
- data/lib/generators/paid_up/install/install_generator.rb +4 -1
- data/lib/generators/paid_up/install/templates/ability.rb +2 -0
- data/lib/generators/paid_up/install/templates/initializer.rb +2 -0
- data/lib/generators/paid_up/utils.rb +2 -0
- data/lib/paid_up/configuration.rb +4 -2
- data/lib/paid_up/engine.rb +2 -0
- data/lib/paid_up/extensions/integer.rb +2 -0
- data/lib/paid_up/extensions/stripe.rb +2 -0
- data/lib/paid_up/feature.rb +10 -7
- data/lib/paid_up/feature_setting_type.rb +45 -0
- data/lib/paid_up/feature_setting_types/rolify.rb +10 -0
- data/lib/paid_up/feature_setting_types/table.rb +7 -0
- data/lib/paid_up/localization.rb +2 -0
- data/lib/paid_up/mixins/paid_for.rb +59 -47
- data/lib/paid_up/mixins/subscriber.rb +45 -101
- data/lib/paid_up/railtie.rb +2 -0
- data/lib/paid_up/ruby_version_check.rb +15 -0
- data/lib/paid_up/subscription.rb +80 -0
- data/lib/paid_up/validators/rolify_rows.rb +11 -6
- data/lib/paid_up/validators/table_rows.rb +9 -6
- data/lib/paid_up/version.rb +2 -0
- data/lib/paid_up.rb +8 -0
- data/paid_up.gemspec +108 -115
- data/spec/controllers/paid_up/plans_spec.rb +2 -0
- data/spec/controllers/paid_up/subscriptions_spec.rb +18 -11
- data/spec/dummy/Rakefile +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css.scss +6 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/models/ability.rb +2 -0
- data/spec/dummy/app/models/doodad.rb +2 -0
- data/spec/dummy/app/models/group.rb +2 -0
- data/spec/dummy/app/models/post.rb +2 -0
- data/spec/dummy/app/models/role.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.haml +13 -11
- data/spec/dummy/bin/bundle +2 -0
- data/spec/dummy/bin/rails +2 -0
- data/spec/dummy/bin/rake +2 -0
- data/spec/dummy/bin/setup +10 -8
- data/spec/dummy/config/application.rb +2 -3
- data/spec/dummy/config/boot.rb +2 -0
- data/spec/dummy/config/environment.rb +2 -0
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/test.rb +2 -4
- data/spec/dummy/config/initializers/assets.rb +2 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
- data/spec/dummy/config/initializers/devise.rb +2 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
- data/spec/dummy/config/initializers/inflections.rb +1 -0
- data/spec/dummy/config/initializers/mime_types.rb +1 -0
- data/spec/dummy/config/initializers/paid_up.rb +10 -16
- data/spec/dummy/config/initializers/rolify.rb +2 -0
- data/spec/dummy/config/initializers/session_store.rb +2 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config.ru +2 -0
- data/spec/dummy/db/schema.rb +14 -23
- data/spec/dummy/db/seeds.rb +8 -6
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/tasks/system.rake +2 -0
- data/spec/factories/doodad.rb +2 -0
- data/spec/factories/group.rb +2 -0
- data/spec/factories/plan.rb +2 -0
- data/spec/factories/plan_feature_setting.rb +2 -0
- data/spec/factories/post.rb +2 -0
- data/spec/factories/user.rb +3 -1
- data/spec/models/group_spec.rb +9 -7
- data/spec/models/paid_up/feature_spec.rb +2 -0
- data/spec/models/paid_up/plan_feature_setting_spec.rb +2 -0
- data/spec/models/paid_up/plan_spec.rb +2 -0
- data/spec/models/scope_spec.rb +9 -7
- data/spec/models/user_spec.rb +60 -58
- data/spec/paid_up_spec.rb +2 -0
- data/spec/rails_helper.rb +16 -2
- data/spec/routing/paid_up/plans_spec.rb +2 -0
- data/spec/routing/paid_up/subscription_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/controller_macros.rb +2 -0
- data/spec/support/factory_girl.rb +2 -0
- data/spec/support/loaded_site/features.rb +2 -0
- data/spec/support/loaded_site/groups.rb +2 -0
- data/spec/support/loaded_site/loaded_site.rb +2 -0
- data/spec/support/loaded_site/plans.rb +2 -0
- data/spec/support/loaded_site/posts.rb +2 -0
- data/spec/support/loaded_site/users.rb +4 -2
- data/spec/support/stripe.rb +2 -0
- data/spec/views/paid_up/plans_spec.rb +9 -7
- data/spec/views/paid_up/subscriptions_spec.rb +20 -19
- metadata +124 -90
- data/app/views/devise/confirmations/new.html.haml +0 -13
- data/app/views/devise/passwords/edit.html.haml +0 -19
- data/app/views/devise/passwords/new.html.haml +0 -14
- data/app/views/devise/registrations/_new_form.html.haml +0 -23
- data/app/views/devise/registrations/edit.html.haml +0 -39
- data/app/views/devise/registrations/new.html.haml +0 -11
- data/app/views/devise/sessions/_new_form.html.haml +0 -21
- data/app/views/devise/sessions/new.html.haml +0 -11
- data/app/views/devise/shared/_links.html.haml +0 -14
- data/app/views/devise/unlocks/new.html.haml +0 -14
- data/app/views/layouts/mailer.html.haml +0 -3
- data/app/views/layouts/mailer.text.haml +0 -1
- data/app/views/paid_up/subscription_mailer/payment_failed_email.html.haml +0 -0
- data/app/views/paid_up/subscription_mailer/payment_failed_email.text.haml +0 -0
- data/coverage/.last_run.json +0 -5
- data/coverage/.resultset.json +0 -1927
- data/spec/dummy/app/views/pages/index.html.haml +0 -1
- data/spec/dummy/config/environments/production.rb +0 -83
- data/spec/dummy/config/initializers/high_voltage.rb +0 -3
data/lib/paid_up/feature.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# PaidUp module
|
2
4
|
module PaidUp
|
3
|
-
|
5
|
+
@feature_object = {}
|
4
6
|
|
5
7
|
def self.add_feature(params)
|
6
8
|
feature = PaidUp::Feature.new(params)
|
7
|
-
|
9
|
+
@feature_object[feature.slug.to_sym] = feature
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.features
|
11
|
-
|
13
|
+
@feature_object
|
12
14
|
end
|
13
15
|
|
14
16
|
# Feature Class: Not an ActiveRecord object.
|
@@ -45,7 +47,7 @@ module PaidUp
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def feature_model_name
|
48
|
-
acceptable_setting_types = %w(
|
50
|
+
acceptable_setting_types = %w(table_rows rolify_rows)
|
49
51
|
unless acceptable_setting_types.include? setting_type
|
50
52
|
raise :no_implicit_conversion_of_type_features.l(type: setting_type)
|
51
53
|
end
|
@@ -60,6 +62,10 @@ module PaidUp
|
|
60
62
|
raw[slug.to_sym]
|
61
63
|
end
|
62
64
|
|
65
|
+
def self.find_by_slug!(slug)
|
66
|
+
find_by_slug(slug) || raise(:feature_not_found.l)
|
67
|
+
end
|
68
|
+
|
63
69
|
def self.all
|
64
70
|
raw.values
|
65
71
|
end
|
@@ -80,10 +86,7 @@ module PaidUp
|
|
80
86
|
find_all(conditions).first
|
81
87
|
end
|
82
88
|
|
83
|
-
# Define on self, since it's a class method
|
84
89
|
def self.method_missing(method_sym, *arguments, &block)
|
85
|
-
# the first argument is a Symbol, so you need to_s it if you want to
|
86
|
-
# pattern match
|
87
90
|
if method_sym.to_s =~ /^find_by_(.*)$/
|
88
91
|
find(Regexp.last_match[1].to_sym => arguments.first)
|
89
92
|
elsif method_sym.to_s =~ /^find_all_by_(.*)$/
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# PaidUp module
|
4
|
+
module PaidUp
|
5
|
+
# Feature Setting Type Class: Not an ActiveRecord object.
|
6
|
+
class FeatureSettingType
|
7
|
+
include ActiveModel::Model
|
8
|
+
include ActiveModel::AttributeMethods
|
9
|
+
|
10
|
+
attr_accessor :name, :user
|
11
|
+
delegate :plan, to: :user
|
12
|
+
|
13
|
+
def rows_unlimited?
|
14
|
+
rows_allowed == PaidUp::Unlimited.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def rows_remaining
|
18
|
+
rows_allowed - rows_count
|
19
|
+
end
|
20
|
+
|
21
|
+
def rows_allowed
|
22
|
+
plan.feature_setting name
|
23
|
+
end
|
24
|
+
|
25
|
+
def rows
|
26
|
+
scope.where(user: user)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ids
|
30
|
+
rows.ids
|
31
|
+
end
|
32
|
+
|
33
|
+
def rows_count
|
34
|
+
rows.size
|
35
|
+
end
|
36
|
+
|
37
|
+
def model
|
38
|
+
name.classify.constantize
|
39
|
+
end
|
40
|
+
|
41
|
+
def scope
|
42
|
+
model.paid_for_scope
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/paid_up/localization.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PaidUp
|
2
4
|
module Mixins
|
5
|
+
ASSOCIATION_METHODS = {
|
6
|
+
rolify_rows: :associations_for_rolify_rows,
|
7
|
+
table_rows: :associations_for_table_rows,
|
8
|
+
boolean: :true
|
9
|
+
}.freeze
|
10
|
+
|
3
11
|
# PaidFor Mixin
|
4
12
|
module PaidFor
|
5
13
|
extend ActiveSupport::Concern
|
@@ -7,41 +15,53 @@ module PaidUp
|
|
7
15
|
def paid_for(options = {})
|
8
16
|
cattr_accessor :paid_for_scope_symbol # Creates class-level instance var
|
9
17
|
|
10
|
-
|
11
|
-
|
18
|
+
extend ClassMethods
|
19
|
+
include InstanceMethods
|
12
20
|
|
13
21
|
self.paid_for_scope_symbol = options.fetch(:scope, :all)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
case feature.setting_type
|
18
|
-
when 'boolean'
|
19
|
-
# Nothing needs doing
|
20
|
-
when 'rolify_rows'
|
21
|
-
resourcify
|
22
|
-
attr_accessor :owner
|
23
|
-
when 'table_rows'
|
24
|
-
belongs_to :user
|
25
|
-
User.has_many table_name.to_sym
|
26
|
-
else
|
27
|
-
raise(
|
28
|
-
:value_is_not_a_valid_setting_type.l(
|
29
|
-
value: feature.setting_type
|
30
|
-
)
|
31
|
-
)
|
32
|
-
end
|
22
|
+
|
23
|
+
validate_feature
|
24
|
+
associations
|
33
25
|
end
|
34
26
|
|
27
|
+
# Extended by paid_for mixin
|
35
28
|
module ClassMethods
|
36
29
|
def feature
|
37
30
|
PaidUp::Feature.find_by_slug(table_name)
|
38
31
|
end
|
39
32
|
|
40
33
|
def paid_for_scope
|
41
|
-
send(
|
34
|
+
send(paid_for_scope_symbol)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def validate_feature
|
40
|
+
return true unless feature.nil?
|
41
|
+
raise(:feature_not_found_feature.l(feature: table_name))
|
42
|
+
end
|
43
|
+
|
44
|
+
def associations
|
45
|
+
setting_type = feature.setting_type
|
46
|
+
method = ASSOCIATION_METHODS[setting_type.to_sym] ||
|
47
|
+
raise(
|
48
|
+
:value_is_not_a_valid_setting_type.l(value: setting_type)
|
49
|
+
)
|
50
|
+
send(method)
|
51
|
+
end
|
52
|
+
|
53
|
+
def associations_for_rolify_rows
|
54
|
+
resourcify
|
55
|
+
attr_accessor :owner
|
56
|
+
end
|
57
|
+
|
58
|
+
def associations_for_table_rows
|
59
|
+
belongs_to :user
|
60
|
+
User.has_many table_name.to_sym
|
42
61
|
end
|
43
62
|
end
|
44
63
|
|
64
|
+
# Included by paid_for mixin
|
45
65
|
module InstanceMethods
|
46
66
|
def owners
|
47
67
|
case self.class.feature.setting_type
|
@@ -71,40 +91,32 @@ module PaidUp
|
|
71
91
|
end
|
72
92
|
|
73
93
|
def owners_records
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
.with_role(:owner, subscriber)
|
84
|
-
.paid_for_scope
|
85
|
-
.ids
|
86
|
-
else
|
87
|
-
raise(
|
88
|
-
:no_features_associated_with_table.l(
|
89
|
-
table: self.class.table_name
|
90
|
-
)
|
91
|
-
)
|
92
|
-
end
|
94
|
+
self.class.where(id: owners_records_ids)
|
95
|
+
end
|
96
|
+
|
97
|
+
def owners_records_ids
|
98
|
+
setting = self.class.feature.setting_type
|
99
|
+
.gsub('_rows', '_setting')
|
100
|
+
table_name = self.class.table_name
|
101
|
+
unless %w(table_setting rolify_setting).include? setting
|
102
|
+
raise :no_features_associated_with_table.l(table: table_name)
|
93
103
|
end
|
94
|
-
|
104
|
+
owners.map do |subscriber|
|
105
|
+
subscriber.send(setting, table_name).ids
|
106
|
+
end.flatten
|
95
107
|
end
|
96
108
|
|
97
109
|
def owners_records_count
|
98
|
-
owners_records.
|
110
|
+
owners_records.size
|
99
111
|
end
|
100
112
|
|
101
|
-
def enabled
|
113
|
+
def enabled?
|
102
114
|
if owners_enabled_count >= owners_records_count
|
103
115
|
true
|
104
116
|
else
|
105
|
-
|
106
|
-
|
107
|
-
|
117
|
+
owners_records.order(id: :asc)
|
118
|
+
.limit(owners_enabled_count)
|
119
|
+
.include? self
|
108
120
|
end
|
109
121
|
end
|
110
122
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PaidUp
|
2
4
|
module Mixins
|
3
5
|
# Subscriber Mixin
|
@@ -10,12 +12,15 @@ module PaidUp
|
|
10
12
|
has_many feature.slug.to_sym
|
11
13
|
end
|
12
14
|
|
15
|
+
delegate :plan, to: :paid_up_subscription
|
13
16
|
after_initialize :set_default_attributes, :load_stripe_data
|
17
|
+
after_save :load_stripe_data
|
14
18
|
before_save :remove_anonymous_association
|
15
19
|
before_destroy { |record| record.stripe_data.delete }
|
16
|
-
|
20
|
+
include InstanceMethods
|
17
21
|
end
|
18
22
|
|
23
|
+
# Included by subscriber mixin
|
19
24
|
module InstanceMethods
|
20
25
|
def reload(*args, &blk)
|
21
26
|
super(*args, &blk)
|
@@ -31,144 +36,71 @@ module PaidUp
|
|
31
36
|
stripe_data.present? && stripe_data.sources.all(object: 'card')
|
32
37
|
end
|
33
38
|
|
34
|
-
def subscribe_to_plan(
|
39
|
+
def subscribe_to_plan(
|
40
|
+
new_plan, stripe_token = nil, coupon = nil, trial_end = nil
|
41
|
+
)
|
35
42
|
# If there is an existing subscription
|
36
|
-
if stripe_id.present? &&
|
37
|
-
|
38
|
-
subscription.source = stripe_token
|
39
|
-
subscription.save
|
40
|
-
reload
|
41
|
-
end
|
42
|
-
if coupon_code.present?
|
43
|
-
stripe_data.coupon = coupon_code
|
44
|
-
stripe_data.save
|
45
|
-
end
|
46
|
-
if trial_end.present?
|
47
|
-
stripe_data.subscription.trial_end = trial_end
|
48
|
-
stripe_data.subscription.save
|
49
|
-
end
|
50
|
-
subscription.plan = plan_to_set.stripe_id
|
51
|
-
result = subscription.save ||
|
52
|
-
(raise(:could_not_update_subscription.l) && false)
|
43
|
+
if stripe_id.present? && paid_up_subscription.present?
|
44
|
+
paid_up_subscription.update(new_plan, stripe_token, coupon, trial_end)
|
53
45
|
else # Totally new subscription
|
54
|
-
|
55
|
-
source: stripe_token,
|
56
|
-
plan: plan_to_set.stripe_id,
|
57
|
-
email: email,
|
58
|
-
trial_end: trial_end
|
59
|
-
}
|
60
|
-
coupon_code.present? && args[:coupon] = coupon_code
|
61
|
-
customer = Stripe::Customer.create(args) ||
|
62
|
-
(raise(:could_not_create_subscription.l) && false)
|
63
|
-
|
64
|
-
# If there is an update to be made, we go ahead
|
65
|
-
if stripe_id != customer.id
|
66
|
-
result = update_attributes(stripe_id: customer.id) ||
|
67
|
-
(raise(:could_not_associate_subscription.l) && false)
|
68
|
-
else
|
69
|
-
result = true
|
70
|
-
end
|
46
|
+
paid_up_subscription.create(new_plan, stripe_token, coupon, trial_end)
|
71
47
|
end
|
72
|
-
|
48
|
+
Rails.cache.delete("#{stripe_id}/stripe_data")
|
49
|
+
reload
|
73
50
|
end
|
74
51
|
|
75
52
|
def subscribe_to_free_plan
|
76
53
|
subscribe_to_plan PaidUp::Plan.free
|
77
54
|
end
|
78
55
|
|
79
|
-
def
|
80
|
-
|
81
|
-
PaidUp::Plan.find_by_stripe_id(subscription.plan.id)
|
82
|
-
else
|
83
|
-
PaidUp::Plan.free
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def table_rows_unlimited?(table_name)
|
88
|
-
table_rows_allowed(table_name) == PaidUp::Unlimited.to_i
|
89
|
-
end
|
90
|
-
|
91
|
-
def table_rows_remaining(table_name)
|
92
|
-
table_rows_allowed(table_name) - table_rows(table_name)
|
93
|
-
end
|
94
|
-
|
95
|
-
def table_rows_allowed(table_name)
|
96
|
-
plan.feature_setting table_name
|
97
|
-
end
|
98
|
-
|
99
|
-
def table_rows(table_name)
|
100
|
-
model = table_name.classify.constantize
|
101
|
-
model.where(user: self).paid_for_scope.size
|
102
|
-
end
|
103
|
-
|
104
|
-
def rolify_rows_unlimited?(table_name)
|
105
|
-
rolify_rows_allowed(table_name) == PaidUp::Unlimited.to_i
|
106
|
-
end
|
107
|
-
|
108
|
-
def rolify_rows_remaining(table_name)
|
109
|
-
rolify_rows_allowed(table_name) - rolify_rows(table_name)
|
56
|
+
def table_setting(table_name)
|
57
|
+
PaidUp::TableFeatureSettingType.new(name: table_name, user: self)
|
110
58
|
end
|
111
59
|
|
112
|
-
def
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
def rolify_rows(table_name)
|
117
|
-
model = table_name.classify.constantize
|
118
|
-
model.with_role(:owner, self).paid_for_scope.size
|
60
|
+
def rolify_setting(table_name)
|
61
|
+
PaidUp::RolifyFeatureSettingType.new(name: table_name, user: self)
|
119
62
|
end
|
120
63
|
|
121
64
|
def plan_stripe_id
|
122
|
-
|
123
|
-
subscription.plan.id
|
65
|
+
paid_up_subscription&.stripe_data&.plan&.id
|
124
66
|
end
|
125
67
|
|
126
|
-
def
|
68
|
+
def paid_up_subscription
|
127
69
|
stripe_data.nil? && subscribe_to_free_plan
|
128
|
-
|
70
|
+
@subscription
|
129
71
|
end
|
130
72
|
|
131
|
-
def
|
73
|
+
def subscribed_to?(plan_to_check)
|
132
74
|
plan.present? && plan.id == plan_to_check.id
|
133
75
|
end
|
134
76
|
|
135
77
|
def can_upgrade_to?(plan_to_check)
|
136
78
|
plan.nil? || (
|
137
|
-
!
|
79
|
+
!subscribed_to?(plan_to_check) &&
|
138
80
|
(plan_to_check.sort_order.to_i > plan.sort_order.to_i)
|
139
81
|
)
|
140
82
|
end
|
141
83
|
|
142
84
|
def can_downgrade_to?(plan_to_check)
|
143
|
-
|
144
|
-
!
|
85
|
+
plan.present? && (
|
86
|
+
!subscribed_to?(plan_to_check) &&
|
145
87
|
(plan_to_check.sort_order.to_i < plan.sort_order.to_i)
|
146
88
|
)
|
147
89
|
end
|
148
90
|
|
149
91
|
def using_free_plan?
|
150
|
-
plan.nil? ||
|
151
|
-
|
152
|
-
(plan.stripe_id == PaidUp.configuration.free_plan_stripe_id)
|
92
|
+
plan.nil? || stripe_data.delinquent ||
|
93
|
+
plan.stripe_id == PaidUp.configuration.free_plan_stripe_id
|
153
94
|
end
|
154
95
|
|
155
96
|
private
|
156
97
|
|
157
98
|
def set_default_attributes
|
158
|
-
|
159
|
-
|
160
|
-
end
|
99
|
+
return unless new_record?
|
100
|
+
self.stripe_id = PaidUp.configuration.anonymous_customer_stripe_id
|
161
101
|
end
|
162
102
|
|
163
103
|
def load_stripe_data
|
164
|
-
working_stripe_id = if new_record?
|
165
|
-
PaidUp.configuration
|
166
|
-
.anonymous_customer_stripe_id
|
167
|
-
else
|
168
|
-
!stripe_id.present? && subscribe_to_free_plan
|
169
|
-
stripe_id
|
170
|
-
end
|
171
|
-
|
172
104
|
@customer_stripe_data = Rails.cache.fetch(
|
173
105
|
"#{working_stripe_id}/stripe_data",
|
174
106
|
expires_in: 12.hours
|
@@ -176,14 +108,26 @@ module PaidUp
|
|
176
108
|
Stripe::Customer.retrieve working_stripe_id
|
177
109
|
end
|
178
110
|
|
179
|
-
@
|
111
|
+
@subscription = PaidUp::Subscription.new(user: self)
|
112
|
+
|
113
|
+
raise(:could_not_load_subscription.l) if @customer_stripe_data.nil?
|
114
|
+
stripe_data
|
180
115
|
end
|
181
116
|
|
182
|
-
def
|
183
|
-
if
|
184
|
-
|
117
|
+
def working_stripe_id
|
118
|
+
if new_record?
|
119
|
+
PaidUp.configuration.anonymous_customer_stripe_id
|
120
|
+
else
|
121
|
+
subscribe_to_free_plan unless stripe_id.present?
|
122
|
+
stripe_id
|
185
123
|
end
|
186
124
|
end
|
125
|
+
|
126
|
+
def remove_anonymous_association
|
127
|
+
return unless stripe_id ==
|
128
|
+
PaidUp.configuration.anonymous_customer_stripe_id
|
129
|
+
self.stripe_id = nil
|
130
|
+
end
|
187
131
|
end
|
188
132
|
end
|
189
133
|
end
|
data/lib/paid_up/railtie.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if RUBY_VERSION < '2.3.0' && RUBY_ENGINE == 'ruby'
|
4
|
+
desc = if defined?(RUBY_DESCRIPTION)
|
5
|
+
RUBY_DESCRIPTION
|
6
|
+
else
|
7
|
+
"ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
|
8
|
+
end
|
9
|
+
abort <<-end_message
|
10
|
+
This version of PaidUp requires Ruby 2.3.0 or newer.
|
11
|
+
You're running
|
12
|
+
#{desc}
|
13
|
+
Please upgrade to Ruby 2.3.0 or newer to continue.
|
14
|
+
end_message
|
15
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# PaidUp module
|
4
|
+
module PaidUp
|
5
|
+
# Subscription Class: Not an ActiveRecord object.
|
6
|
+
class Subscription
|
7
|
+
include ActiveModel::Model
|
8
|
+
include ActiveModel::AttributeMethods
|
9
|
+
|
10
|
+
attr_accessor :stripe_data, :user
|
11
|
+
delegate :status, :trial_start, :trial_end, :current_period_start,
|
12
|
+
:current_period_end, :cancel_at_period_end, to: :stripe_data
|
13
|
+
delegate :email, :stripe_id, to: :user
|
14
|
+
|
15
|
+
def initialize(args)
|
16
|
+
super args
|
17
|
+
self.stripe_data = user.stripe_data.subscriptions.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def plan
|
21
|
+
if stripe_data&.plan&.id.present?
|
22
|
+
PaidUp::Plan.find_by_stripe_id(stripe_data.plan.id)
|
23
|
+
else
|
24
|
+
PaidUp::Plan.free
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(plan, stripe_token = nil, coupon = nil, trial_end = nil)
|
29
|
+
update_stripe_token(stripe_token)
|
30
|
+
update_coupon(coupon)
|
31
|
+
update_trial_end(trial_end)
|
32
|
+
update_plan(plan)
|
33
|
+
stripe_data.save || raise(:could_not_update_plan.l)
|
34
|
+
end
|
35
|
+
|
36
|
+
def create(plan, stripe_token = nil, coupon = nil, trial_end = nil)
|
37
|
+
customer = Stripe::Customer.create(source: stripe_token, email: email,
|
38
|
+
plan: plan.stripe_id, coupon: coupon,
|
39
|
+
trial_end: trial_end) ||
|
40
|
+
raise(:could_not_create_subscription.l)
|
41
|
+
|
42
|
+
# If there is an update to be made, we go ahead
|
43
|
+
return true if stripe_id == customer.id
|
44
|
+
user.update_attributes(stripe_id: customer.id) ||
|
45
|
+
raise(:could_not_associate_subscription.l)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def update_stripe_token(stripe_token)
|
51
|
+
return unless stripe_token.present?
|
52
|
+
# The customer has entered a new card
|
53
|
+
# We need to update the info on the Stripe API.
|
54
|
+
stripe_data.source = stripe_token
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_coupon(coupon)
|
58
|
+
return unless coupon.present?
|
59
|
+
# The customer has entered a new coupon code
|
60
|
+
# We need to update the stripe customer.
|
61
|
+
stripe_data.coupon = coupon
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_trial_end(trial_end)
|
65
|
+
return unless trial_end.present?
|
66
|
+
# The customer has cancelled or otherwise altered their trial_end
|
67
|
+
# We need to update the info on the Stripe API.
|
68
|
+
# stripe_data.stripe_data.trial_end = trial_end
|
69
|
+
# stripe_data.stripe_data.save!
|
70
|
+
stripe_data.trial_end = trial_end
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_plan(new_plan)
|
74
|
+
return unless new_plan.present?
|
75
|
+
# The customer has changed plans
|
76
|
+
# We need to update the info on the Stripe API.
|
77
|
+
stripe_data.plan = new_plan.stripe_id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,17 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PaidUp
|
2
4
|
module Validators
|
3
5
|
# RolifyRows Validator
|
4
6
|
class RolifyRows < ActiveModel::Validator
|
5
7
|
def validate(record)
|
8
|
+
found_in = options[:found_in]
|
6
9
|
if record.send(options[:field]) == options[:comparison] &&
|
7
|
-
!
|
8
|
-
|
9
|
-
)
|
10
|
-
record.errors[
|
11
|
-
options[:found_in]
|
12
|
-
] << :when_using_rolify_rows_table_must_exist.l
|
10
|
+
!found_in_valid?(record, found_in)
|
11
|
+
record.errors[found_in] << :when_using_rolify_rows_table_must_exist.l
|
13
12
|
end
|
14
13
|
end
|
14
|
+
|
15
|
+
def found_in_valid?(record, found_in)
|
16
|
+
ActiveRecord::Base.connection.data_source_exists?(
|
17
|
+
record.send(found_in)
|
18
|
+
)
|
19
|
+
end
|
15
20
|
end
|
16
21
|
end
|
17
22
|
end
|
@@ -1,17 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PaidUp
|
2
4
|
module Validators
|
3
5
|
# Table Rows validator
|
4
6
|
class TableRows < ActiveModel::Validator
|
5
7
|
def validate(record)
|
8
|
+
found_in = options[:found_in]
|
6
9
|
if record.send(options[:field]) == options[:comparison] &&
|
7
|
-
!
|
8
|
-
|
9
|
-
)
|
10
|
-
record.errors[
|
11
|
-
options[:found_in]
|
12
|
-
] << :when_using_table_rows_table_must_exist.l
|
10
|
+
!found_in_valid?(record, found_in)
|
11
|
+
record.errors[found_in] << :when_using_table_rows_table_must_exist.l
|
13
12
|
end
|
14
13
|
end
|
14
|
+
|
15
|
+
def found_in_valid?(record, found_in)
|
16
|
+
ActiveRecord::Base.connection.data_source_exists? record.send(found_in)
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
data/lib/paid_up/version.rb
CHANGED
data/lib/paid_up.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# PaidUp Module
|
2
4
|
module PaidUp
|
3
5
|
require 'active_record/railtie'
|
@@ -18,10 +20,13 @@ module PaidUp
|
|
18
20
|
|
19
21
|
require 'paid_up/configuration'
|
20
22
|
require 'paid_up/feature'
|
23
|
+
require 'paid_up/feature_setting_type'
|
24
|
+
require 'paid_up/subscription'
|
21
25
|
require 'paid_up/railtie'
|
22
26
|
require 'paid_up/engine'
|
23
27
|
require 'paid_up/localization'
|
24
28
|
require 'paid_up/version'
|
29
|
+
require 'paid_up/ruby_version_check'
|
25
30
|
|
26
31
|
require 'paid_up/extensions/stripe'
|
27
32
|
require 'paid_up/extensions/integer'
|
@@ -29,6 +34,9 @@ module PaidUp
|
|
29
34
|
require 'paid_up/mixins/subscriber'
|
30
35
|
require 'paid_up/mixins/paid_for'
|
31
36
|
|
37
|
+
require 'paid_up/feature_setting_types/table'
|
38
|
+
require 'paid_up/feature_setting_types/rolify'
|
39
|
+
|
32
40
|
require 'haml-rails'
|
33
41
|
require 'bootstrap_leather'
|
34
42
|
|