Module: PricingPlans::PlanOwner
- Defined in:
- lib/pricing_plans/plan_owner.rb
Overview
Mix-in for the configured plan owner class (e.g., Organization)
Provides readable, owner-centric helpers.
Defined Under Namespace
Modules: ClassMethods, HasManyInterceptor
Class Method Summary
collapse
Instance Method Summary
collapse
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, &block) ⇒ Object
Syntactic sugar for feature checks:
Allows calls like plan_owner.plan_allows_api_access? which map to
plan_owner.plan_allows?(:api_access).
241
242
243
244
245
246
247
|
# File 'lib/pricing_plans/plan_owner.rb', line 241
def method_missing(method_name, *args, &block)
if (m = method_name.to_s.match(/^plan_allows_(.+)\?$/))
feature_key = m[1].to_sym
return plan_allows?(feature_key)
end
super
end
|
Class Method Details
.define_limit_sugar_methods(plan_owner_class, limit_key) ⇒ Object
Define English-y sugar methods on the plan owner for a specific limit key.
Idempotent: skips if methods already exist.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
# File 'lib/pricing_plans/plan_owner.rb', line 14
def self.define_limit_sugar_methods(plan_owner_class, limit_key)
key = limit_key.to_sym
within_m = :"#{key}_within_plan_limits?"
remaining_m = :"#{key}_remaining"
percent_m = :"#{key}_percent_used"
grace_active_m = :"#{key}_grace_active?"
grace_ends_m = :"#{key}_grace_ends_at"
blocked_m = :"#{key}_blocked?"
unless plan_owner_class.method_defined?(within_m)
plan_owner_class.define_method(within_m) do |by: 1|
LimitChecker.within_limit?(self, key, by: by)
end
end
unless plan_owner_class.method_defined?(remaining_m)
plan_owner_class.define_method(remaining_m) do
LimitChecker.plan_limit_remaining(self, key)
end
end
unless plan_owner_class.method_defined?(percent_m)
plan_owner_class.define_method(percent_m) do
LimitChecker.plan_limit_percent_used(self, key)
end
end
unless plan_owner_class.method_defined?(grace_active_m)
plan_owner_class.define_method(grace_active_m) do
GraceManager.grace_active?(self, key)
end
end
unless plan_owner_class.method_defined?(grace_ends_m)
plan_owner_class.define_method(grace_ends_m) do
GraceManager.grace_ends_at(self, key)
end
end
unless plan_owner_class.method_defined?(blocked_m)
plan_owner_class.define_method(blocked_m) do
GraceManager.should_block?(self, key)
end
end
end
|
.included(base) ⇒ Object
7
8
9
10
|
# File 'lib/pricing_plans/plan_owner.rb', line 7
def self.included(base)
base.extend(ClassMethods)
base.singleton_class.prepend HasManyInterceptor
end
|
Instance Method Details
#any_grace_active_for?(*limit_keys) ⇒ Boolean
Aggregate helpers across multiple limit keys
294
295
296
|
# File 'lib/pricing_plans/plan_owner.rb', line 294
def any_grace_active_for?(*limit_keys)
limit_keys.flatten.any? { |k| GraceManager.grace_active?(self, k) }
end
|
#approaching_limit?(limit_key, at: nil) ⇒ Boolean
350
351
352
|
# File 'lib/pricing_plans/plan_owner.rb', line 350
def approaching_limit?(limit_key, at: nil)
PricingPlans.approaching_limit?(self, limit_key, at: at)
end
|
#assign_pricing_plan!(plan_key, source: "manual") ⇒ Object
224
225
226
|
# File 'lib/pricing_plans/plan_owner.rb', line 224
def assign_pricing_plan!(plan_key, source: "manual")
Assignment.assign_plan_to(self, plan_key, source: source)
end
|
#attention_required_for_limit?(limit_key) ⇒ Boolean
346
347
348
|
# File 'lib/pricing_plans/plan_owner.rb', line 346
def attention_required_for_limit?(limit_key)
PricingPlans.attention_required?(self, limit_key)
end
|
#current_pricing_plan ⇒ Object
#current_pricing_plan_resolution ⇒ Object
201
202
203
|
# File 'lib/pricing_plans/plan_owner.rb', line 201
def current_pricing_plan_resolution
PlanResolver.resolution_for(self)
end
|
#current_pricing_plan_source ⇒ Object
205
206
207
|
# File 'lib/pricing_plans/plan_owner.rb', line 205
def current_pricing_plan_source
current_pricing_plan_resolution.source
end
|
#earliest_grace_ends_at_for(*limit_keys) ⇒ Object
298
299
300
301
|
# File 'lib/pricing_plans/plan_owner.rb', line 298
def earliest_grace_ends_at_for(*limit_keys)
times = limit_keys.flatten.map { |k| GraceManager.grace_ends_at(self, k) }.compact
times.min
end
|
#grace_active_for?(limit_key) ⇒ Boolean
Per-limit grace helpers managed by PricingPlans
271
272
273
|
# File 'lib/pricing_plans/plan_owner.rb', line 271
def grace_active_for?(limit_key)
GraceManager.grace_active?(self, limit_key)
end
|
#grace_ends_at_for(limit_key) ⇒ Object
275
276
277
|
# File 'lib/pricing_plans/plan_owner.rb', line 275
def grace_ends_at_for(limit_key)
GraceManager.grace_ends_at(self, limit_key)
end
|
#grace_remaining_days_for(limit_key) ⇒ Object
285
286
287
|
# File 'lib/pricing_plans/plan_owner.rb', line 285
def grace_remaining_days_for(limit_key)
(grace_remaining_seconds_for(limit_key) / 86_400.0).ceil
end
|
#grace_remaining_seconds_for(limit_key) ⇒ Object
279
280
281
282
283
|
# File 'lib/pricing_plans/plan_owner.rb', line 279
def grace_remaining_seconds_for(limit_key)
ends_at = grace_ends_at_for(limit_key)
return 0 unless ends_at
[0, (ends_at - Time.current).to_i].max
end
|
#has_plan_assignment? ⇒ Boolean
214
215
216
217
|
# File 'lib/pricing_plans/plan_owner.rb', line 214
def has_plan_assignment?
return false unless respond_to?(:id) && id.present?
Assignment.exists?(plan_owner_type: self.class.name, plan_owner_id: id)
end
|
#limit(limit_key) ⇒ Object
Rails-y wrappers for usage/status (defaults to all configured limits)
304
305
306
|
# File 'lib/pricing_plans/plan_owner.rb', line 304
def limit(limit_key)
PricingPlans.status(self, limits: [limit_key]).first
end
|
#limit_alert(limit_key) ⇒ Object
Returns the pure-data alert view model for a single limit key
360
361
362
|
# File 'lib/pricing_plans/plan_owner.rb', line 360
def limit_alert(limit_key)
PricingPlans.alert_for(self, limit_key)
end
|
#limit_message(limit_key) ⇒ Object
338
339
340
|
# File 'lib/pricing_plans/plan_owner.rb', line 338
def limit_message(limit_key)
PricingPlans.message_for(self, limit_key)
end
|
#limit_overage(limit_key) ⇒ Object
342
343
344
|
# File 'lib/pricing_plans/plan_owner.rb', line 342
def limit_overage(limit_key)
PricingPlans.overage_for(self, limit_key)
end
|
#limit_severity(limit_key) ⇒ Object
View-friendly, English-like convenience helpers (pure data decisions)
334
335
336
|
# File 'lib/pricing_plans/plan_owner.rb', line 334
def limit_severity(limit_key)
PricingPlans.severity_for(self, limit_key)
end
|
#limits(*limit_keys) ⇒ Object
308
309
310
311
|
# File 'lib/pricing_plans/plan_owner.rb', line 308
def limits(*limit_keys)
keys = normalize_limit_keys(limit_keys)
PricingPlans.status(self, limits: keys)
end
|
#limits_message(*limit_keys) ⇒ Object
322
323
324
325
|
# File 'lib/pricing_plans/plan_owner.rb', line 322
def limits_message(*limit_keys)
keys = normalize_limit_keys(limit_keys)
PricingPlans.combine_messages_for(self, *keys)
end
|
#limits_overview(*limit_keys) ⇒ Object
Global overview for banner building
328
329
330
331
|
# File 'lib/pricing_plans/plan_owner.rb', line 328
def limits_overview(*limit_keys)
keys = normalize_limit_keys(limit_keys)
PricingPlans.overview_for(self, *keys)
end
|
#limits_severity(*limit_keys) ⇒ Object
317
318
319
320
|
# File 'lib/pricing_plans/plan_owner.rb', line 317
def limits_severity(*limit_keys)
keys = normalize_limit_keys(limit_keys)
PricingPlans.highest_severity_for(self, *keys)
end
|
#limits_summary(*limit_keys) ⇒ Object
313
314
315
|
# File 'lib/pricing_plans/plan_owner.rb', line 313
def limits_summary(*limit_keys)
limits(*limit_keys)
end
|
#on_free_plan? ⇒ Boolean
209
210
211
212
|
# File 'lib/pricing_plans/plan_owner.rb', line 209
def on_free_plan?
plan = current_pricing_plan || PricingPlans::Registry.default_plan
plan&.free? || false
end
|
#pay_on_grace_period? ⇒ Boolean
265
266
267
268
|
# File 'lib/pricing_plans/plan_owner.rb', line 265
def pay_on_grace_period?
sub = PaySupport.current_subscription_for(self)
!!(sub && sub.respond_to?(:on_grace_period?) && sub.on_grace_period?)
end
|
#pay_on_trial? ⇒ Boolean
260
261
262
263
|
# File 'lib/pricing_plans/plan_owner.rb', line 260
def pay_on_trial?
sub = PaySupport.current_subscription_for(self)
!!(sub && sub.respond_to?(:on_trial?) && sub.on_trial?)
end
|
#pay_subscription_active? ⇒ Boolean
Pay (Stripe) convenience wrappers (return false/nil if Pay not available)
Pay (Stripe) state — billing-facing, NOT used by our enforcement logic
#plan_allows?(feature_key) ⇒ Boolean
233
234
235
236
|
# File 'lib/pricing_plans/plan_owner.rb', line 233
def plan_allows?(feature_key)
plan = current_pricing_plan
plan&.allows_feature?(feature_key) || false
end
|
#plan_assignment ⇒ Object
219
220
221
222
|
# File 'lib/pricing_plans/plan_owner.rb', line 219
def plan_assignment
return nil unless respond_to?(:id) && id.present?
Assignment.find_by(plan_owner_type: self.class.name, plan_owner_id: id)
end
|
#plan_blocked_for?(limit_key) ⇒ Boolean
289
290
291
|
# File 'lib/pricing_plans/plan_owner.rb', line 289
def plan_blocked_for?(limit_key)
GraceManager.should_block?(self, limit_key)
end
|
#plan_cta ⇒ Object
355
356
357
|
# File 'lib/pricing_plans/plan_owner.rb', line 355
def plan_cta
PricingPlans.cta_for(self)
end
|
#plan_limit_percent_used(limit_key) ⇒ Object
#plan_limit_remaining(limit_key) ⇒ Object
#remove_pricing_plan! ⇒ Object
#respond_to_missing?(method_name, include_private = false) ⇒ Boolean
249
250
251
252
|
# File 'lib/pricing_plans/plan_owner.rb', line 249
def respond_to_missing?(method_name, include_private = false)
return true if method_name.to_s.start_with?("plan_allows_") && method_name.to_s.end_with?("?")
super
end
|
#within_plan_limits?(limit_key, by: 1) ⇒ Boolean
185
186
187
|
# File 'lib/pricing_plans/plan_owner.rb', line 185
def within_plan_limits?(limit_key, by: 1)
LimitChecker.within_limit?(self, limit_key, by: by)
end
|