Skip to content

Commit 7cb4734

Browse files
committed
refactor: suggest volume not plan for emails
1 parent 6d07f8d commit 7cb4734

File tree

11 files changed

+82
-104
lines changed

11 files changed

+82
-104
lines changed

lib/plausible/billing/plans.ex

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -213,41 +213,30 @@ defmodule Plausible.Billing.Plans do
213213
end
214214

215215
@doc """
216-
Returns the most appropriate plan for a team based on its usage during a
217-
given cycle.
216+
Returns the most appropriate monthly pageview volume for a given usage cycle.
217+
The cycle is either last 30 days (for trials) or last billing cycle for teams
218+
with an existing subscription.
218219
219-
If the usage during the cycle exceeds the enterprise-level threshold, or if
220-
the team already has an enterprise plan, it suggests the :enterprise
221-
plan.
220+
The generation and tier from which we're searching for a suitable volume doesn't
221+
matter - the monthly pageview volumes for all plans starting from v3 are going from
222+
10k to 10M. This function uses v4 Growth but it might as well be e.g. v5 Business.
222223
223-
Otherwise, it recommends the plan where the cycle usage falls just under the
224-
plan's limit from the available options for the team.
224+
If the usage during the cycle exceeds the enterprise-level threshold, or if
225+
the team already has an enterprise plan, it returns `:enterprise`. Otherwise,
226+
a string representing the volume, e.g. "100k" or "5M".
225227
"""
226-
@enterprise_level_usage 10_000_000
227-
@spec suggest(Teams.Team.t(), non_neg_integer()) :: Plan.t()
228-
def suggest(team, usage_during_cycle) do
229-
cond do
230-
usage_during_cycle > @enterprise_level_usage ->
231-
:enterprise
232-
233-
Teams.Billing.enterprise_configured?(team) ->
234-
:enterprise
235-
236-
true ->
237-
subscription = Teams.Billing.get_subscription(team)
238-
suggest_by_usage(subscription, usage_during_cycle)
228+
@spec suggest_volume(Teams.Team.t(), non_neg_integer()) :: String.t() | :enterprise
229+
def suggest_volume(team, usage_during_cycle) do
230+
if Teams.Billing.enterprise_configured?(team) do
231+
:enterprise
232+
else
233+
plans_v4()
234+
|> Enum.filter(&(&1.kind == :growth))
235+
|> Enum.find(%{volume: :enterprise}, &(usage_during_cycle < &1.monthly_pageview_limit))
236+
|> Map.get(:volume)
239237
end
240238
end
241239

242-
def suggest_by_usage(subscription, usage_during_cycle) do
243-
available_plans =
244-
if business_tier?(subscription),
245-
do: business_plans_for(subscription),
246-
else: growth_plans_for(subscription)
247-
248-
Enum.find(available_plans, &(usage_during_cycle < &1.monthly_pageview_limit))
249-
end
250-
251240
def all() do
252241
legacy_plans() ++ plans_v1() ++ plans_v2() ++ plans_v3() ++ plans_v4() ++ plans_v5()
253242
end

lib/plausible/billing/site_locker.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ defmodule Plausible.Billing.SiteLocker do
5555
defp send_grace_period_end_email(team, true) do
5656
team = Repo.preload(team, [:owners, :billing_members])
5757
usage = Teams.Billing.monthly_pageview_usage(team)
58-
suggested_plan = Plausible.Billing.Plans.suggest(team, usage.last_cycle.total)
58+
suggested_volume = Plausible.Billing.Plans.suggest_volume(team, usage.last_cycle.total)
5959

6060
for recipient <- team.owners ++ team.billing_members do
6161
recipient
62-
|> PlausibleWeb.Email.dashboard_locked(team, usage, suggested_plan)
62+
|> PlausibleWeb.Email.dashboard_locked(team, usage, suggested_volume)
6363
|> Plausible.Mailer.send()
6464
end
6565
end

lib/plausible_web/email.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ defmodule PlausibleWeb.Email do
9595
|> render("trial_one_week_reminder.html", user: user, team: team)
9696
end
9797

98-
def trial_upgrade_email(user, team, day, usage, suggested_plan) do
98+
def trial_upgrade_email(user, team, day, usage, suggested_volume) do
9999
base_email()
100100
|> to(user)
101101
|> tag("trial-upgrade-email")
@@ -106,7 +106,7 @@ defmodule PlausibleWeb.Email do
106106
day: day,
107107
custom_events: usage.custom_events,
108108
usage: usage.total,
109-
suggested_plan: suggested_plan
109+
suggested_volume: suggested_volume
110110
)
111111
end
112112

@@ -157,7 +157,7 @@ defmodule PlausibleWeb.Email do
157157
})
158158
end
159159

