Class: PricingPlans::LimitChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/pricing_plans/limit_checker.rb

Class Method Summary collapse

Class Method Details

.after_limit_action(plan_owner, limit_key) ⇒ Object

Keep short helpers undocumented; public API is plan_limit_* aliases



48
49
50
51
52
53
54
# File 'lib/pricing_plans/limit_checker.rb', line 48

def after_limit_action(plan_owner, limit_key)
  plan = PlanResolver.effective_plan_for(plan_owner)
  limit_config = plan&.limit_for(limit_key)
  return :block_usage unless limit_config

  limit_config[:after_limit]
end

.current_usage_for(plan_owner, limit_key, limit_config = nil) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/pricing_plans/limit_checker.rb', line 65

def current_usage_for(plan_owner, limit_key, limit_config = nil)
  limit_config ||= begin
    plan = PlanResolver.effective_plan_for(plan_owner)
    plan&.limit_for(limit_key)
  end

  return 0 unless limit_config

  if limit_config[:per]
    # Per-period allowance - check usage table
    per_period_usage(plan_owner, limit_key)
  else
    # Persistent cap - count live objects
    persistent_usage(plan_owner, limit_key)
  end
end

.limit_amount(plan_owner, limit_key) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/pricing_plans/limit_checker.rb', line 56

def limit_amount(plan_owner, limit_key)
  plan = PlanResolver.effective_plan_for(plan_owner)
  limit_config = plan&.limit_for(limit_key)
  # BREAKING CHANGE: Undefined limits now default to 0 (blocked) instead of :unlimited
  return 0 unless limit_config

  limit_config[:to]
end

.percent_used(plan_owner, limit_key) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/pricing_plans/limit_checker.rb', line 34

def percent_used(plan_owner, limit_key)
  plan = PlanResolver.effective_plan_for(plan_owner)
  limit_config = plan&.limit_for(limit_key)
  return 0.0 unless limit_config

  limit_amount = limit_config[:to]
  return 0.0 if limit_amount == :unlimited || limit_amount.zero?

  current_usage = current_usage_for(plan_owner, limit_key, limit_config)
  [(current_usage.to_f / limit_amount) * 100, 100.0].min
end

.plan_limit_percent_used(plan_owner, limit_key) ⇒ Object



11
12
13
# File 'lib/pricing_plans/limit_checker.rb', line 11

def plan_limit_percent_used(plan_owner, limit_key)
  percent_used(plan_owner, limit_key)
end

.plan_limit_remaining(plan_owner, limit_key) ⇒ Object

English-y aliases used widely across helpers/tests



7
8
9
# File 'lib/pricing_plans/limit_checker.rb', line 7

def plan_limit_remaining(plan_owner, limit_key)
  remaining(plan_owner, limit_key)
end

.remaining(plan_owner, limit_key) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/pricing_plans/limit_checker.rb', line 20

def remaining(plan_owner, limit_key)
  plan = PlanResolver.effective_plan_for(plan_owner)
  limit_config = plan&.limit_for(limit_key)
  # BREAKING CHANGE: Undefined limits now default to 0 (blocked) instead of :unlimited
  # This is secure-by-default: if a plan doesn't define a limit, access is blocked
  return 0 unless limit_config

  limit_amount = limit_config[:to]
  return :unlimited if limit_amount == :unlimited

  current_usage = current_usage_for(plan_owner, limit_key, limit_config)
  [0, limit_amount - current_usage].max
end

.should_warn?(plan_owner, limit_key) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/pricing_plans/limit_checker.rb', line 90

def should_warn?(plan_owner, limit_key)
  percent = percent_used(plan_owner, limit_key)
  thresholds = warning_thresholds(plan_owner, limit_key)

  # Find the highest threshold that has been crossed
  crossed_threshold = thresholds.select { |t| percent >= (t * 100) }.max
  return nil unless crossed_threshold

  # Check if we've already warned for this threshold
  state = enforcement_state(plan_owner, limit_key)
  last_threshold = state&.last_warning_threshold

  # Return the threshold if this is a new higher threshold, nil otherwise
  crossed_threshold > (last_threshold || 0) ? crossed_threshold : nil
end

.warning_thresholds(plan_owner, limit_key) ⇒ Object



82
83
84
85
86
87
88
# File 'lib/pricing_plans/limit_checker.rb', line 82

def warning_thresholds(plan_owner, limit_key)
  plan = PlanResolver.effective_plan_for(plan_owner)
  limit_config = plan&.limit_for(limit_key)
  return [] unless limit_config

  limit_config[:warn_at] || []
end

.within_limit?(plan_owner, limit_key, by: 1) ⇒ Boolean

Returns:

  • (Boolean)


14
15
16
17
18
# File 'lib/pricing_plans/limit_checker.rb', line 14

def within_limit?(plan_owner, limit_key, by: 1)
  remaining_amount = remaining(plan_owner, limit_key)
  return true if remaining_amount == :unlimited
  remaining_amount >= by
end