Module: Profitable
- Extended by:
- ActionView::Helpers::NumberHelper, JsonHelpers
- Defined in:
- lib/profitable/error.rb,
lib/profitable/engine.rb,
lib/profitable/metrics.rb,
lib/profitable/version.rb,
lib/profitable/json_helpers.rb,
lib/profitable/mrr_calculator.rb,
lib/profitable/numeric_result.rb,
lib/profitable/processors/base.rb,
app/controllers/profitable/base_controller.rb,
lib/profitable/processors/stripe_processor.rb,
lib/profitable/processors/braintree_processor.rb,
app/controllers/profitable/dashboard_controller.rb,
lib/profitable/processors/paddle_billing_processor.rb,
lib/profitable/processors/paddle_classic_processor.rb,
sig/profitable.rbs
Defined Under Namespace
Modules: JsonHelpers, Processors
Classes: BaseController, DashboardController, Engine, Error, MrrCalculator, NumericResult
Constant Summary
collapse
- TRIAL_SUBSCRIPTION_STATUSES =
Pay exposes some processor-specific status variants beyond the core generic list.
We normalize them into business-meaningful groups so current-state metrics,
historical event metrics, and churn denominators all behave consistently.
- Trial statuses bill nothing until the trial actually ends (Stripe: trialing,
Lemon Squeezy: on_trial).
- Churned statuses stop billing at ends_at (Stripe: canceled, Paddle Classic:
deleted, Braintree/Lemon Squeezy: expired, legacy Pay: ended/cancelled).
- Never-billable statuses either failed to start billing (Stripe: incomplete,
incomplete_expired, unpaid) or have not started billing yet (Braintree: pending).
['trialing', 'on_trial'].freeze
- CHURNED_STATUSES =
['canceled', 'cancelled', 'ended', 'deleted', 'expired'].freeze
- NEVER_BILLABLE_SUBSCRIPTION_STATUSES =
['incomplete', 'incomplete_expired', 'unpaid', 'pending'].freeze
- DEFAULT_PERIOD =
30.days
- MRR_MILESTONES =
[5, 10, 20, 30, 50, 75, 100, 200, 300, 400, 500, 1_000, 2_000, 3_000, 5_000, 10_000, 20_000, 30_000, 50_000, 83_333, 100_000, 250_000, 500_000, 1_000_000, 5_000_000, 10_000_000, 25_000_000, 50_000_000, 75_000_000, 100_000_000]
- VERSION =
"0.6.0"
Class Method Summary
collapse
-
.active_subscribers ⇒ Object
Customers with subscriptions that are billable right now.
-
.all_time_revenue ⇒ Object
-
.arr ⇒ Object
Annual Recurring Revenue (ARR) based on the current recurring base.
-
.average_revenue_per_customer ⇒ Object
-
.churn(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.churned_customers(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.churned_mrr(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.daily_summary(days: 30) ⇒ Object
-
.estimated_arr_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
-
.estimated_revenue_run_rate_valuation(multiplier = nil, at: nil, multiple: nil, in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.estimated_ttm_revenue_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
-
.estimated_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
Backwards-compatible ARR-multiple heuristic for a quick valuation estimate.
-
.lifetime_value ⇒ Object
-
.monthly_summary(months: 12) ⇒ Object
-
.mrr ⇒ Object
Monthly Recurring Revenue (MRR) from subscriptions that are billable right now.
-
.mrr_at(date) ⇒ Object
Historical MRR snapshot from subscriptions that were billable at the given date.
-
.mrr_growth(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.mrr_growth_rate(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.new_customers(in_the_last: DEFAULT_PERIOD) ⇒ Object
First-time customers added in the period, based on first monetization date rather than signup date.
-
.new_mrr(in_the_last: DEFAULT_PERIOD) ⇒ Object
Full monthly value of subscriptions that became billable in the period.
-
.new_subscribers(in_the_last: DEFAULT_PERIOD) ⇒ Object
Customers whose subscriptions first became billable in the period.
-
.period_data(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.recurring_revenue_in_period(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.recurring_revenue_percentage(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.revenue_in_period(in_the_last: DEFAULT_PERIOD) ⇒ Object
Historical revenue collected over a rolling period.
-
.revenue_run_rate(in_the_last: DEFAULT_PERIOD) ⇒ Object
-
.time_to_next_mrr_milestone ⇒ Object
-
.total_customers ⇒ Object
Customers who have actually monetized: either a paid charge or a subscription that has crossed into a billable state.
-
.total_subscribers ⇒ Object
Customers who have ever had a paid subscription.
-
.ttm ⇒ Object
Founder-friendly shorthand for trailing-twelve-month revenue.
-
.ttm_revenue ⇒ Object
Trailing twelve-month revenue reflects actual cash collected in the last year.
Class Method Details
.active_subscribers ⇒ Object
Customers with subscriptions that are billable right now.
Excludes free trials, paused subscriptions, and churned subscriptions.
116
117
118
|
# File 'lib/profitable/metrics.rb', line 116
def active_subscribers
NumericResult.new(calculate_active_subscribers, :integer)
end
|
.all_time_revenue ⇒ Object
47
48
49
|
# File 'lib/profitable/metrics.rb', line 47
def all_time_revenue
NumericResult.new(calculate_all_time_revenue)
end
|
.arr ⇒ Object
Annual Recurring Revenue (ARR) based on the current recurring base.
This is today's MRR annualized, not historical 12-month revenue.
39
40
41
|
# File 'lib/profitable/metrics.rb', line 39
def arr
NumericResult.new(calculate_arr)
end
|
.average_revenue_per_customer ⇒ Object
146
147
148
|
# File 'lib/profitable/metrics.rb', line 146
def average_revenue_per_customer
NumericResult.new(calculate_average_revenue_per_customer)
end
|
.churn(in_the_last: DEFAULT_PERIOD) ⇒ Object
43
44
45
|
# File 'lib/profitable/metrics.rb', line 43
def churn(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_churn(in_the_last), :percentage)
end
|
.churned_customers(in_the_last: DEFAULT_PERIOD) ⇒ Object
132
133
134
|
# File 'lib/profitable/metrics.rb', line 132
def churned_customers(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_churned_customers(in_the_last), :integer)
end
|
.churned_mrr(in_the_last: DEFAULT_PERIOD) ⇒ Object
142
143
144
|
# File 'lib/profitable/metrics.rb', line 142
def churned_mrr(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_churned_mrr(in_the_last))
end
|
.daily_summary(days: 30) ⇒ Object
170
171
172
|
# File 'lib/profitable/metrics.rb', line 170
def daily_summary(days: 30)
calculate_daily_summary(days)
end
|
.estimated_arr_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
88
89
90
91
|
# File 'lib/profitable/metrics.rb', line 88
def estimated_arr_valuation(multiplier = nil, at: nil, multiple: nil)
actual_multiplier = multiplier || at || multiple || 3
NumericResult.new(calculate_estimated_valuation_from(arr.to_i, actual_multiplier))
end
|
.estimated_revenue_run_rate_valuation(multiplier = nil, at: nil, multiple: nil, in_the_last: DEFAULT_PERIOD) ⇒ Object
98
99
100
101
|
# File 'lib/profitable/metrics.rb', line 98
def estimated_revenue_run_rate_valuation(multiplier = nil, at: nil, multiple: nil, in_the_last: DEFAULT_PERIOD)
actual_multiplier = multiplier || at || multiple || 3
NumericResult.new(calculate_estimated_valuation_from(revenue_run_rate(in_the_last:).to_i, actual_multiplier))
end
|
.estimated_ttm_revenue_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
93
94
95
96
|
# File 'lib/profitable/metrics.rb', line 93
def estimated_ttm_revenue_valuation(multiplier = nil, at: nil, multiple: nil)
actual_multiplier = multiplier || at || multiple || 3
NumericResult.new(calculate_estimated_valuation_from(ttm_revenue.to_i, actual_multiplier))
end
|
.estimated_valuation(multiplier = nil, at: nil, multiple: nil) ⇒ Object
Backwards-compatible ARR-multiple heuristic for a quick valuation estimate.
This is intentionally simple and should not be treated as a market appraisal.
84
85
86
|
# File 'lib/profitable/metrics.rb', line 84
def estimated_valuation(multiplier = nil, at: nil, multiple: nil)
estimated_arr_valuation(multiplier, at:, multiple:)
end
|
.lifetime_value ⇒ Object
150
151
152
|
# File 'lib/profitable/metrics.rb', line 150
def lifetime_value
NumericResult.new(calculate_lifetime_value)
end
|
.monthly_summary(months: 12) ⇒ Object
166
167
168
|
# File 'lib/profitable/metrics.rb', line 166
def monthly_summary(months: 12)
calculate_monthly_summary(months)
end
|
.mrr ⇒ Object
Monthly Recurring Revenue (MRR) from subscriptions that are billable right now.
This is a current recurring run-rate metric, useful for operating momentum
and near-term subscription changes.
28
29
30
|
# File 'lib/profitable/metrics.rb', line 28
def mrr
NumericResult.new(MrrCalculator.calculate)
end
|
.mrr_at(date) ⇒ Object
Historical MRR snapshot from subscriptions that were billable at the given date.
33
34
35
|
# File 'lib/profitable/metrics.rb', line 33
def mrr_at(date)
NumericResult.new(calculate_mrr_at(date))
end
|
.mrr_growth(in_the_last: DEFAULT_PERIOD) ⇒ Object
154
155
156
|
# File 'lib/profitable/metrics.rb', line 154
def mrr_growth(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_mrr_growth(in_the_last))
end
|
.mrr_growth_rate(in_the_last: DEFAULT_PERIOD) ⇒ Object
158
159
160
|
# File 'lib/profitable/metrics.rb', line 158
def mrr_growth_rate(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_mrr_growth_rate(in_the_last), :percentage)
end
|
.new_customers(in_the_last: DEFAULT_PERIOD) ⇒ Object
First-time customers added in the period, based on first monetization date
rather than signup date.
122
123
124
|
# File 'lib/profitable/metrics.rb', line 122
def new_customers(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_new_customers(in_the_last), :integer)
end
|
.new_mrr(in_the_last: DEFAULT_PERIOD) ⇒ Object
Full monthly value of subscriptions that became billable in the period.
This is a flow metric, so it still counts subscriptions that churned later in the same window.
138
139
140
|
# File 'lib/profitable/metrics.rb', line 138
def new_mrr(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_new_mrr(in_the_last))
end
|
.new_subscribers(in_the_last: DEFAULT_PERIOD) ⇒ Object
Customers whose subscriptions first became billable in the period.
Trial starts do not count until the trial ends.
128
129
130
|
# File 'lib/profitable/metrics.rb', line 128
def new_subscribers(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_new_subscribers(in_the_last), :integer)
end
|
.period_data(in_the_last: DEFAULT_PERIOD) ⇒ Object
174
175
176
|
# File 'lib/profitable/metrics.rb', line 174
def period_data(in_the_last: DEFAULT_PERIOD)
calculate_period_data(in_the_last)
end
|
.recurring_revenue_in_period(in_the_last: DEFAULT_PERIOD) ⇒ Object
70
71
72
|
# File 'lib/profitable/metrics.rb', line 70
def recurring_revenue_in_period(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_recurring_revenue_in_period(in_the_last))
end
|
.recurring_revenue_percentage(in_the_last: DEFAULT_PERIOD) ⇒ Object
74
75
76
|
# File 'lib/profitable/metrics.rb', line 74
def recurring_revenue_percentage(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_recurring_revenue_percentage(in_the_last), :percentage)
end
|
.revenue_in_period(in_the_last: DEFAULT_PERIOD) ⇒ Object
Historical revenue collected over a rolling period.
Unlike ARR, this is trailing actual revenue rather than a projection.
66
67
68
|
# File 'lib/profitable/metrics.rb', line 66
def revenue_in_period(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_revenue_in_period(in_the_last))
end
|
.revenue_run_rate(in_the_last: DEFAULT_PERIOD) ⇒ Object
78
79
80
|
# File 'lib/profitable/metrics.rb', line 78
def revenue_run_rate(in_the_last: DEFAULT_PERIOD)
NumericResult.new(calculate_revenue_run_rate(in_the_last))
end
|
.time_to_next_mrr_milestone ⇒ Object
162
163
164
|
# File 'lib/profitable/metrics.rb', line 162
def time_to_next_mrr_milestone
NumericResult.new(calculate_time_to_next_mrr_milestone, :string)
end
|
.total_customers ⇒ Object
Customers who have actually monetized: either a paid charge or a subscription
that has crossed into a billable state.
105
106
107
|
# File 'lib/profitable/metrics.rb', line 105
def total_customers
NumericResult.new(calculate_total_customers, :integer)
end
|
.total_subscribers ⇒ Object
Customers who have ever had a paid subscription. Trial-only subscriptions do not count.
110
111
112
|
# File 'lib/profitable/metrics.rb', line 110
def total_subscribers
NumericResult.new(calculate_total_subscribers, :integer)
end
|
.ttm ⇒ Object
Founder-friendly shorthand for trailing-twelve-month revenue.
We keep the explicit ttm_revenue name as the canonical API because bare
"TTM" is ambiguous in finance once profit metrics enter the picture.
60
61
62
|
# File 'lib/profitable/metrics.rb', line 60
def ttm
ttm_revenue
end
|
.ttm_revenue ⇒ Object
Trailing twelve-month revenue reflects actual cash collected in the last year.
It complements ARR, which annualizes the current recurring base.
53
54
55
|
# File 'lib/profitable/metrics.rb', line 53
def ttm_revenue
revenue_in_period(in_the_last: 12.months)
end
|