160-
def over_limit_email(user, team, usage, suggested_plan) do
160+
def over_limit_email(user, team, usage, suggested_volume) do
161161
priority_email()
162162
|> to(user)
163163
|> tag("over-limit")
@@ -166,7 +166,7 @@ defmodule PlausibleWeb.Email do
166166
user: user,
167167
team: team,
168168
usage: usage,
169-
suggested_plan: suggested_plan
169+
suggested_volume: suggested_volume
170170
})
171171
end
172172

@@ -183,7 +183,7 @@ defmodule PlausibleWeb.Email do
183183
})
184184
end
185185

186-
def dashboard_locked(user, team, usage, suggested_plan) do
186+
def dashboard_locked(user, team, usage, suggested_volume) do
187187
priority_email()
188188
|> to(user)
189189
|> tag("dashboard-locked")
@@ -192,7 +192,7 @@ defmodule PlausibleWeb.Email do
192192
user: user,
193193
team: team,
194194
usage: usage,
195-
suggested_plan: suggested_plan
195+
suggested_volume: suggested_volume
196196
})
197197
end
198198

lib/plausible_web/templates/email/dashboard_locked.html.heex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ During the last billing cycle ({PlausibleWeb.TextHelpers.format_date_range(
99
)}), the usage was {PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total)} billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
1010
<a href={PlausibleWeb.Router.Helpers.settings_url(PlausibleWeb.Endpoint, :subscription) <> "?__team=#{@team.identifier}"}>account settings</a>, you'll find an overview of your usage and limits.
1111
<br /><br />
12-
<%= if @suggested_plan == :enterprise do %>
12+
<%= if @suggested_volume == :enterprise do %>
1313
Your usage exceeds our standard plans, so please reply back to this email for a tailored quote.
1414
<% else %>
15-
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <> "?__team=#{@team.identifier}"}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_plan.volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
15+
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <> "?__team=#{@team.identifier}"}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
1616
<br /><br />
1717
If your usage decreases in the future, you can switch to a lower plan at any time. Any credit balance will automatically apply to future payments.
1818
<% end %>

lib/plausible_web/templates/email/over_limit.html.heex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ During the last billing cycle ({PlausibleWeb.TextHelpers.format_date_range(
1010
)}), your account used {PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total)} billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
1111
<a href={plausible_url() <> PlausibleWeb.Router.Helpers.settings_path(PlausibleWeb.Endpoint, :subscription) <> "?__team=#{@team.identifier}"}>account settings</a>, you'll find an overview of your usage and limits.
1212
<br /><br />
13-
<%= if @suggested_plan == :enterprise do %>
13+
<%= if @suggested_volume == :enterprise do %>
1414
Your usage exceeds our standard plans, so please reply back to this email for a tailored quote.
1515
<% else %>
16-
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <> "?__team=#{@team.identifier}"}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_plan.volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
16+
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <> "?__team=#{@team.identifier}"}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
1717
<br /><br />
1818
If your usage decreases in the future, you can switch to a lower plan at any time. Any credit balance will automatically apply to future payments.
1919
<% end %>

lib/plausible_web/templates/email/trial_upgrade_email.html.heex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ In the last month, your account has used {PlausibleWeb.AuthView.delimit_integer(
66
" and custom events in total",
77
else:
88
""}.
9-
<%= if @suggested_plan == :enterprise do %>
9+
<%= if @suggested_volume == :enterprise do %>
1010
This is more than our standard plans, so please reply back to this email to get a quote for your volume.
1111
<% else %>
12-
Based on that we recommend you select a {@suggested_plan.volume}/mo plan. <br /><br />
12+
Based on that we recommend you select a {@suggested_volume}/mo plan. <br /><br />
1313
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) <> "?__team=#{@team.identifier}"}>
1414
Upgrade now
1515
</a>

lib/workers/check_usage.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ defmodule Plausible.Workers.CheckUsage do
108108
defp check_regular_subscriber(subscriber, usage_mod) do
109109
case check_pageview_usage_two_cycles(subscriber, usage_mod) do
110110
{:over_limit, pageview_usage} ->
111-
suggested_plan =
112-
Plausible.Billing.Plans.suggest(subscriber, pageview_usage.last_cycle.total)
111+
suggested_volume =
112+
Plausible.Billing.Plans.suggest_volume(subscriber, pageview_usage.last_cycle.total)
113113

114114
for owner <- subscriber.owners ++ subscriber.billing_members do
115-
PlausibleWeb.Email.over_limit_email(owner, subscriber, pageview_usage, suggested_plan)
115+
PlausibleWeb.Email.over_limit_email(owner, subscriber, pageview_usage, suggested_volume)
116116
|> Plausible.Mailer.send()
117117
end
118118

lib/workers/send_trial_notifications.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,20 @@ defmodule Plausible.Workers.SendTrialNotifications do
6464

6565
defp send_tomorrow_reminder(users, team) do
6666
usage = Plausible.Teams.Billing.usage_cycle(team, :last_30_days)
67-
suggested_plan = Plausible.Billing.Plans.suggest(team, usage.total)
67+
suggested_volume = Plausible.Billing.Plans.suggest_volume(team, usage.total)
6868

