mirror of
https://github.com/plausible/analytics.git
synced 2025-01-03 07:08:04 +03:00
Check site limit for enterprise customers
This commit is contained in:
parent
792e534edd
commit
e66e9bd1b7
@ -7,7 +7,8 @@ defmodule Plausible.Billing.EnterprisePlan do
|
||||
:paddle_plan_id,
|
||||
:billing_interval,
|
||||
:monthly_pageview_limit,
|
||||
:hourly_api_request_limit
|
||||
:hourly_api_request_limit,
|
||||
:site_limit
|
||||
]
|
||||
|
||||
schema "enterprise_plans" do
|
||||
@ -15,6 +16,7 @@ defmodule Plausible.Billing.EnterprisePlan do
|
||||
field :billing_interval, Ecto.Enum, values: [:monthly, :yearly]
|
||||
field :monthly_pageview_limit, :integer
|
||||
field :hourly_api_request_limit, :integer
|
||||
field :site_limit, :integer
|
||||
|
||||
belongs_to :user, Plausible.Auth.User
|
||||
|
||||
|
@ -14,7 +14,8 @@ defmodule Plausible.Billing.EnterprisePlanAdmin do
|
||||
paddle_plan_id: nil,
|
||||
billing_interval: %{choices: [{"Yearly", "yearly"}, {"Monthly", "monthly"}]},
|
||||
monthly_pageview_limit: nil,
|
||||
hourly_api_request_limit: nil
|
||||
hourly_api_request_limit: nil,
|
||||
site_limit: nil
|
||||
]
|
||||
end
|
||||
|
||||
@ -29,7 +30,8 @@ defmodule Plausible.Billing.EnterprisePlanAdmin do
|
||||
paddle_plan_id: nil,
|
||||
billing_interval: nil,
|
||||
monthly_pageview_limit: nil,
|
||||
hourly_api_request_limit: nil
|
||||
hourly_api_request_limit: nil,
|
||||
site_limit: nil
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -124,6 +124,17 @@ defmodule Plausible.Sites do
|
||||
)
|
||||
end
|
||||
|
||||
def count_owned_by(user) do
|
||||
Repo.one(
|
||||
from s in Plausible.Site,
|
||||
join: sm in Plausible.Site.Membership,
|
||||
on: sm.site_id == s.id,
|
||||
where: sm.role == :owner,
|
||||
where: sm.user_id == ^user.id,
|
||||
select: count(sm)
|
||||
)
|
||||
end
|
||||
|
||||
def owner_for(site) do
|
||||
Repo.one(
|
||||
from u in Plausible.Auth.User,
|
||||
|
@ -128,7 +128,7 @@ defmodule PlausibleWeb.Email do
|
||||
})
|
||||
end
|
||||
|
||||
def enterprise_over_limit_email(user, usage, last_cycle) do
|
||||
def enterprise_over_limit_email(user, usage, last_cycle, site_usage, site_allowance) do
|
||||
base_email()
|
||||
|> to("enterprise@plausible.io")
|
||||
|> tag("enterprise-over-limit")
|
||||
@ -136,7 +136,9 @@ defmodule PlausibleWeb.Email do
|
||||
|> render("enterprise_over_limit.html", %{
|
||||
user: user,
|
||||
usage: usage,
|
||||
last_cycle: last_cycle
|
||||
last_cycle: last_cycle,
|
||||
site_usage: site_usage,
|
||||
site_allowance: site_allowance
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -41,7 +41,7 @@ defmodule PlausibleWeb.Router do
|
||||
plug PlausibleWeb.Firewall
|
||||
end
|
||||
|
||||
if Application.get_env(:plausible, :environment) == "dev" do
|
||||
if Mix.env() == :dev do
|
||||
forward "/sent-emails", Bamboo.SentEmailViewerPlug
|
||||
end
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
Automated notice about an account that has gone over their enteprise plan limit.
|
||||
Automated notice about an enterprise account that has gone over their limits. <br /><br />
|
||||
|
||||
Customer email: <% @user.email %>
|
||||
Last billing cycle: <%= date_format(@last_cycle.first) %> to <%= date_format(@last_cycle.last) %>
|
||||
Usage: <%= PlausibleWeb.StatsView.large_number_format(@usage) %> billable pageviews
|
||||
Customer email: <%= @user.email %><br />
|
||||
Last billing cycle: <%= date_format(@last_cycle.first) %> to <%= date_format(@last_cycle.last) %><br >
|
||||
Pageview Usage: <%= PlausibleWeb.StatsView.large_number_format(@usage) %> billable pageviews<br />
|
||||
Site usage: <%= @site_usage %> / <%= @site_allowance %> allowed sites<br />
|
||||
|
||||
--<br />
|
||||
<%= plausible_url() %><br />
|
||||
|
@ -50,38 +50,80 @@ defmodule Plausible.Workers.CheckUsage do
|
||||
)
|
||||
|
||||
for subscriber <- active_subscribers do
|
||||
allowance = Plausible.Billing.Plans.allowance(subscriber.subscription)
|
||||
{last_last_month, last_month} = billing_mod.last_two_billing_months_usage(subscriber)
|
||||
is_over_limit = last_last_month > allowance && last_month > allowance
|
||||
if subscriber.enterprise_plan do
|
||||
check_enterprise_subscriber(subscriber, billing_mod)
|
||||
else
|
||||
check_regular_subscriber(subscriber, billing_mod)
|
||||
end
|
||||
end
|
||||
|
||||
cond do
|
||||
is_over_limit && subscriber.enterprise_plan ->
|
||||
{_, last_cycle} = billing_mod.last_two_billing_cycles(subscriber)
|
||||
:ok
|
||||
end
|
||||
|
||||
def check_enterprise_subscriber(subscriber, billing_mod) do
|
||||
pageview_limit = check_pageview_limit(subscriber, billing_mod)
|
||||
site_limit = check_site_limit(subscriber)
|
||||
|
||||
case {pageview_limit, site_limit} do
|
||||
{{:within_limit, _}, {:within_limit, _}} ->
|
||||
nil
|
||||
|
||||
{{_, {last_cycle, last_cycle_usage}}, {_, {site_usage, site_allowance}}} ->
|
||||
template =
|
||||
PlausibleWeb.Email.enterprise_over_limit_email(subscriber, last_month, last_cycle)
|
||||
PlausibleWeb.Email.enterprise_over_limit_email(
|
||||
subscriber,
|
||||
last_cycle_usage,
|
||||
last_cycle,
|
||||
site_usage,
|
||||
site_allowance
|
||||
)
|
||||
|
||||
Plausible.Mailer.send_email_safe(template)
|
||||
end
|
||||
end
|
||||
|
||||
is_over_limit ->
|
||||
{_, last_cycle} = billing_mod.last_two_billing_cycles(subscriber)
|
||||
suggested_plan = Plausible.Billing.Plans.suggested_plan(subscriber, last_month)
|
||||
defp check_regular_subscriber(subscriber, billing_mod) do
|
||||
case check_pageview_limit(subscriber, billing_mod) do
|
||||
{:over_limit, {last_cycle, last_cycle_usage}} ->
|
||||
suggested_plan = Plausible.Billing.Plans.suggested_plan(subscriber, last_cycle)
|
||||
|
||||
template =
|
||||
PlausibleWeb.Email.over_limit_email(
|
||||
subscriber,
|
||||
last_month,
|
||||
last_cycle_usage,
|
||||
last_cycle,
|
||||
suggested_plan
|
||||
)
|
||||
|
||||
Plausible.Mailer.send_email_safe(template)
|
||||
|
||||
true ->
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
:ok
|
||||
defp check_pageview_limit(subscriber, billing_mod) do
|
||||
allowance = Plausible.Billing.Plans.allowance(subscriber.subscription)
|
||||
{_, last_cycle} = billing_mod.last_two_billing_cycles(subscriber)
|
||||
|
||||
{last_last_cycle_usage, last_cycle_usage} =
|
||||
billing_mod.last_two_billing_months_usage(subscriber)
|
||||
|
||||
if last_last_cycle_usage > allowance && last_cycle_usage > allowance do
|
||||
{:over_limit, {last_cycle, last_cycle_usage, allowance}}
|
||||
else
|
||||
{:within_limit, {last_cycle, last_cycle_usage}}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_site_limit(subscriber) do
|
||||
allowance = subscriber.enterprise_plan.site_limit
|
||||
total_sites = Plausible.Sites.count_owned_by(subscriber)
|
||||
|
||||
if total_sites >= allowance do
|
||||
{:over_limit, {total_sites, allowance}}
|
||||
else
|
||||
{:within_limit, {total_sites, allowance}}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,18 @@
|
||||
defmodule Plausible.Repo.Migrations.AddSiteLimitToEnterprisePlans do
|
||||
use Ecto.Migration
|
||||
use Plausible.Repo
|
||||
|
||||
def change do
|
||||
alter table(:enterprise_plans) do
|
||||
add :site_limit, :integer
|
||||
end
|
||||
|
||||
flush()
|
||||
|
||||
Repo.update_all("enterprise_plans", set: [site_limit: 50])
|
||||
|
||||
alter table(:enterprise_plans) do
|
||||
modify :site_limit, :integer, null: false
|
||||
end
|
||||
end
|
||||
end
|
@ -121,7 +121,8 @@ defmodule Plausible.Factory do
|
||||
paddle_plan_id: sequence(:paddle_plan_id, &"plan-#{&1}"),
|
||||
billing_interval: :monthly,
|
||||
monthly_pageview_limit: 1_000_000,
|
||||
hourly_api_request_limit: 3000
|
||||
hourly_api_request_limit: 3000,
|
||||
site_limit: 100
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -31,6 +31,9 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
} do
|
||||
billing_stub =
|
||||
Plausible.Billing
|
||||
|> stub(:last_two_billing_cycles, fn _user ->
|
||||
{Date.range(Timex.today(), Timex.today()), Date.range(Timex.today(), Timex.today())}
|
||||
end)
|
||||
|> stub(:last_two_billing_months_usage, fn _user -> {9_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
@ -68,7 +71,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
)
|
||||
end
|
||||
|
||||
test "checks usage for enterprise customer, sends usage information to enterprise@plausible.io",
|
||||
describe "enterprise customers" do
|
||||
test "checks billable pageview usage for enterprise customer, sends usage information to enterprise@plausible.io",
|
||||
%{
|
||||
user: user
|
||||
} do
|
||||
@ -95,6 +99,38 @@ defmodule Plausible.Workers.CheckUsageTest do
|
||||
)
|
||||
end
|
||||
|
||||
test "checks site limit for enterprise customer, sends usage information to enterprise@plausible.io",
|
||||
%{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
Plausible.Billing
|
||||
|> stub(:last_two_billing_months_usage, fn _user -> {1, 1} end)
|
||||
|> stub(:last_two_billing_cycles, fn _user ->
|
||||
{Date.range(Timex.today(), Timex.today()), Date.range(Timex.today(), Timex.today())}
|
||||
end)
|
||||
|
||||
enterprise_plan = insert(:enterprise_plan, user: user, site_limit: 2)
|
||||
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
insert(:site, members: [user])
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: enterprise_plan.paddle_plan_id,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, billing_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
to: [{nil, "enterprise@plausible.io"}],
|
||||
subject: "#{user.email} has outgrown their enterprise plan"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "timing" do
|
||||
test "checks usage one day after the last_bill_date", %{
|
||||
user: user
|
||||
|
Loading…
Reference in New Issue
Block a user