6969
for user <- users do
70-
PlausibleWeb.Email.trial_upgrade_email(user, team, "tomorrow", usage, suggested_plan)
70+
PlausibleWeb.Email.trial_upgrade_email(user, team, "tomorrow", usage, suggested_volume)
7171
|> Plausible.Mailer.send()
7272
end
7373
end
7474

7575
defp send_today_reminder(users, team) do
7676
usage = Plausible.Teams.Billing.usage_cycle(team, :last_30_days)
77-
suggested_plan = Plausible.Billing.Plans.suggest(team, usage.total)
77+
suggested_volume = Plausible.Billing.Plans.suggest_volume(team, usage.total)
7878

7979
for user <- users do
80-
PlausibleWeb.Email.trial_upgrade_email(user, team, "today", usage, suggested_plan)
80+
PlausibleWeb.Email.trial_upgrade_email(user, team, "today", usage, suggested_volume)
8181
|> Plausible.Mailer.send()
8282
end
8383
end

test/plausible/billing/plans_test.exs

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -214,42 +214,27 @@ defmodule Plausible.Billing.PlansTest do
214214
end
215215
end
216216

217-
describe "suggested_plan/2" do
217+
describe "suggest_volume/2" do
218218
test "returns suggested plan based on usage" do
219219
team = new_user() |> subscribe_to_plan(@v1_plan_id) |> team_of()
220220

221-
assert %Plausible.Billing.Plan{
222-
monthly_pageview_limit: 100_000,
223-
monthly_cost: nil,
224-
monthly_product_id: "558745",
225-
volume: "100k",
226-
yearly_cost: nil,
227-
yearly_product_id: "590752"
228-
} = Plans.suggest(team, 10_000)
229-
230-
assert %Plausible.Billing.Plan{
231-
monthly_pageview_limit: 200_000,
232-
monthly_cost: nil,
233-
monthly_product_id: "597485",
234-
volume: "200k",
235-
yearly_cost: nil,
236-
yearly_product_id: "597486"
237-
} = Plans.suggest(team, 100_000)
221+
assert Plans.suggest_volume(team, 10_000) == "100k"
222+
assert Plans.suggest_volume(team, 100_000) == "200k"
238223
end
239224

240-
test "returns nil when user has enterprise-level usage" do
225+
test "returns :enterprise when user has enterprise-level usage" do
241226
team = new_user() |> subscribe_to_plan(@v1_plan_id) |> team_of()
242-
assert :enterprise == Plans.suggest(team, 100_000_000)
227+
assert Plans.suggest_volume(team, 10_000_000) == :enterprise
243228
end
244229

245-
test "returns nil when user is on an enterprise plan" do
230+
test "returns :enterprise when user is on an enterprise plan" do
246231
team =
247232
new_user()
248233
|> subscribe_to_plan(@v1_plan_id)
249234
|> subscribe_to_enterprise_plan(billing_interval: :yearly, subscription?: false)
250235
|> team_of()
251236

252-
assert :enterprise == Plans.suggest(team, 10_000)
237+
assert Plans.suggest_volume(team, 10_000) == :enterprise
253238
end
254239
end
255240

test/plausible_web/email_test.exs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,14 @@ defmodule PlausibleWeb.EmailTest do
152152
team = build(:team, identifier: Ecto.UUID.generate())
153153
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
154154
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
155-
suggested_plan = %Plausible.Billing.Plan{volume: "100k"}
156155

157156
usage = %{
158157
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
159158
last_cycle: %{date_range: last_cycle, total: 32_100}
160159
}
161160

162161
%{html_body: html_body, subject: subject} =
163-
PlausibleWeb.Email.over_limit_email(user, team, usage, suggested_plan)
162+
PlausibleWeb.Email.over_limit_email(user, team, usage, "100k")
164163

165164
assert subject == "[Action required] You have outgrown your Plausible subscription tier"
166165

@@ -214,15 +213,14 @@ defmodule PlausibleWeb.EmailTest do
214213
team = build(:team, identifier: Ecto.UUID.generate())
215214
penultimate_cycle = Date.range(~D[2023-03-01], ~D[2023-03-31])
216215
last_cycle = Date.range(~D[2023-04-01], ~D[2023-04-30])
217-
suggested_plan = %Plausible.Billing.Plan{volume: "100k"}
218216

219217
usage = %{
220218
penultimate_cycle: %{date_range: penultimate_cycle, total: 12_300},
221219
last_cycle: %{date_range: last_cycle, total: 32_100}
222220
}
223221

224222
%{html_body: html_body, subject: subject} =
225-
PlausibleWeb.Email.dashboard_locked(user, team, usage, suggested_plan)
223+
PlausibleWeb.Email.dashboard_locked(user, team, usage, "100k")
226224

227225
assert subject == "[Action required] Your Plausible dashboard is now locked"
228226

0 commit comments

Comments
 (0)