mirror of
https://github.com/plausible/analytics.git
synced 2024-08-16 13:20:59 +03:00
Always recommend a suitable plan on the choose-plan page (#4222)
* pull last_bill_date from paddle sandbox in mix task * move cycle usage checks to Quota module * move quota.ex to a subfolder * split up Quota module * set choose-plan pageview slider according to usage * silence credo
This commit is contained in:
parent
86d7031336
commit
dd1d74ccb7
@ -48,6 +48,7 @@ defmodule Mix.Tasks.PullSandboxSubscription do
|
|||||||
update_url: res["update_url"],
|
update_url: res["update_url"],
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
status: res["state"],
|
status: res["state"],
|
||||||
|
last_bill_date: res["last_payment"]["date"],
|
||||||
next_bill_date: res["next_payment"]["date"],
|
next_bill_date: res["next_payment"]["date"],
|
||||||
next_bill_amount: res["next_payment"]["amount"] |> to_string(),
|
next_bill_amount: res["next_payment"]["amount"] |> to_string(),
|
||||||
currency_code: res["next_payment"]["currency"]
|
currency_code: res["next_payment"]["currency"]
|
||||||
|
@ -132,7 +132,7 @@ defmodule Plausible.Billing.Feature do
|
|||||||
def check_availability(%Plausible.Auth.User{} = user) do
|
def check_availability(%Plausible.Auth.User{} = user) do
|
||||||
cond do
|
cond do
|
||||||
free?() -> :ok
|
free?() -> :ok
|
||||||
__MODULE__ in Quota.allowed_features_for(user) -> :ok
|
__MODULE__ in Quota.Limits.allowed_features_for(user) -> :ok
|
||||||
true -> {:error, :upgrade_required}
|
true -> {:error, :upgrade_required}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -235,7 +235,7 @@ defmodule Plausible.Billing.Plans do
|
|||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
if Enum.any?(Quota.features_usage(user), &(&1 not in growth_features)) do
|
if Enum.any?(Quota.Usage.features_usage(user), &(&1 not in growth_features)) do
|
||||||
:business
|
:business
|
||||||
else
|
else
|
||||||
:growth
|
:growth
|
||||||
|
120
lib/plausible/billing/qouta/limits.ex
Normal file
120
lib/plausible/billing/qouta/limits.ex
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
defmodule Plausible.Billing.Quota.Limits do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use Plausible
|
||||||
|
alias Plausible.Users
|
||||||
|
alias Plausible.Auth.User
|
||||||
|
alias Plausible.Billing.{Plan, Plans, Subscription, EnterprisePlan, Feature}
|
||||||
|
alias Plausible.Billing.Feature.{Goals, Props, StatsAPI}
|
||||||
|
|
||||||
|
@type over_limits_error() :: {:over_plan_limits, [limit()]}
|
||||||
|
@typep limit() :: :site_limit | :pageview_limit | :team_member_limit
|
||||||
|
@pageview_allowance_margin 0.1
|
||||||
|
|
||||||
|
on_ee do
|
||||||
|
@limit_sites_since ~D[2021-05-05]
|
||||||
|
@site_limit_for_trials 10
|
||||||
|
@team_member_limit_for_trials 3
|
||||||
|
|
||||||
|
@spec site_limit(User.t()) :: non_neg_integer() | :unlimited
|
||||||
|
def site_limit(user) do
|
||||||
|
if Timex.before?(user.inserted_at, @limit_sites_since) do
|
||||||
|
:unlimited
|
||||||
|
else
|
||||||
|
get_site_limit_from_plan(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_site_limit_from_plan(user) do
|
||||||
|
user = Users.with_subscription(user)
|
||||||
|
|
||||||
|
case Plans.get_subscription_plan(user.subscription) do
|
||||||
|
%{site_limit: site_limit} -> site_limit
|
||||||
|
:free_10k -> 50
|
||||||
|
nil -> @site_limit_for_trials
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec team_member_limit(User.t()) :: non_neg_integer()
|
||||||
|
def team_member_limit(user) do
|
||||||
|
user = Users.with_subscription(user)
|
||||||
|
|
||||||
|
case Plans.get_subscription_plan(user.subscription) do
|
||||||
|
%{team_member_limit: limit} -> limit
|
||||||
|
:free_10k -> :unlimited
|
||||||
|
nil -> @team_member_limit_for_trials
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
def site_limit(_) do
|
||||||
|
:unlimited
|
||||||
|
end
|
||||||
|
|
||||||
|
def team_member_limit(_) do
|
||||||
|
:unlimited
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@monthly_pageview_limit_for_free_10k 10_000
|
||||||
|
@monthly_pageview_limit_for_trials :unlimited
|
||||||
|
|
||||||
|
@spec monthly_pageview_limit(User.t() | Subscription.t()) ::
|
||||||
|
non_neg_integer() | :unlimited
|
||||||
|
def monthly_pageview_limit(%User{} = user) do
|
||||||
|
user = Users.with_subscription(user)
|
||||||
|
monthly_pageview_limit(user.subscription)
|
||||||
|
end
|
||||||
|
|
||||||
|
def monthly_pageview_limit(subscription) do
|
||||||
|
case Plans.get_subscription_plan(subscription) do
|
||||||
|
%EnterprisePlan{monthly_pageview_limit: limit} ->
|
||||||
|
limit
|
||||||
|
|
||||||
|
%Plan{monthly_pageview_limit: limit} ->
|
||||||
|
limit
|
||||||
|
|
||||||
|
:free_10k ->
|
||||||
|
@monthly_pageview_limit_for_free_10k
|
||||||
|
|
||||||
|
_any ->
|
||||||
|
if subscription do
|
||||||
|
Sentry.capture_message("Unknown monthly pageview limit for plan",
|
||||||
|
extra: %{paddle_plan_id: subscription.paddle_plan_id}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@monthly_pageview_limit_for_trials
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pageview_limit_with_margin(limit, margin \\ nil) do
|
||||||
|
margin = if margin, do: margin, else: @pageview_allowance_margin
|
||||||
|
ceil(limit * (1 + margin))
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns a list of features the user can use. Trial users have the
|
||||||
|
ability to use all features during their trial.
|
||||||
|
"""
|
||||||
|
def allowed_features_for(user) do
|
||||||
|
user = Users.with_subscription(user)
|
||||||
|
|
||||||
|
case Plans.get_subscription_plan(user.subscription) do
|
||||||
|
%EnterprisePlan{features: features} ->
|
||||||
|
features
|
||||||
|
|
||||||
|
%Plan{features: features} ->
|
||||||
|
features
|
||||||
|
|
||||||
|
:free_10k ->
|
||||||
|
[Goals, Props, StatsAPI]
|
||||||
|
|
||||||
|
nil ->
|
||||||
|
if Users.on_trial?(user) do
|
||||||
|
Feature.list()
|
||||||
|
else
|
||||||
|
[Goals]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
123
lib/plausible/billing/qouta/quota.ex
Normal file
123
lib/plausible/billing/qouta/quota.ex
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
defmodule Plausible.Billing.Quota do
|
||||||
|
@moduledoc """
|
||||||
|
This module provides functions to work with plans usage and limits.
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Plausible
|
||||||
|
alias Plausible.Users
|
||||||
|
alias Plausible.Auth.User
|
||||||
|
alias Plausible.Billing.{Plan, Plans, EnterprisePlan}
|
||||||
|
alias Plausible.Billing.Quota.{Usage, Limits}
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Enterprise plans are always allowed to add more sites (even when
|
||||||
|
over limit) to avoid service disruption. Their usage is checked
|
||||||
|
in a background job instead (see `check_usage.ex`).
|
||||||
|
"""
|
||||||
|
def ensure_can_add_new_site(user) do
|
||||||
|
user = Users.with_subscription(user)
|
||||||
|
|
||||||
|
case Plans.get_subscription_plan(user.subscription) do
|
||||||
|
%EnterprisePlan{} ->
|
||||||
|
:ok
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
usage = Usage.site_usage(user)
|
||||||
|
limit = Limits.site_limit(user)
|
||||||
|
|
||||||
|
if below_limit?(usage, limit), do: :ok, else: {:error, {:over_limit, limit}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Ensures that the given user (or the usage map) is within the limits
|
||||||
|
of the given plan.
|
||||||
|
|
||||||
|
An `opts` argument can be passed with `ignore_pageview_limit: true`
|
||||||
|
which bypasses the pageview limit check and returns `:ok` as long as
|
||||||
|
the other limits are not exceeded.
|
||||||
|
"""
|
||||||
|
@spec ensure_within_plan_limits(User.t() | map(), struct() | atom() | nil, Keyword.t()) ::
|
||||||
|
:ok | {:error, Limits.over_limits_error()}
|
||||||
|
def ensure_within_plan_limits(user_or_usage, plan, opts \\ [])
|
||||||
|
|
||||||
|
def ensure_within_plan_limits(%User{} = user, %plan_mod{} = plan, opts)
|
||||||
|
when plan_mod in [Plan, EnterprisePlan] do
|
||||||
|
ensure_within_plan_limits(Usage.usage(user), plan, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_within_plan_limits(usage, %plan_mod{} = plan, opts)
|
||||||
|
when plan_mod in [Plan, EnterprisePlan] do
|
||||||
|
case exceeded_limits(usage, plan, opts) do
|
||||||
|
[] -> :ok
|
||||||
|
exceeded_limits -> {:error, {:over_plan_limits, exceeded_limits}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_within_plan_limits(_, _, _), do: :ok
|
||||||
|
|
||||||
|
defp exceeded_limits(usage, plan, opts) do
|
||||||
|
for {limit, exceeded?} <- [
|
||||||
|
{:team_member_limit, not within_limit?(usage.team_members, plan.team_member_limit)},
|
||||||
|
{:site_limit, not within_limit?(usage.sites, plan.site_limit)},
|
||||||
|
{:monthly_pageview_limit,
|
||||||
|
exceeds_monthly_pageview_limit?(usage.monthly_pageviews, plan, opts)}
|
||||||
|
],
|
||||||
|
exceeded? do
|
||||||
|
limit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp exceeds_monthly_pageview_limit?(usage, plan, opts) do
|
||||||
|
if Keyword.get(opts, :ignore_pageview_limit) do
|
||||||
|
false
|
||||||
|
else
|
||||||
|
case usage do
|
||||||
|
%{last_30_days: %{total: total}} ->
|
||||||
|
margin = Keyword.get(opts, :pageview_allowance_margin)
|
||||||
|
limit = Limits.pageview_limit_with_margin(plan.monthly_pageview_limit, margin)
|
||||||
|
!within_limit?(total, limit)
|
||||||
|
|
||||||
|
cycles_usage ->
|
||||||
|
exceeds_last_two_usage_cycles?(cycles_usage, plan.monthly_pageview_limit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec exceeds_last_two_usage_cycles?(Usage.cycles_usage(), non_neg_integer()) :: boolean()
|
||||||
|
def exceeds_last_two_usage_cycles?(cycles_usage, allowed_volume) do
|
||||||
|
exceeded = exceeded_cycles(cycles_usage, allowed_volume)
|
||||||
|
:penultimate_cycle in exceeded && :last_cycle in exceeded
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec exceeded_cycles(Usage.cycles_usage(), non_neg_integer()) :: list()
|
||||||
|
def exceeded_cycles(cycles_usage, allowed_volume) do
|
||||||
|
limit = Limits.pageview_limit_with_margin(allowed_volume)
|
||||||
|
|
||||||
|
Enum.reduce(cycles_usage, [], fn {cycle, %{total: total}}, exceeded_cycles ->
|
||||||
|
if below_limit?(total, limit) do
|
||||||
|
exceeded_cycles
|
||||||
|
else
|
||||||
|
exceeded_cycles ++ [cycle]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec below_limit?(non_neg_integer(), non_neg_integer() | :unlimited) :: boolean()
|
||||||
|
@doc """
|
||||||
|
Returns whether the usage is below the limit or not.
|
||||||
|
Returns false if usage is equal to the limit.
|
||||||
|
"""
|
||||||
|
def below_limit?(usage, limit) do
|
||||||
|
if limit == :unlimited, do: true, else: usage < limit
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec within_limit?(non_neg_integer(), non_neg_integer() | :unlimited) :: boolean()
|
||||||
|
@doc """
|
||||||
|
Returns whether the usage is within the limit or not.
|
||||||
|
Returns true if usage is equal to the limit.
|
||||||
|
"""
|
||||||
|
def within_limit?(usage, limit) do
|
||||||
|
if limit == :unlimited, do: true, else: usage <= limit
|
||||||
|
end
|
||||||
|
end
|
@ -1,34 +1,26 @@
|
|||||||
defmodule Plausible.Billing.Quota do
|
defmodule Plausible.Billing.Quota.Usage do
|
||||||
@moduledoc """
|
@moduledoc false
|
||||||
This module provides functions to work with plans usage and limits.
|
|
||||||
"""
|
|
||||||
|
|
||||||
use Plausible
|
use Plausible
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Plausible.Users
|
alias Plausible.Users
|
||||||
alias Plausible.Auth.User
|
alias Plausible.Auth.User
|
||||||
alias Plausible.Site
|
alias Plausible.Site
|
||||||
alias Plausible.Billing.{Plan, Plans, Subscription, Subscriptions, EnterprisePlan, Feature}
|
alias Plausible.Billing.{Subscriptions}
|
||||||
alias Plausible.Billing.Feature.{Goals, RevenueGoals, Funnels, Props, StatsAPI}
|
alias Plausible.Billing.Feature.{RevenueGoals, Funnels, Props, StatsAPI}
|
||||||
|
|
||||||
@type limit() :: :site_limit | :pageview_limit | :team_member_limit
|
@type cycles_usage() :: %{cycle() => usage_cycle()}
|
||||||
|
|
||||||
@type over_limits_error() :: {:over_plan_limits, [limit()]}
|
@typep cycle :: :current_cycle | :last_cycle | :penultimate_cycle
|
||||||
|
@typep last_30_days_usage() :: %{:last_30_days => usage_cycle()}
|
||||||
|
@typep monthly_pageview_usage() :: cycles_usage() | last_30_days_usage()
|
||||||
|
|
||||||
@type monthly_pageview_usage() :: %{period() => usage_cycle()}
|
@typep usage_cycle :: %{
|
||||||
|
date_range: Date.Range.t(),
|
||||||
@type period :: :last_30_days | :current_cycle | :last_cycle | :penultimate_cycle
|
pageviews: non_neg_integer(),
|
||||||
|
custom_events: non_neg_integer(),
|
||||||
@type usage_cycle :: %{
|
total: non_neg_integer()
|
||||||
date_range: Date.Range.t(),
|
}
|
||||||
pageviews: non_neg_integer(),
|
|
||||||
custom_events: non_neg_integer(),
|
|
||||||
total: non_neg_integer()
|
|
||||||
}
|
|
||||||
|
|
||||||
@pageview_allowance_margin 0.1
|
|
||||||
|
|
||||||
def pageview_allowance_margin(), do: @pageview_allowance_margin
|
|
||||||
|
|
||||||
def usage(user, opts \\ []) do
|
def usage(user, opts \\ []) do
|
||||||
basic_usage = %{
|
basic_usage = %{
|
||||||
@ -45,50 +37,6 @@ defmodule Plausible.Billing.Quota do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
on_ee do
|
|
||||||
@limit_sites_since ~D[2021-05-05]
|
|
||||||
@site_limit_for_trials 10
|
|
||||||
@team_member_limit_for_trials 3
|
|
||||||
|
|
||||||
@spec site_limit(User.t()) :: non_neg_integer() | :unlimited
|
|
||||||
def site_limit(user) do
|
|
||||||
if Timex.before?(user.inserted_at, @limit_sites_since) do
|
|
||||||
:unlimited
|
|
||||||
else
|
|
||||||
get_site_limit_from_plan(user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp get_site_limit_from_plan(user) do
|
|
||||||
user = Users.with_subscription(user)
|
|
||||||
|
|
||||||
case Plans.get_subscription_plan(user.subscription) do
|
|
||||||
%{site_limit: site_limit} -> site_limit
|
|
||||||
:free_10k -> 50
|
|
||||||
nil -> @site_limit_for_trials
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec team_member_limit(User.t()) :: non_neg_integer()
|
|
||||||
def team_member_limit(user) do
|
|
||||||
user = Users.with_subscription(user)
|
|
||||||
|
|
||||||
case Plans.get_subscription_plan(user.subscription) do
|
|
||||||
%{team_member_limit: limit} -> limit
|
|
||||||
:free_10k -> :unlimited
|
|
||||||
nil -> @team_member_limit_for_trials
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
def site_limit(_) do
|
|
||||||
:unlimited
|
|
||||||
end
|
|
||||||
|
|
||||||
def team_member_limit(_) do
|
|
||||||
:unlimited
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec site_usage(User.t()) :: non_neg_integer()
|
@spec site_usage(User.t()) :: non_neg_integer()
|
||||||
@doc """
|
@doc """
|
||||||
Returns the number of sites the given user owns.
|
Returns the number of sites the given user owns.
|
||||||
@ -97,58 +45,6 @@ defmodule Plausible.Billing.Quota do
|
|||||||
Plausible.Sites.owned_sites_count(user)
|
Plausible.Sites.owned_sites_count(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
|
||||||
Enterprise plans are always allowed to add more sites (even when
|
|
||||||
over limit) to avoid service disruption. Their usage is checked
|
|
||||||
in a background job instead (see `check_usage.ex`).
|
|
||||||
"""
|
|
||||||
def ensure_can_add_new_site(user) do
|
|
||||||
user = Users.with_subscription(user)
|
|
||||||
|
|
||||||
case Plans.get_subscription_plan(user.subscription) do
|
|
||||||
%EnterprisePlan{} ->
|
|
||||||
:ok
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
usage = site_usage(user)
|
|
||||||
limit = site_limit(user)
|
|
||||||
|
|
||||||
if below_limit?(usage, limit), do: :ok, else: {:error, {:over_limit, limit}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@monthly_pageview_limit_for_free_10k 10_000
|
|
||||||
@monthly_pageview_limit_for_trials :unlimited
|
|
||||||
|
|
||||||
@spec monthly_pageview_limit(User.t() | Subscription.t()) ::
|
|
||||||
non_neg_integer() | :unlimited
|
|
||||||
def monthly_pageview_limit(%User{} = user) do
|
|
||||||
user = Users.with_subscription(user)
|
|
||||||
monthly_pageview_limit(user.subscription)
|
|
||||||
end
|
|
||||||
|
|
||||||
def monthly_pageview_limit(subscription) do
|
|
||||||
case Plans.get_subscription_plan(subscription) do
|
|
||||||
%EnterprisePlan{monthly_pageview_limit: limit} ->
|
|
||||||
limit
|
|
||||||
|
|
||||||
%Plan{monthly_pageview_limit: limit} ->
|
|
||||||
limit
|
|
||||||
|
|
||||||
:free_10k ->
|
|
||||||
@monthly_pageview_limit_for_free_10k
|
|
||||||
|
|
||||||
_any ->
|
|
||||||
if subscription do
|
|
||||||
Sentry.capture_message("Unknown monthly pageview limit for plan",
|
|
||||||
extra: %{paddle_plan_id: subscription.paddle_plan_id}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
@monthly_pageview_limit_for_trials
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Queries the ClickHouse database for the monthly pageview usage. If the given user's
|
Queries the ClickHouse database for the monthly pageview usage. If the given user's
|
||||||
subscription is `active`, `past_due`, or a `deleted` (but not yet expired), a map
|
subscription is `active`, `past_due`, or a `deleted` (but not yet expired), a map
|
||||||
@ -195,8 +91,7 @@ defmodule Plausible.Billing.Quota do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec usage_cycle(User.t(), period(), list() | nil, Date.t()) :: usage_cycle()
|
@spec usage_cycle(User.t(), :last_30_days | cycle(), list() | nil, Date.t()) :: usage_cycle()
|
||||||
|
|
||||||
def usage_cycle(user, cycle, owned_site_ids \\ nil, today \\ Timex.today())
|
def usage_cycle(user, cycle, owned_site_ids \\ nil, today \\ Timex.today())
|
||||||
|
|
||||||
def usage_cycle(user, cycle, nil, today) do
|
def usage_cycle(user, cycle, nil, today) do
|
||||||
@ -398,114 +293,9 @@ defmodule Plausible.Billing.Quota do
|
|||||||
for {f_mod, used?} <- used_features, used?, f_mod.enabled?(site), do: f_mod
|
for {f_mod, used?} <- used_features, used?, f_mod.enabled?(site), do: f_mod
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
|
||||||
Ensures that the given user (or the usage map) is within the limits
|
|
||||||
of the given plan.
|
|
||||||
|
|
||||||
An `opts` argument can be passed with `ignore_pageview_limit: true`
|
|
||||||
which bypasses the pageview limit check and returns `:ok` as long as
|
|
||||||
the other limits are not exceeded.
|
|
||||||
"""
|
|
||||||
@spec ensure_within_plan_limits(User.t() | map(), struct() | atom() | nil, Keyword.t()) ::
|
|
||||||
:ok | {:error, over_limits_error()}
|
|
||||||
def ensure_within_plan_limits(user_or_usage, plan, opts \\ [])
|
|
||||||
|
|
||||||
def ensure_within_plan_limits(%User{} = user, %plan_mod{} = plan, opts)
|
|
||||||
when plan_mod in [Plan, EnterprisePlan] do
|
|
||||||
ensure_within_plan_limits(usage(user), plan, opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_within_plan_limits(usage, %plan_mod{} = plan, opts)
|
|
||||||
when plan_mod in [Plan, EnterprisePlan] do
|
|
||||||
case exceeded_limits(usage, plan, opts) do
|
|
||||||
[] -> :ok
|
|
||||||
exceeded_limits -> {:error, {:over_plan_limits, exceeded_limits}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_within_plan_limits(_, _, _), do: :ok
|
|
||||||
|
|
||||||
defp exceeded_limits(usage, plan, opts) do
|
|
||||||
for {limit, exceeded?} <- [
|
|
||||||
{:team_member_limit, not within_limit?(usage.team_members, plan.team_member_limit)},
|
|
||||||
{:site_limit, not within_limit?(usage.sites, plan.site_limit)},
|
|
||||||
{:monthly_pageview_limit,
|
|
||||||
exceeds_monthly_pageview_limit?(usage.monthly_pageviews, plan, opts)}
|
|
||||||
],
|
|
||||||
exceeded? do
|
|
||||||
limit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp exceeds_monthly_pageview_limit?(usage, plan, opts) do
|
|
||||||
if Keyword.get(opts, :ignore_pageview_limit) do
|
|
||||||
false
|
|
||||||
else
|
|
||||||
case usage do
|
|
||||||
%{last_30_days: %{total: total}} ->
|
|
||||||
!within_limit?(total, pageview_limit_with_margin(plan, opts))
|
|
||||||
|
|
||||||
billing_cycles_usage ->
|
|
||||||
Plausible.Workers.CheckUsage.exceeds_last_two_usage_cycles?(
|
|
||||||
billing_cycles_usage,
|
|
||||||
plan.monthly_pageview_limit
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp pageview_limit_with_margin(%{monthly_pageview_limit: limit}, opts) do
|
|
||||||
margin = Keyword.get(opts, :pageview_allowance_margin, @pageview_allowance_margin)
|
|
||||||
ceil(limit * (1 + margin))
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Returns a list of features the user can use. Trial users have the
|
|
||||||
ability to use all features during their trial.
|
|
||||||
"""
|
|
||||||
def allowed_features_for(user) do
|
|
||||||
user = Users.with_subscription(user)
|
|
||||||
|
|
||||||
case Plans.get_subscription_plan(user.subscription) do
|
|
||||||
%EnterprisePlan{features: features} ->
|
|
||||||
features
|
|
||||||
|
|
||||||
%Plan{features: features} ->
|
|
||||||
features
|
|
||||||
|
|
||||||
:free_10k ->
|
|
||||||
[Goals, Props, StatsAPI]
|
|
||||||
|
|
||||||
nil ->
|
|
||||||
if Users.on_trial?(user) do
|
|
||||||
Feature.list()
|
|
||||||
else
|
|
||||||
[Goals]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp owned_sites_query(user) do
|
defp owned_sites_query(user) do
|
||||||
from sm in Site.Membership,
|
from sm in Site.Membership,
|
||||||
where: sm.role == :owner and sm.user_id == ^user.id,
|
where: sm.role == :owner and sm.user_id == ^user.id,
|
||||||
select: %{site_id: sm.site_id}
|
select: %{site_id: sm.site_id}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec below_limit?(non_neg_integer(), non_neg_integer() | :unlimited) :: boolean()
|
|
||||||
@doc """
|
|
||||||
Returns whether the usage is below the limit or not.
|
|
||||||
Returns false if usage is equal to the limit.
|
|
||||||
"""
|
|
||||||
def below_limit?(usage, limit) do
|
|
||||||
if limit == :unlimited, do: true, else: usage < limit
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec within_limit?(non_neg_integer(), non_neg_integer() | :unlimited) :: boolean()
|
|
||||||
@doc """
|
|
||||||
Returns whether the usage is within the limit or not.
|
|
||||||
Returns true if usage is equal to the limit.
|
|
||||||
"""
|
|
||||||
def within_limit?(usage, limit) do
|
|
||||||
if limit == :unlimited, do: true, else: usage <= limit
|
|
||||||
end
|
|
||||||
end
|
end
|
@ -68,7 +68,7 @@ defmodule Plausible.Billing.SiteLocker do
|
|||||||
|
|
||||||
@spec send_grace_period_end_email(Plausible.Auth.User.t()) :: Plausible.Mailer.result()
|
@spec send_grace_period_end_email(Plausible.Auth.User.t()) :: Plausible.Mailer.result()
|
||||||
def send_grace_period_end_email(user) do
|
def send_grace_period_end_email(user) do
|
||||||
usage = Plausible.Billing.Quota.monthly_pageview_usage(user)
|
usage = Plausible.Billing.Quota.Usage.monthly_pageview_usage(user)
|
||||||
suggested_plan = Plausible.Billing.Plans.suggest(user, usage.last_cycle.total)
|
suggested_plan = Plausible.Billing.Plans.suggest(user, usage.last_cycle.total)
|
||||||
|
|
||||||
PlausibleWeb.Email.dashboard_locked(user, usage, suggested_plan)
|
PlausibleWeb.Email.dashboard_locked(user, usage, suggested_plan)
|
||||||
|
@ -26,7 +26,7 @@ defmodule Plausible.Site.Memberships.AcceptInvitation do
|
|||||||
@spec transfer_ownership(Site.t(), Auth.User.t()) ::
|
@spec transfer_ownership(Site.t(), Auth.User.t()) ::
|
||||||
{:ok, Site.Membership.t()}
|
{:ok, Site.Membership.t()}
|
||||||
| {:error,
|
| {:error,
|
||||||
Billing.Quota.over_limits_error()
|
Billing.Quota.Limits.over_limits_error()
|
||||||
| Ecto.Changeset.t()
|
| Ecto.Changeset.t()
|
||||||
| :transfer_to_self
|
| :transfer_to_self
|
||||||
| :no_plan}
|
| :no_plan}
|
||||||
@ -54,7 +54,7 @@ defmodule Plausible.Site.Memberships.AcceptInvitation do
|
|||||||
{:ok, Site.Membership.t()}
|
{:ok, Site.Membership.t()}
|
||||||
| {:error,
|
| {:error,
|
||||||
:invitation_not_found
|
:invitation_not_found
|
||||||
| Billing.Quota.over_limits_error()
|
| Billing.Quota.Limits.over_limits_error()
|
||||||
| Ecto.Changeset.t()
|
| Ecto.Changeset.t()
|
||||||
| :no_plan}
|
| :no_plan}
|
||||||
def accept_invitation(invitation_id, user) do
|
def accept_invitation(invitation_id, user) do
|
||||||
|
@ -41,7 +41,7 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
|
|||||||
{:ok, [Membership.t()]}
|
{:ok, [Membership.t()]}
|
||||||
| {:error,
|
| {:error,
|
||||||
invite_error()
|
invite_error()
|
||||||
| Quota.over_limits_error()}
|
| Quota.Limits.over_limits_error()}
|
||||||
def bulk_transfer_ownership_direct(sites, new_owner) do
|
def bulk_transfer_ownership_direct(sites, new_owner) do
|
||||||
Plausible.Repo.transaction(fn ->
|
Plausible.Repo.transaction(fn ->
|
||||||
for site <- sites do
|
for site <- sites do
|
||||||
@ -134,8 +134,8 @@ defmodule Plausible.Site.Memberships.CreateInvitation do
|
|||||||
|
|
||||||
defp check_team_member_limit(site, _role, invitee_email) do
|
defp check_team_member_limit(site, _role, invitee_email) do
|
||||||
site = Plausible.Repo.preload(site, :owner)
|
site = Plausible.Repo.preload(site, :owner)
|
||||||
limit = Quota.team_member_limit(site.owner)
|
limit = Quota.Limits.team_member_limit(site.owner)
|
||||||
usage = Quota.team_member_usage(site.owner, exclude_emails: invitee_email)
|
usage = Quota.Usage.team_member_usage(site.owner, exclude_emails: invitee_email)
|
||||||
|
|
||||||
if Quota.below_limit?(usage, limit),
|
if Quota.below_limit?(usage, limit),
|
||||||
do: :ok,
|
do: :ok,
|
||||||
|
@ -66,7 +66,7 @@ defmodule Plausible.Site.Memberships.Invitations do
|
|||||||
|
|
||||||
on_ee do
|
on_ee do
|
||||||
@spec ensure_can_take_ownership(Site.t(), Auth.User.t()) ::
|
@spec ensure_can_take_ownership(Site.t(), Auth.User.t()) ::
|
||||||
:ok | {:error, Quota.over_limits_error() | :no_plan}
|
:ok | {:error, Quota.Limits.over_limits_error() | :no_plan}
|
||||||
def ensure_can_take_ownership(site, new_owner) do
|
def ensure_can_take_ownership(site, new_owner) do
|
||||||
site = Repo.preload(site, :owner)
|
site = Repo.preload(site, :owner)
|
||||||
new_owner = Plausible.Users.with_subscription(new_owner)
|
new_owner = Plausible.Users.with_subscription(new_owner)
|
||||||
@ -78,7 +78,7 @@ defmodule Plausible.Site.Memberships.Invitations do
|
|||||||
usage_after_transfer = %{
|
usage_after_transfer = %{
|
||||||
monthly_pageviews: monthly_pageview_usage_after_transfer(site, new_owner),
|
monthly_pageviews: monthly_pageview_usage_after_transfer(site, new_owner),
|
||||||
team_members: team_member_usage_after_transfer(site, new_owner),
|
team_members: team_member_usage_after_transfer(site, new_owner),
|
||||||
sites: Quota.site_usage(new_owner) + 1
|
sites: Quota.Usage.site_usage(new_owner) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Quota.ensure_within_plan_limits(usage_after_transfer, plan)
|
Quota.ensure_within_plan_limits(usage_after_transfer, plan)
|
||||||
@ -88,8 +88,8 @@ defmodule Plausible.Site.Memberships.Invitations do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp team_member_usage_after_transfer(site, new_owner) do
|
defp team_member_usage_after_transfer(site, new_owner) do
|
||||||
current_usage = Quota.team_member_usage(new_owner)
|
current_usage = Quota.Usage.team_member_usage(new_owner)
|
||||||
site_usage = Quota.team_member_usage(site.owner, site: site)
|
site_usage = Quota.Usage.team_member_usage(site.owner, site: site)
|
||||||
|
|
||||||
extra_usage =
|
extra_usage =
|
||||||
if Plausible.Sites.is_member?(new_owner.id, site), do: 0, else: 1
|
if Plausible.Sites.is_member?(new_owner.id, site), do: 0, else: 1
|
||||||
@ -99,7 +99,7 @@ defmodule Plausible.Site.Memberships.Invitations do
|
|||||||
|
|
||||||
defp monthly_pageview_usage_after_transfer(site, new_owner) do
|
defp monthly_pageview_usage_after_transfer(site, new_owner) do
|
||||||
site_ids = Plausible.Sites.owned_site_ids(new_owner) ++ [site.id]
|
site_ids = Plausible.Sites.owned_site_ids(new_owner) ++ [site.id]
|
||||||
Quota.monthly_pageview_usage(new_owner, site_ids)
|
Quota.Usage.monthly_pageview_usage(new_owner, site_ids)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@spec ensure_can_take_ownership(Site.t(), Auth.User.t()) :: :ok
|
@spec ensure_can_take_ownership(Site.t(), Auth.User.t()) :: :ok
|
||||||
@ -117,7 +117,7 @@ defmodule Plausible.Site.Memberships.Invitations do
|
|||||||
def check_feature_access(site, new_owner, false = _selfhost?) do
|
def check_feature_access(site, new_owner, false = _selfhost?) do
|
||||||
missing_features =
|
missing_features =
|
||||||
site
|
site
|
||||||
|> Quota.features_usage()
|
|> Quota.Usage.features_usage()
|
||||||
|> Enum.filter(&(&1.check_availability(new_owner) != :ok))
|
|> Enum.filter(&(&1.check_availability(new_owner) != :ok))
|
||||||
|
|
||||||
if missing_features == [] do
|
if missing_features == [] do
|
||||||
|
@ -9,12 +9,12 @@ defmodule PlausibleWeb.AdminController do
|
|||||||
|> String.to_integer()
|
|> String.to_integer()
|
||||||
|> Plausible.Users.with_subscription()
|
|> Plausible.Users.with_subscription()
|
||||||
|
|
||||||
usage = Quota.usage(user, with_features: true)
|
usage = Quota.Usage.usage(user, with_features: true)
|
||||||
|
|
||||||
limits = %{
|
limits = %{
|
||||||
monthly_pageviews: Quota.monthly_pageview_limit(user),
|
monthly_pageviews: Quota.Limits.monthly_pageview_limit(user),
|
||||||
sites: Quota.site_limit(user),
|
sites: Quota.Limits.site_limit(user),
|
||||||
team_members: Quota.team_member_limit(user)
|
team_members: Quota.Limits.team_member_limit(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
html_response = usage_and_limits_html(user, usage, limits)
|
html_response = usage_and_limits_html(user, usage, limits)
|
||||||
|
@ -633,12 +633,12 @@ defmodule PlausibleWeb.AuthController do
|
|||||||
subscription: user.subscription,
|
subscription: user.subscription,
|
||||||
invoices: Plausible.Billing.paddle_api().get_invoices(user.subscription),
|
invoices: Plausible.Billing.paddle_api().get_invoices(user.subscription),
|
||||||
theme: user.theme || "system",
|
theme: user.theme || "system",
|
||||||
team_member_limit: Quota.team_member_limit(user),
|
team_member_limit: Quota.Limits.team_member_limit(user),
|
||||||
team_member_usage: Quota.team_member_usage(user),
|
team_member_usage: Quota.Usage.team_member_usage(user),
|
||||||
site_limit: Quota.site_limit(user),
|
site_limit: Quota.Limits.site_limit(user),
|
||||||
site_usage: Quota.site_usage(user),
|
site_usage: Quota.Usage.site_usage(user),
|
||||||
pageview_limit: Quota.monthly_pageview_limit(user),
|
pageview_limit: Quota.Limits.monthly_pageview_limit(user),
|
||||||
pageview_usage: Quota.monthly_pageview_usage(user),
|
pageview_usage: Quota.Usage.monthly_pageview_usage(user),
|
||||||
totp_enabled?: Auth.TOTP.enabled?(user)
|
totp_enabled?: Auth.TOTP.enabled?(user)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -29,8 +29,8 @@ defmodule PlausibleWeb.Site.MembershipController do
|
|||||||
|> Sites.get_for_user!(conn.assigns.site.domain)
|
|> Sites.get_for_user!(conn.assigns.site.domain)
|
||||||
|> Plausible.Repo.preload(:owner)
|
|> Plausible.Repo.preload(:owner)
|
||||||
|
|
||||||
limit = Plausible.Billing.Quota.team_member_limit(site.owner)
|
limit = Plausible.Billing.Quota.Limits.team_member_limit(site.owner)
|
||||||
usage = Plausible.Billing.Quota.team_member_usage(site.owner)
|
usage = Plausible.Billing.Quota.Usage.team_member_usage(site.owner)
|
||||||
below_limit? = Plausible.Billing.Quota.below_limit?(usage, limit)
|
below_limit? = Plausible.Billing.Quota.below_limit?(usage, limit)
|
||||||
|
|
||||||
render(
|
render(
|
||||||
|
@ -18,8 +18,8 @@ defmodule PlausibleWeb.SiteController do
|
|||||||
|
|
||||||
render(conn, "new.html",
|
render(conn, "new.html",
|
||||||
changeset: Plausible.Site.changeset(%Plausible.Site{}),
|
changeset: Plausible.Site.changeset(%Plausible.Site{}),
|
||||||
first_site?: Quota.site_usage(current_user) == 0,
|
first_site?: Quota.Usage.site_usage(current_user) == 0,
|
||||||
site_limit: Quota.site_limit(current_user),
|
site_limit: Quota.Limits.site_limit(current_user),
|
||||||
site_limit_exceeded?: Quota.ensure_can_add_new_site(current_user) != :ok,
|
site_limit_exceeded?: Quota.ensure_can_add_new_site(current_user) != :ok,
|
||||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||||
)
|
)
|
||||||
@ -27,7 +27,7 @@ defmodule PlausibleWeb.SiteController do
|
|||||||
|
|
||||||
def create_site(conn, %{"site" => site_params}) do
|
def create_site(conn, %{"site" => site_params}) do
|
||||||
user = conn.assigns[:current_user]
|
user = conn.assigns[:current_user]
|
||||||
first_site? = Quota.site_usage(user) == 0
|
first_site? = Quota.Usage.site_usage(user) == 0
|
||||||
|
|
||||||
case Sites.create(user, site_params) do
|
case Sites.create(user, site_params) do
|
||||||
{:ok, %{site: site}} ->
|
{:ok, %{site: site}} ->
|
||||||
@ -53,7 +53,7 @@ defmodule PlausibleWeb.SiteController do
|
|||||||
render(conn, "new.html",
|
render(conn, "new.html",
|
||||||
changeset: changeset,
|
changeset: changeset,
|
||||||
first_site?: first_site?,
|
first_site?: first_site?,
|
||||||
site_limit: Quota.site_limit(user),
|
site_limit: Quota.Limits.site_limit(user),
|
||||||
site_limit_exceeded?: false,
|
site_limit_exceeded?: false,
|
||||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
alias PlausibleWeb.Components.Billing.{PlanBox, PlanBenefits, Notice, PageviewSlider}
|
alias PlausibleWeb.Components.Billing.{PlanBox, PlanBenefits, Notice, PageviewSlider}
|
||||||
alias Plausible.Site
|
alias Plausible.Site
|
||||||
alias Plausible.Users
|
alias Plausible.Users
|
||||||
alias Plausible.Billing.{Plans, Plan, Quota}
|
alias Plausible.Billing.{Plans, Quota}
|
||||||
|
|
||||||
@contact_link "https://plausible.io/contact"
|
@contact_link "https://plausible.io/contact"
|
||||||
@billing_faq_link "https://plausible.io/docs/billing"
|
@billing_faq_link "https://plausible.io/docs/billing"
|
||||||
@ -22,13 +22,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
Users.with_subscription(user_id)
|
Users.with_subscription(user_id)
|
||||||
end)
|
end)
|
||||||
|> assign_new(:usage, fn %{user: user} ->
|
|> assign_new(:usage, fn %{user: user} ->
|
||||||
Quota.usage(user, with_features: true)
|
Quota.Usage.usage(user, with_features: true)
|
||||||
end)
|
|
||||||
|> assign_new(:last_30_days_usage, fn %{user: user, usage: usage} ->
|
|
||||||
case usage do
|
|
||||||
%{last_30_days: usage_cycle} -> usage_cycle.total
|
|
||||||
_ -> Quota.usage_cycle(user, :last_30_days).total
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|> assign_new(:owned_plan, fn %{user: %{subscription: subscription}} ->
|
|> assign_new(:owned_plan, fn %{user: %{subscription: subscription}} ->
|
||||||
Plans.get_regular_plan(subscription, only_non_expired: true)
|
Plans.get_regular_plan(subscription, only_non_expired: true)
|
||||||
@ -63,11 +57,10 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
get_available_volumes(available_plans)
|
get_available_volumes(available_plans)
|
||||||
end)
|
end)
|
||||||
|> assign_new(:selected_volume, fn %{
|
|> assign_new(:selected_volume, fn %{
|
||||||
owned_plan: owned_plan,
|
usage: usage,
|
||||||
last_30_days_usage: last_30_days_usage,
|
|
||||||
available_volumes: available_volumes
|
available_volumes: available_volumes
|
||||||
} ->
|
} ->
|
||||||
default_selected_volume(owned_plan, last_30_days_usage, available_volumes)
|
default_selected_volume(usage.monthly_pageviews, available_volumes)
|
||||||
end)
|
end)
|
||||||
|> assign_new(:selected_interval, fn %{current_interval: current_interval} ->
|
|> assign_new(:selected_interval, fn %{current_interval: current_interval} ->
|
||||||
current_interval || :monthly
|
current_interval || :monthly
|
||||||
@ -149,8 +142,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
<PlanBox.enterprise benefits={@enterprise_benefits} />
|
<PlanBox.enterprise benefits={@enterprise_benefits} />
|
||||||
</div>
|
</div>
|
||||||
<p class="mx-auto mt-8 max-w-2xl text-center text-lg leading-8 text-gray-600 dark:text-gray-400">
|
<p class="mx-auto mt-8 max-w-2xl text-center text-lg leading-8 text-gray-600 dark:text-gray-400">
|
||||||
You have used <b><%= PlausibleWeb.AuthView.delimit_integer(@last_30_days_usage) %></b>
|
<.render_usage pageview_usage={@usage.monthly_pageviews} />
|
||||||
billable pageviews in the last 30 days
|
|
||||||
</p>
|
</p>
|
||||||
<.pageview_limit_notice :if={!@owned_plan} />
|
<.pageview_limit_notice :if={!@owned_plan} />
|
||||||
<.help_links />
|
<.help_links />
|
||||||
@ -160,6 +152,22 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp render_usage(assigns) do
|
||||||
|
case assigns.pageview_usage do
|
||||||
|
%{last_30_days: _} ->
|
||||||
|
~H"""
|
||||||
|
You have used
|
||||||
|
<b><%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.last_30_days.total) %></b> billable pageviews in the last 30 days
|
||||||
|
"""
|
||||||
|
|
||||||
|
%{last_cycle: _} ->
|
||||||
|
~H"""
|
||||||
|
You have used
|
||||||
|
<b><%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.last_cycle.total) %></b> billable pageviews in the last billing cycle
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def handle_event("set_interval", %{"interval" => interval}, socket) do
|
def handle_event("set_interval", %{"interval" => interval}, socket) do
|
||||||
new_interval =
|
new_interval =
|
||||||
case interval do
|
case interval do
|
||||||
@ -189,10 +197,14 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
|||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp default_selected_volume(%Plan{monthly_pageview_limit: limit}, _, _), do: limit
|
defp default_selected_volume(pageview_usage, available_volumes) do
|
||||||
|
total =
|
||||||
|
case pageview_usage do
|
||||||
|
%{last_30_days: usage} -> usage.total
|
||||||
|
%{last_cycle: usage} -> usage.total
|
||||||
|
end
|
||||||
|
|
||||||
defp default_selected_volume(_, last_30_days_usage, available_volumes) do
|
Enum.find(available_volumes, &(total < &1)) || :enterprise
|
||||||
Enum.find(available_volumes, &(last_30_days_usage < &1)) || :enterprise
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp current_user_subscription_interval(subscription) do
|
defp current_user_subscription_interval(subscription) do
|
||||||
|
@ -10,7 +10,7 @@ defmodule PlausibleWeb.AuthView do
|
|||||||
|
|
||||||
def subscription_quota(subscription, options) do
|
def subscription_quota(subscription, options) do
|
||||||
subscription
|
subscription
|
||||||
|> Plausible.Billing.Quota.monthly_pageview_limit()
|
|> Plausible.Billing.Quota.Limits.monthly_pageview_limit()
|
||||||
|> PlausibleWeb.StatsView.large_number_format()
|
|> PlausibleWeb.StatsView.large_number_format()
|
||||||
|> then(fn quota ->
|
|> then(fn quota ->
|
||||||
if Keyword.get(options, :format) == :long,
|
if Keyword.get(options, :format) == :long,
|
||||||
|
@ -33,7 +33,7 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
end
|
end
|
||||||
|
|
||||||
@impl Oban.Worker
|
@impl Oban.Worker
|
||||||
def perform(_job, quota_mod \\ Quota, today \\ Timex.today()) do
|
def perform(_job, usage_mod \\ Quota.Usage, today \\ Timex.today()) do
|
||||||
yesterday = today |> Timex.shift(days: -1)
|
yesterday = today |> Timex.shift(days: -1)
|
||||||
|
|
||||||
active_subscribers =
|
active_subscribers =
|
||||||
@ -56,13 +56,13 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
for subscriber <- active_subscribers do
|
for subscriber <- active_subscribers do
|
||||||
case {subscriber.grace_period, subscriber.enterprise_plan} do
|
case {subscriber.grace_period, subscriber.enterprise_plan} do
|
||||||
{nil, nil} ->
|
{nil, nil} ->
|
||||||
check_regular_subscriber(subscriber, quota_mod)
|
check_regular_subscriber(subscriber, usage_mod)
|
||||||
|
|
||||||
{nil, _} ->
|
{nil, _} ->
|
||||||
check_enterprise_subscriber(subscriber, quota_mod)
|
check_enterprise_subscriber(subscriber, usage_mod)
|
||||||
|
|
||||||
{_, nil} ->
|
{_, nil} ->
|
||||||
maybe_remove_grace_period(subscriber, quota_mod)
|
maybe_remove_grace_period(subscriber, usage_mod)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
:skip
|
:skip
|
||||||
@ -72,29 +72,9 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec exceeds_last_two_usage_cycles?(Quota.monthly_pageview_usage(), non_neg_integer()) ::
|
|
||||||
boolean()
|
|
||||||
|
|
||||||
def exceeds_last_two_usage_cycles?(usage, limit) when is_integer(limit) do
|
|
||||||
limit = ceil(limit * (1 + Quota.pageview_allowance_margin()))
|
|
||||||
|
|
||||||
Enum.all?([usage.last_cycle, usage.penultimate_cycle], fn usage ->
|
|
||||||
not Quota.below_limit?(usage.total, limit)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec last_usage_cycle_below_limit?(Quota.monthly_pageview_usage(), non_neg_integer()) ::
|
|
||||||
boolean()
|
|
||||||
|
|
||||||
def last_usage_cycle_below_limit?(usage, limit) when is_integer(limit) do
|
|
||||||
limit = ceil(limit * (1 + Quota.pageview_allowance_margin()))
|
|
||||||
|
|
||||||
Quota.below_limit?(usage.last_cycle.total, limit)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp check_site_usage_for_enterprise(subscriber) do
|
defp check_site_usage_for_enterprise(subscriber) do
|
||||||
limit = subscriber.enterprise_plan.site_limit
|
limit = subscriber.enterprise_plan.site_limit
|
||||||
usage = Quota.site_usage(subscriber)
|
usage = Quota.Usage.site_usage(subscriber)
|
||||||
|
|
||||||
if Quota.below_limit?(usage, limit) do
|
if Quota.below_limit?(usage, limit) do
|
||||||
{:below_limit, {usage, limit}}
|
{:below_limit, {usage, limit}}
|
||||||
@ -103,8 +83,8 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_remove_grace_period(subscriber, quota_mod) do
|
def maybe_remove_grace_period(subscriber, usage_mod) do
|
||||||
case check_pageview_usage_last_cycle(subscriber, quota_mod) do
|
case check_pageview_usage_last_cycle(subscriber, usage_mod) do
|
||||||
{:below_limit, _} ->
|
{:below_limit, _} ->
|
||||||
subscriber
|
subscriber
|
||||||
|> Plausible.Auth.GracePeriod.remove_changeset()
|
|> Plausible.Auth.GracePeriod.remove_changeset()
|
||||||
@ -115,8 +95,8 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_regular_subscriber(subscriber, quota_mod) do
|
defp check_regular_subscriber(subscriber, usage_mod) do
|
||||||
case check_pageview_usage_two_cycles(subscriber, quota_mod) do
|
case check_pageview_usage_two_cycles(subscriber, usage_mod) do
|
||||||
{:over_limit, pageview_usage} ->
|
{:over_limit, pageview_usage} ->
|
||||||
suggested_plan =
|
suggested_plan =
|
||||||
Plausible.Billing.Plans.suggest(subscriber, pageview_usage.last_cycle.total)
|
Plausible.Billing.Plans.suggest(subscriber, pageview_usage.last_cycle.total)
|
||||||
@ -133,8 +113,8 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_enterprise_subscriber(subscriber, quota_mod) do
|
def check_enterprise_subscriber(subscriber, usage_mod) do
|
||||||
pageview_usage = check_pageview_usage_two_cycles(subscriber, quota_mod)
|
pageview_usage = check_pageview_usage_two_cycles(subscriber, usage_mod)
|
||||||
site_usage = check_site_usage_for_enterprise(subscriber)
|
site_usage = check_site_usage_for_enterprise(subscriber)
|
||||||
|
|
||||||
case {pageview_usage, site_usage} do
|
case {pageview_usage, site_usage} do
|
||||||
@ -156,25 +136,25 @@ defmodule Plausible.Workers.CheckUsage do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_pageview_usage_two_cycles(subscriber, quota_mod) do
|
defp check_pageview_usage_two_cycles(subscriber, usage_mod) do
|
||||||
usage = quota_mod.monthly_pageview_usage(subscriber)
|
usage = usage_mod.monthly_pageview_usage(subscriber)
|
||||||
limit = Quota.monthly_pageview_limit(subscriber)
|
limit = Quota.Limits.monthly_pageview_limit(subscriber)
|
||||||
|
|
||||||
if exceeds_last_two_usage_cycles?(usage, limit) do
|
if Quota.exceeds_last_two_usage_cycles?(usage, limit) do
|
||||||
{:over_limit, usage}
|
{:over_limit, usage}
|
||||||
else
|
else
|
||||||
{:below_limit, usage}
|
{:below_limit, usage}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_pageview_usage_last_cycle(subscriber, quota_mod) do
|
defp check_pageview_usage_last_cycle(subscriber, usage_mod) do
|
||||||
usage = quota_mod.monthly_pageview_usage(subscriber)
|
usage = usage_mod.monthly_pageview_usage(subscriber)
|
||||||
limit = Quota.monthly_pageview_limit(subscriber)
|
limit = Quota.Limits.monthly_pageview_limit(subscriber)
|
||||||
|
|
||||||
if last_usage_cycle_below_limit?(usage, limit) do
|
if :last_cycle in Quota.exceeded_cycles(usage, limit) do
|
||||||
{:below_limit, usage}
|
|
||||||
else
|
|
||||||
{:over_limit, usage}
|
{:over_limit, usage}
|
||||||
|
else
|
||||||
|
{:below_limit, usage}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,14 +55,14 @@ defmodule Plausible.Workers.SendTrialNotifications do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp send_tomorrow_reminder(user) do
|
defp send_tomorrow_reminder(user) do
|
||||||
usage = Plausible.Billing.Quota.usage_cycle(user, :last_30_days)
|
usage = Plausible.Billing.Quota.Usage.usage_cycle(user, :last_30_days)
|
||||||
|
|
||||||
PlausibleWeb.Email.trial_upgrade_email(user, "tomorrow", usage)
|
PlausibleWeb.Email.trial_upgrade_email(user, "tomorrow", usage)
|
||||||
|> Plausible.Mailer.send()
|
|> Plausible.Mailer.send()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp send_today_reminder(user) do
|
defp send_today_reminder(user) do
|
||||||
usage = Plausible.Billing.Quota.usage_cycle(user, :last_30_days)
|
usage = Plausible.Billing.Quota.Usage.usage_cycle(user, :last_30_days)
|
||||||
|
|
||||||
PlausibleWeb.Email.trial_upgrade_email(user, "today", usage)
|
PlausibleWeb.Email.trial_upgrade_email(user, "today", usage)
|
||||||
|> Plausible.Mailer.send()
|
|> Plausible.Mailer.send()
|
||||||
|
@ -24,14 +24,14 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||||
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
||||||
|
|
||||||
assert 50 == Quota.site_limit(user_on_v1)
|
assert 50 == Quota.Limits.site_limit(user_on_v1)
|
||||||
assert 50 == Quota.site_limit(user_on_v2)
|
assert 50 == Quota.Limits.site_limit(user_on_v2)
|
||||||
assert 50 == Quota.site_limit(user_on_v3)
|
assert 50 == Quota.Limits.site_limit(user_on_v3)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 50 when user is on free_10k plan" do
|
test "returns 50 when user is on free_10k plan" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
||||||
assert 50 == Quota.site_limit(user)
|
assert 50 == Quota.Limits.site_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns the configured site limit for enterprise plan" do
|
test "returns the configured site limit for enterprise plan" do
|
||||||
@ -40,7 +40,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
enterprise_plan = insert(:enterprise_plan, user_id: user.id, site_limit: 500)
|
enterprise_plan = insert(:enterprise_plan, user_id: user.id, site_limit: 500)
|
||||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||||
|
|
||||||
assert enterprise_plan.site_limit == Quota.site_limit(user)
|
assert enterprise_plan.site_limit == Quota.Limits.site_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 10 when user in on trial" do
|
test "returns 10 when user in on trial" do
|
||||||
@ -49,7 +49,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7)
|
trial_expiry_date: Timex.shift(Timex.now(), days: 7)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 10 == Quota.site_limit(user)
|
assert 10 == Quota.Limits.site_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns the subscription limit for enterprise users who have not paid yet" do
|
test "returns the subscription limit for enterprise users who have not paid yet" do
|
||||||
@ -59,7 +59,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription: build(:subscription, paddle_plan_id: @v1_plan_id)
|
subscription: build(:subscription, paddle_plan_id: @v1_plan_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 50 == Quota.site_limit(user)
|
assert 50 == Quota.Limits.site_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 10 for enterprise users who have not upgraded yet and are on trial" do
|
test "returns 10 for enterprise users who have not upgraded yet and are on trial" do
|
||||||
@ -69,7 +69,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription: nil
|
subscription: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 10 == Quota.site_limit(user)
|
assert 10 == Quota.Limits.site_limit(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:site, memberships: [build(:site_membership, user: user, role: :admin)])
|
insert(:site, memberships: [build(:site_membership, user: user, role: :admin)])
|
||||||
insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
insert(:site, memberships: [build(:site_membership, user: user, role: :viewer)])
|
||||||
|
|
||||||
assert Quota.site_usage(user) == 3
|
assert Quota.Usage.site_usage(user) == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "below_limit?/2" do
|
describe "below_limit?/2" do
|
||||||
@ -209,19 +209,19 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
test "is based on the plan if user is on a legacy plan" do
|
test "is based on the plan if user is on a legacy plan" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @legacy_plan_id))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @legacy_plan_id))
|
||||||
|
|
||||||
assert Quota.monthly_pageview_limit(user.subscription) == 1_000_000
|
assert Quota.Limits.monthly_pageview_limit(user.subscription) == 1_000_000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "is based on the plan if user is on a standard plan" do
|
test "is based on the plan if user is on a standard plan" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||||
|
|
||||||
assert Quota.monthly_pageview_limit(user.subscription) == 10_000
|
assert Quota.Limits.monthly_pageview_limit(user.subscription) == 10_000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "free_10k has 10k monthly_pageview_limit" do
|
test "free_10k has 10k monthly_pageview_limit" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
||||||
|
|
||||||
assert Quota.monthly_pageview_limit(user.subscription) == 10_000
|
assert Quota.Limits.monthly_pageview_limit(user.subscription) == 10_000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "is based on the enterprise plan if user is on an enterprise plan" do
|
test "is based on the enterprise plan if user is on an enterprise plan" do
|
||||||
@ -233,14 +233,14 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription =
|
subscription =
|
||||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||||
|
|
||||||
assert Quota.monthly_pageview_limit(subscription) == 100_000
|
assert Quota.Limits.monthly_pageview_limit(subscription) == 100_000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not limit pageviews when user has a pending enterprise plan" do
|
test "does not limit pageviews when user has a pending enterprise plan" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
subscription = insert(:subscription, user_id: user.id, paddle_plan_id: "pending-enterprise")
|
subscription = insert(:subscription, user_id: user.id, paddle_plan_id: "pending-enterprise")
|
||||||
|
|
||||||
assert Quota.monthly_pageview_limit(subscription) == :unlimited
|
assert Quota.Limits.monthly_pageview_limit(subscription) == :unlimited
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 3
|
assert Quota.Usage.team_member_usage(me) == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
test "counts the same email address as one team member" do
|
test "counts the same email address as one team member" do
|
||||||
@ -310,7 +310,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
|
|
||||||
insert(:invitation, site: site_i_own_3, inviter: me, email: "joe@plausible.test")
|
insert(:invitation, site: site_i_own_3, inviter: me, email: "joe@plausible.test")
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 2
|
assert Quota.Usage.team_member_usage(me) == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
test "counts pending invitations as team members" do
|
test "counts pending invitations as team members" do
|
||||||
@ -332,7 +332,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:invitation, site: site_i_own, inviter: member)
|
insert(:invitation, site: site_i_own, inviter: member)
|
||||||
insert(:invitation, site: site_i_have_access, inviter: me)
|
insert(:invitation, site: site_i_have_access, inviter: me)
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 3
|
assert Quota.Usage.team_member_usage(me) == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not count ownership transfer as a team member" do
|
test "does not count ownership transfer as a team member" do
|
||||||
@ -341,12 +341,12 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
|
|
||||||
insert(:invitation, site: site_i_own, inviter: me, role: :owner)
|
insert(:invitation, site: site_i_own, inviter: me, role: :owner)
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 0
|
assert Quota.Usage.team_member_usage(me) == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns zero when user does not have any site" do
|
test "returns zero when user does not have any site" do
|
||||||
me = insert(:user)
|
me = insert(:user)
|
||||||
assert Quota.team_member_usage(me) == 0
|
assert Quota.Usage.team_member_usage(me) == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not count email report recipients as team members" do
|
test "does not count email report recipients as team members" do
|
||||||
@ -358,7 +358,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
recipients: ["adam@plausible.test", "vini@plausible.test"]
|
recipients: ["adam@plausible.test", "vini@plausible.test"]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 0
|
assert Quota.Usage.team_member_usage(me) == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
test "excludes specific emails from limit calculation" do
|
test "excludes specific emails from limit calculation" do
|
||||||
@ -377,11 +377,13 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:invitation, site: site_i_own, inviter: member)
|
insert(:invitation, site: site_i_own, inviter: member)
|
||||||
invitation = insert(:invitation, site: site_i_own, inviter: me, email: "foo@example.com")
|
invitation = insert(:invitation, site: site_i_own, inviter: me, email: "foo@example.com")
|
||||||
|
|
||||||
assert Quota.team_member_usage(me) == 4
|
assert Quota.Usage.team_member_usage(me) == 4
|
||||||
assert Quota.team_member_usage(me, exclude_emails: "arbitrary@example.com") == 4
|
assert Quota.Usage.team_member_usage(me, exclude_emails: "arbitrary@example.com") == 4
|
||||||
assert Quota.team_member_usage(me, exclude_emails: member.email) == 3
|
assert Quota.Usage.team_member_usage(me, exclude_emails: member.email) == 3
|
||||||
assert Quota.team_member_usage(me, exclude_emails: invitation.email) == 3
|
assert Quota.Usage.team_member_usage(me, exclude_emails: invitation.email) == 3
|
||||||
assert Quota.team_member_usage(me, exclude_emails: [member.email, invitation.email]) == 2
|
|
||||||
|
assert Quota.Usage.team_member_usage(me, exclude_emails: [member.email, invitation.email]) ==
|
||||||
|
2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -392,14 +394,14 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||||
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
||||||
|
|
||||||
assert :unlimited == Quota.team_member_limit(user_on_v1)
|
assert :unlimited == Quota.Limits.team_member_limit(user_on_v1)
|
||||||
assert :unlimited == Quota.team_member_limit(user_on_v2)
|
assert :unlimited == Quota.Limits.team_member_limit(user_on_v2)
|
||||||
assert :unlimited == Quota.team_member_limit(user_on_v3)
|
assert :unlimited == Quota.Limits.team_member_limit(user_on_v3)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns unlimited when user is on free_10k plan" do
|
test "returns unlimited when user is on free_10k plan" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
||||||
assert :unlimited == Quota.team_member_limit(user)
|
assert :unlimited == Quota.Limits.team_member_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 5 when user in on trial" do
|
test "returns 5 when user in on trial" do
|
||||||
@ -408,7 +410,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
trial_expiry_date: Timex.shift(Timex.now(), days: 7)
|
trial_expiry_date: Timex.shift(Timex.now(), days: 7)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 3 == Quota.team_member_limit(user)
|
assert 3 == Quota.Limits.team_member_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns the enterprise plan limit" do
|
test "returns the enterprise plan limit" do
|
||||||
@ -419,7 +421,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription: build(:subscription, paddle_plan_id: "123321")
|
subscription: build(:subscription, paddle_plan_id: "123321")
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 27 == Quota.team_member_limit(user)
|
assert 27 == Quota.Limits.team_member_limit(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "reads from json file when the user is on a v4 plan" do
|
test "reads from json file when the user is on a v4 plan" do
|
||||||
@ -427,22 +429,22 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
|
|
||||||
user_on_business = insert(:user, subscription: build(:business_subscription))
|
user_on_business = insert(:user, subscription: build(:business_subscription))
|
||||||
|
|
||||||
assert 3 == Quota.team_member_limit(user_on_growth)
|
assert 3 == Quota.Limits.team_member_limit(user_on_growth)
|
||||||
assert 10 == Quota.team_member_limit(user_on_business)
|
assert 10 == Quota.Limits.team_member_limit(user_on_business)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns unlimited when user is on a v3 business plan" do
|
test "returns unlimited when user is on a v3 business plan" do
|
||||||
user =
|
user =
|
||||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_business_plan_id))
|
insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_business_plan_id))
|
||||||
|
|
||||||
assert :unlimited == Quota.team_member_limit(user)
|
assert :unlimited == Quota.Limits.team_member_limit(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "features_usage/1" do
|
describe "features_usage/1" do
|
||||||
test "returns an empty list for a user/site who does not use any feature" do
|
test "returns an empty list for a user/site who does not use any feature" do
|
||||||
assert [] == Quota.features_usage(insert(:user))
|
assert [] == Quota.Usage.features_usage(insert(:user))
|
||||||
assert [] == Quota.features_usage(insert(:site))
|
assert [] == Quota.Usage.features_usage(insert(:site))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns [Props] when user/site uses custom props" do
|
test "returns [Props] when user/site uses custom props" do
|
||||||
@ -454,8 +456,8 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
memberships: [build(:site_membership, user: user, role: :owner)]
|
memberships: [build(:site_membership, user: user, role: :owner)]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert [Props] == Quota.features_usage(site)
|
assert [Props] == Quota.Usage.features_usage(site)
|
||||||
assert [Props] == Quota.features_usage(user)
|
assert [Props] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
on_ee do
|
on_ee do
|
||||||
@ -467,8 +469,8 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
||||||
Plausible.Funnels.create(site, "dummy", steps)
|
Plausible.Funnels.create(site, "dummy", steps)
|
||||||
|
|
||||||
assert [Funnels] == Quota.features_usage(site)
|
assert [Funnels] == Quota.Usage.features_usage(site)
|
||||||
assert [Funnels] == Quota.features_usage(user)
|
assert [Funnels] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns [RevenueGoals] when user/site uses revenue goals" do
|
test "returns [RevenueGoals] when user/site uses revenue goals" do
|
||||||
@ -476,8 +478,8 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
site = insert(:site, memberships: [build(:site_membership, user: user, role: :owner)])
|
site = insert(:site, memberships: [build(:site_membership, user: user, role: :owner)])
|
||||||
insert(:goal, currency: :USD, site: site, event_name: "Purchase")
|
insert(:goal, currency: :USD, site: site, event_name: "Purchase")
|
||||||
|
|
||||||
assert [RevenueGoals] == Quota.features_usage(site)
|
assert [RevenueGoals] == Quota.Usage.features_usage(site)
|
||||||
assert [RevenueGoals] == Quota.features_usage(user)
|
assert [RevenueGoals] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -485,7 +487,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
insert(:api_key, user: user)
|
insert(:api_key, user: user)
|
||||||
|
|
||||||
assert [StatsAPI] == Quota.features_usage(user)
|
assert [StatsAPI] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
on_ee do
|
on_ee do
|
||||||
@ -504,8 +506,8 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
steps = Enum.map(goals, &%{"goal_id" => &1.id})
|
||||||
Plausible.Funnels.create(site, "dummy", steps)
|
Plausible.Funnels.create(site, "dummy", steps)
|
||||||
|
|
||||||
assert [Props, Funnels, RevenueGoals] == Quota.features_usage(site)
|
assert [Props, Funnels, RevenueGoals] == Quota.Usage.features_usage(site)
|
||||||
assert [Props, Funnels, RevenueGoals] == Quota.features_usage(user)
|
assert [Props, Funnels, RevenueGoals] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -517,7 +519,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
memberships: [build(:site_membership, user: user, role: :admin)]
|
memberships: [build(:site_membership, user: user, role: :admin)]
|
||||||
)
|
)
|
||||||
|
|
||||||
assert [] == Quota.features_usage(user)
|
assert [] == Quota.Usage.features_usage(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -525,7 +527,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
on_ee do
|
on_ee do
|
||||||
test "users with expired trials have no access to subscription features" do
|
test "users with expired trials have no access to subscription features" do
|
||||||
user = insert(:user, trial_expiry_date: ~D[2023-01-01])
|
user = insert(:user, trial_expiry_date: ~D[2023-01-01])
|
||||||
assert [Goals] == Quota.allowed_features_for(user)
|
assert [Goals] == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -534,14 +536,14 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
user_on_v2 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||||
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
user_on_v3 = insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_plan_id))
|
||||||
|
|
||||||
assert [Goals, Props, StatsAPI] == Quota.allowed_features_for(user_on_v1)
|
assert [Goals, Props, StatsAPI] == Quota.Limits.allowed_features_for(user_on_v1)
|
||||||
assert [Goals, Props, StatsAPI] == Quota.allowed_features_for(user_on_v2)
|
assert [Goals, Props, StatsAPI] == Quota.Limits.allowed_features_for(user_on_v2)
|
||||||
assert [Goals, Props, StatsAPI] == Quota.allowed_features_for(user_on_v3)
|
assert [Goals, Props, StatsAPI] == Quota.Limits.allowed_features_for(user_on_v3)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns [Goals, Props, StatsAPI] when user is on free_10k plan" do
|
test "returns [Goals, Props, StatsAPI] when user is on free_10k plan" do
|
||||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
user = insert(:user, subscription: build(:subscription, paddle_plan_id: "free_10k"))
|
||||||
assert [Goals, Props, StatsAPI] == Quota.allowed_features_for(user)
|
assert [Goals, Props, StatsAPI] == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
on_ee do
|
on_ee do
|
||||||
@ -560,14 +562,14 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
insert(:subscription, user_id: user.id, paddle_plan_id: enterprise_plan.paddle_plan_id)
|
||||||
|
|
||||||
assert [Plausible.Billing.Feature.StatsAPI, Plausible.Billing.Feature.Funnels] ==
|
assert [Plausible.Billing.Feature.StatsAPI, Plausible.Billing.Feature.Funnels] ==
|
||||||
Quota.allowed_features_for(user)
|
Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns all features when user in on trial" do
|
test "returns all features when user in on trial" do
|
||||||
user = insert(:user, trial_expiry_date: Timex.shift(Timex.now(), days: 7))
|
user = insert(:user, trial_expiry_date: Timex.shift(Timex.now(), days: 7))
|
||||||
|
|
||||||
assert Plausible.Billing.Feature.list() == Quota.allowed_features_for(user)
|
assert Plausible.Billing.Feature.list() == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns previous plan limits for enterprise users who have not paid yet" do
|
test "returns previous plan limits for enterprise users who have not paid yet" do
|
||||||
@ -577,7 +579,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription: build(:subscription, paddle_plan_id: @v1_plan_id)
|
subscription: build(:subscription, paddle_plan_id: @v1_plan_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert [Goals, Props, StatsAPI] == Quota.allowed_features_for(user)
|
assert [Goals, Props, StatsAPI] == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns all features for enterprise users who have not upgraded yet and are on trial" do
|
test "returns all features for enterprise users who have not upgraded yet and are on trial" do
|
||||||
@ -587,7 +589,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
subscription: nil
|
subscription: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
assert Plausible.Billing.Feature.list() == Quota.allowed_features_for(user)
|
assert Plausible.Billing.Feature.list() == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns old plan features for enterprise customers who are due to change a plan" do
|
test "returns old plan features for enterprise customers who are due to change a plan" do
|
||||||
@ -602,7 +604,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
)
|
)
|
||||||
|
|
||||||
insert(:enterprise_plan, user_id: user.id, paddle_plan_id: "new-paddle-plan-id")
|
insert(:enterprise_plan, user_id: user.id, paddle_plan_id: "new-paddle-plan-id")
|
||||||
assert [Plausible.Billing.Feature.StatsAPI] == Quota.allowed_features_for(user)
|
assert [Plausible.Billing.Feature.StatsAPI] == Quota.Limits.allowed_features_for(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -619,7 +621,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
pageviews: 0,
|
pageviews: 0,
|
||||||
date_range: date_range
|
date_range: date_range
|
||||||
}
|
}
|
||||||
} = Quota.monthly_pageview_usage(user)
|
} = Quota.Usage.monthly_pageview_usage(user)
|
||||||
|
|
||||||
assert date_range.last == Date.utc_today()
|
assert date_range.last == Date.utc_today()
|
||||||
assert Date.compare(date_range.first, date_range.last) == :lt
|
assert Date.compare(date_range.first, date_range.last) == :lt
|
||||||
@ -650,7 +652,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
pageviews: 3,
|
pageviews: 3,
|
||||||
date_range: %{}
|
date_range: %{}
|
||||||
}
|
}
|
||||||
} = Quota.monthly_pageview_usage(user)
|
} = Quota.Usage.monthly_pageview_usage(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns usage for user with subscription and a site" do
|
test "returns usage for user with subscription and a site" do
|
||||||
@ -693,7 +695,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
pageviews: 0,
|
pageviews: 0,
|
||||||
date_range: %{}
|
date_range: %{}
|
||||||
}
|
}
|
||||||
} = Quota.monthly_pageview_usage(user)
|
} = Quota.Usage.monthly_pageview_usage(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns usage for only a subset of site IDs" do
|
test "returns usage for only a subset of site IDs" do
|
||||||
@ -740,7 +742,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
pageviews: 0,
|
pageviews: 0,
|
||||||
date_range: %{}
|
date_range: %{}
|
||||||
}
|
}
|
||||||
} = Quota.monthly_pageview_usage(user, [site1.id, site3.id])
|
} = Quota.Usage.monthly_pageview_usage(user, [site1.id, site3.id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -777,13 +779,13 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:subscription, user_id: user.id, last_bill_date: last_bill_date)
|
insert(:subscription, user_id: user.id, last_bill_date: last_bill_date)
|
||||||
|
|
||||||
assert %{date_range: penultimate_cycle, pageviews: 2, custom_events: 3, total: 5} =
|
assert %{date_range: penultimate_cycle, pageviews: 2, custom_events: 3, total: 5} =
|
||||||
Quota.usage_cycle(user, :penultimate_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :penultimate_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: last_cycle, pageviews: 3, custom_events: 2, total: 5} =
|
assert %{date_range: last_cycle, pageviews: 3, custom_events: 2, total: 5} =
|
||||||
Quota.usage_cycle(user, :last_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :last_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: current_cycle, pageviews: 0, custom_events: 3, total: 3} =
|
assert %{date_range: current_cycle, pageviews: 0, custom_events: 3, total: 3} =
|
||||||
Quota.usage_cycle(user, :current_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :current_cycle, nil, today)
|
||||||
|
|
||||||
assert penultimate_cycle == Date.range(~D[2023-04-03], ~D[2023-05-02])
|
assert penultimate_cycle == Date.range(~D[2023-04-03], ~D[2023-05-02])
|
||||||
assert last_cycle == Date.range(~D[2023-05-03], ~D[2023-06-02])
|
assert last_cycle == Date.range(~D[2023-05-03], ~D[2023-06-02])
|
||||||
@ -794,7 +796,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
today = ~D[2023-06-01]
|
today = ~D[2023-06-01]
|
||||||
|
|
||||||
assert %{date_range: last_30_days, pageviews: 4, custom_events: 1, total: 5} =
|
assert %{date_range: last_30_days, pageviews: 4, custom_events: 1, total: 5} =
|
||||||
Quota.usage_cycle(user, :last_30_days, nil, today)
|
Quota.Usage.usage_cycle(user, :last_30_days, nil, today)
|
||||||
|
|
||||||
assert last_30_days == Date.range(~D[2023-05-02], ~D[2023-06-01])
|
assert last_30_days == Date.range(~D[2023-05-02], ~D[2023-06-01])
|
||||||
end
|
end
|
||||||
@ -817,7 +819,7 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
insert(:subscription, user_id: user.id, last_bill_date: last_bill_date)
|
insert(:subscription, user_id: user.id, last_bill_date: last_bill_date)
|
||||||
|
|
||||||
assert %{date_range: last_cycle, pageviews: 3, custom_events: 2, total: 5} =
|
assert %{date_range: last_cycle, pageviews: 3, custom_events: 2, total: 5} =
|
||||||
Quota.usage_cycle(user, :last_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :last_cycle, nil, today)
|
||||||
|
|
||||||
assert last_cycle == Date.range(~D[2023-05-03], ~D[2023-06-02])
|
assert last_cycle == Date.range(~D[2023-05-03], ~D[2023-06-02])
|
||||||
end
|
end
|
||||||
@ -829,13 +831,13 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user = insert(:user, subscription: build(:subscription, last_bill_date: last_bill_date))
|
user = insert(:user, subscription: build(:subscription, last_bill_date: last_bill_date))
|
||||||
|
|
||||||
assert %{date_range: penultimate_cycle} =
|
assert %{date_range: penultimate_cycle} =
|
||||||
Quota.usage_cycle(user, :penultimate_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :penultimate_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: last_cycle} =
|
assert %{date_range: last_cycle} =
|
||||||
Quota.usage_cycle(user, :last_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :last_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: current_cycle} =
|
assert %{date_range: current_cycle} =
|
||||||
Quota.usage_cycle(user, :current_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :current_cycle, nil, today)
|
||||||
|
|
||||||
assert penultimate_cycle == Date.range(~D[2020-12-01], ~D[2020-12-31])
|
assert penultimate_cycle == Date.range(~D[2020-12-01], ~D[2020-12-31])
|
||||||
assert last_cycle == Date.range(~D[2021-01-01], ~D[2021-01-31])
|
assert last_cycle == Date.range(~D[2021-01-01], ~D[2021-01-31])
|
||||||
@ -849,13 +851,13 @@ defmodule Plausible.Billing.QuotaTest do
|
|||||||
user = insert(:user, subscription: build(:subscription, last_bill_date: last_bill_date))
|
user = insert(:user, subscription: build(:subscription, last_bill_date: last_bill_date))
|
||||||
|
|
||||||
assert %{date_range: penultimate_cycle, total: 0} =
|
assert %{date_range: penultimate_cycle, total: 0} =
|
||||||
Quota.usage_cycle(user, :penultimate_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :penultimate_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: last_cycle, total: 0} =
|
assert %{date_range: last_cycle, total: 0} =
|
||||||
Quota.usage_cycle(user, :last_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :last_cycle, nil, today)
|
||||||
|
|
||||||
assert %{date_range: current_cycle, total: 0} =
|
assert %{date_range: current_cycle, total: 0} =
|
||||||
Quota.usage_cycle(user, :current_cycle, nil, today)
|
Quota.Usage.usage_cycle(user, :current_cycle, nil, today)
|
||||||
|
|
||||||
assert penultimate_cycle == Date.range(~D[2020-11-01], ~D[2020-11-30])
|
assert penultimate_cycle == Date.range(~D[2020-11-01], ~D[2020-11-30])
|
||||||
assert last_cycle == Date.range(~D[2020-12-01], ~D[2020-12-31])
|
assert last_cycle == Date.range(~D[2020-12-01], ~D[2020-12-31])
|
||||||
|
@ -364,7 +364,7 @@ defmodule PlausibleWeb.SiteControllerTest do
|
|||||||
})
|
})
|
||||||
|
|
||||||
assert redirected_to(conn) == "/example.com/snippet?site_created=true"
|
assert redirected_to(conn) == "/example.com/snippet?site_created=true"
|
||||||
assert Plausible.Billing.Quota.site_usage(user) == 3
|
assert Plausible.Billing.Quota.Usage.site_usage(user) == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
for url <- ["https://Example.com/", "HTTPS://EXAMPLE.COM/", "/Example.com/", "//Example.com/"] do
|
for url <- ["https://Example.com/", "HTTPS://EXAMPLE.COM/", "/Example.com/", "//Example.com/"] do
|
||||||
|
@ -8,6 +8,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
alias Plausible.{Repo, Billing.Subscription}
|
alias Plausible.{Repo, Billing.Subscription}
|
||||||
|
|
||||||
@v1_10k_yearly_plan_id "572810"
|
@v1_10k_yearly_plan_id "572810"
|
||||||
|
@v4_growth_10k_yearly_plan_id "857079"
|
||||||
@v4_growth_200k_yearly_plan_id "857081"
|
@v4_growth_200k_yearly_plan_id "857081"
|
||||||
@v4_business_5m_monthly_plan_id "857111"
|
@v4_business_5m_monthly_plan_id "857111"
|
||||||
@v3_business_10k_monthly_plan_id "857481"
|
@v3_business_10k_monthly_plan_id "857481"
|
||||||
@ -358,16 +359,18 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
"https://plausible.io/white-label-web-analytics"
|
"https://plausible.io/white-label-web-analytics"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "displays usage", %{conn: conn, site: site} do
|
test "displays usage in the last cycle", %{conn: conn, site: site} do
|
||||||
|
yesterday = NaiveDateTime.utc_now() |> NaiveDateTime.add(-1, :day)
|
||||||
|
|
||||||
populate_stats(site, [
|
populate_stats(site, [
|
||||||
build(:pageview),
|
build(:pageview, timestamp: yesterday),
|
||||||
build(:pageview)
|
build(:pageview, timestamp: yesterday)
|
||||||
])
|
])
|
||||||
|
|
||||||
{:ok, _lv, doc} = get_liveview(conn)
|
{:ok, _lv, doc} = get_liveview(conn)
|
||||||
assert doc =~ "You have used"
|
assert doc =~ "You have used"
|
||||||
assert doc =~ "<b>2</b>"
|
assert doc =~ "<b>2</b>"
|
||||||
assert doc =~ "billable pageviews in the last 30 days"
|
assert doc =~ "billable pageviews in the last billing cycle"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "gets default selected interval from current subscription plan", %{conn: conn} do
|
test "gets default selected interval from current subscription plan", %{conn: conn} do
|
||||||
@ -375,9 +378,9 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
assert class_of_element(doc, @yearly_interval_button) =~ @interval_button_active_class
|
assert class_of_element(doc, @yearly_interval_button) =~ @interval_button_active_class
|
||||||
end
|
end
|
||||||
|
|
||||||
test "gets default pageview limit from current subscription plan", %{conn: conn} do
|
test "sets pageview slider according to last cycle usage", %{conn: conn} do
|
||||||
{:ok, _lv, doc} = get_liveview(conn)
|
{:ok, _lv, doc} = get_liveview(conn)
|
||||||
assert text_of_element(doc, @slider_value) == "200k"
|
assert text_of_element(doc, @slider_value) == "10k"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "pageview slider changes selected volume", %{conn: conn} do
|
test "pageview slider changes selected volume", %{conn: conn} do
|
||||||
@ -401,7 +404,9 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "checkout button text and click-disabling CSS classes are dynamic", %{conn: conn} do
|
test "checkout button text and click-disabling CSS classes are dynamic", %{conn: conn} do
|
||||||
{:ok, lv, doc} = get_liveview(conn)
|
{:ok, lv, _doc} = get_liveview(conn)
|
||||||
|
|
||||||
|
doc = set_slider(lv, "200k")
|
||||||
|
|
||||||
assert text_of_element(doc, @growth_checkout_button) == "Currently on this plan"
|
assert text_of_element(doc, @growth_checkout_button) == "Currently on this plan"
|
||||||
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
||||||
@ -431,7 +436,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
growth_checkout_button = find(doc, @growth_checkout_button)
|
growth_checkout_button = find(doc, @growth_checkout_button)
|
||||||
|
|
||||||
assert text_of_attr(growth_checkout_button, "onclick") =~
|
assert text_of_attr(growth_checkout_button, "onclick") =~
|
||||||
"if (true) {window.location = '#{Routes.billing_path(conn, :change_plan_preview, @v4_growth_200k_yearly_plan_id)}'}"
|
"if (true) {window.location = '#{Routes.billing_path(conn, :change_plan_preview, @v4_growth_10k_yearly_plan_id)}'}"
|
||||||
|
|
||||||
set_slider(lv, "5M")
|
set_slider(lv, "5M")
|
||||||
doc = element(lv, @monthly_interval_button) |> render_click()
|
doc = element(lv, @monthly_interval_button) |> render_click()
|
||||||
@ -446,9 +451,9 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
describe "for a user with a v4 business subscription plan" do
|
describe "for a user with a v4 business subscription plan" do
|
||||||
setup [:create_user, :create_site, :log_in, :subscribe_v4_business]
|
setup [:create_user, :create_site, :log_in, :subscribe_v4_business]
|
||||||
|
|
||||||
test "gets default pageview limit from current subscription plan", %{conn: conn} do
|
test "sets pageview slider according to last cycle usage", %{conn: conn} do
|
||||||
{:ok, _lv, doc} = get_liveview(conn)
|
{:ok, _lv, doc} = get_liveview(conn)
|
||||||
assert text_of_element(doc, @slider_value) == "5M"
|
assert text_of_element(doc, @slider_value) == "10k"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "makes it clear that the user is currently on a business tier", %{conn: conn} do
|
test "makes it clear that the user is currently on a business tier", %{conn: conn} do
|
||||||
@ -462,11 +467,12 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "checkout button text and click-disabling CSS classes are dynamic", %{conn: conn} do
|
test "checkout button text and click-disabling CSS classes are dynamic", %{conn: conn} do
|
||||||
{:ok, lv, doc} = get_liveview(conn)
|
{:ok, lv, _doc} = get_liveview(conn)
|
||||||
|
|
||||||
|
doc = set_slider(lv, "5M")
|
||||||
|
|
||||||
assert text_of_element(doc, @business_checkout_button) == "Currently on this plan"
|
assert text_of_element(doc, @business_checkout_button) == "Currently on this plan"
|
||||||
assert class_of_element(doc, @business_checkout_button) =~ "pointer-events-none bg-gray-400"
|
assert class_of_element(doc, @business_checkout_button) =~ "pointer-events-none bg-gray-400"
|
||||||
assert text_of_element(doc, @growth_checkout_button) == "Downgrade to Growth"
|
|
||||||
|
|
||||||
doc = element(lv, @yearly_interval_button) |> render_click()
|
doc = element(lv, @yearly_interval_button) |> render_click()
|
||||||
|
|
||||||
@ -634,7 +640,10 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
|
|
||||||
test "checkout buttons are disabled + notice about billing details (unless plan owned already)",
|
test "checkout buttons are disabled + notice about billing details (unless plan owned already)",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
{:ok, lv, doc} = get_liveview(conn)
|
{:ok, lv, _doc} = get_liveview(conn)
|
||||||
|
|
||||||
|
doc = set_slider(lv, "200k")
|
||||||
|
|
||||||
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
||||||
assert text_of_element(doc, @growth_checkout_button) =~ "Currently on this plan"
|
assert text_of_element(doc, @growth_checkout_button) =~ "Currently on this plan"
|
||||||
refute element_exists?(doc, "#{@growth_checkout_button} + p")
|
refute element_exists?(doc, "#{@growth_checkout_button} + p")
|
||||||
@ -664,7 +673,10 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
|||||||
|
|
||||||
test "checkout buttons are disabled + notice about billing details when plan not owned already",
|
test "checkout buttons are disabled + notice about billing details when plan not owned already",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
{:ok, lv, doc} = get_liveview(conn)
|
{:ok, lv, _doc} = get_liveview(conn)
|
||||||
|
|
||||||
|
doc = set_slider(lv, "200k")
|
||||||
|
|
||||||
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
assert class_of_element(doc, @growth_checkout_button) =~ "pointer-events-none bg-gray-400"
|
||||||
assert text_of_element(doc, @growth_checkout_button) =~ "Currently on this plan"
|
assert text_of_element(doc, @growth_checkout_button) =~ "Currently on this plan"
|
||||||
refute element_exists?(doc, "#{@growth_checkout_button} + p")
|
refute element_exists?(doc, "#{@growth_checkout_button} + p")
|
||||||
|
@ -31,8 +31,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "does not send an email if account has been over the limit for one billing month", %{
|
test "does not send an email if account has been over the limit for one billing month", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 9_000},
|
penultimate_cycle: %{date_range: @date_range, total: 9_000},
|
||||||
@ -46,7 +46,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_no_emails_delivered()
|
assert_no_emails_delivered()
|
||||||
assert Repo.reload(user).grace_period == nil
|
assert Repo.reload(user).grace_period == nil
|
||||||
@ -55,8 +55,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "does not send an email if account is over the limit by less than 10%", %{
|
test "does not send an email if account is over the limit by less than 10%", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 10_999},
|
penultimate_cycle: %{date_range: @date_range, total: 10_999},
|
||||||
@ -70,7 +70,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_no_emails_delivered()
|
assert_no_emails_delivered()
|
||||||
assert Repo.reload(user).grace_period == nil
|
assert Repo.reload(user).grace_period == nil
|
||||||
@ -79,8 +79,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "sends an email when an account is over their limit for two consecutive billing months", %{
|
test "sends an email when an account is over their limit for two consecutive billing months", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -94,7 +94,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_email_delivered_with(
|
assert_email_delivered_with(
|
||||||
to: [user],
|
to: [user],
|
||||||
@ -107,8 +107,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "sends an email suggesting enterprise plan when usage is greater than 10M ", %{
|
test "sends an email suggesting enterprise plan when usage is greater than 10M ", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000_000},
|
||||||
@ -122,7 +122,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_delivered_email_matches(%{html_body: html_body})
|
assert_delivered_email_matches(%{html_body: html_body})
|
||||||
|
|
||||||
@ -136,8 +136,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
|> Plausible.Auth.GracePeriod.start_changeset()
|
|> Plausible.Auth.GracePeriod.start_changeset()
|
||||||
|> Repo.update!()
|
|> Repo.update!()
|
||||||
|
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -151,7 +151,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_no_emails_delivered()
|
assert_no_emails_delivered()
|
||||||
assert Repo.reload(user).grace_period.id == existing_grace_period.id
|
assert Repo.reload(user).grace_period.id == existing_grace_period.id
|
||||||
@ -160,8 +160,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "recommends a plan to upgrade to", %{
|
test "recommends a plan to upgrade to", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -175,7 +175,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_delivered_email_matches(%{
|
assert_delivered_email_matches(%{
|
||||||
html_body: html_body
|
html_body: html_body
|
||||||
@ -185,8 +185,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "clears grace period when plan is applicable again", %{user: user} do
|
test "clears grace period when plan is applicable again", %{user: user} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -200,11 +200,11 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
||||||
|
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -212,7 +212,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
refute user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
refute user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -223,8 +223,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
|> Plausible.Auth.GracePeriod.start_manual_lock_changeset()
|
|> Plausible.Auth.GracePeriod.start_manual_lock_changeset()
|
||||||
|> Repo.update!()
|
|> Repo.update!()
|
||||||
|
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
||||||
@ -240,7 +240,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_no_emails_delivered()
|
assert_no_emails_delivered()
|
||||||
assert Repo.reload(user).grace_period.id == existing_grace_period.id
|
assert Repo.reload(user).grace_period.id == existing_grace_period.id
|
||||||
@ -250,8 +250,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
%{
|
%{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
||||||
@ -267,7 +267,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_email_delivered_with(
|
assert_email_delivered_with(
|
||||||
to: [{nil, "enterprise@plausible.io"}],
|
to: [{nil, "enterprise@plausible.io"}],
|
||||||
@ -279,8 +279,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
%{
|
%{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 1},
|
penultimate_cycle: %{date_range: @date_range, total: 1},
|
||||||
@ -300,7 +300,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_email_delivered_with(
|
assert_email_delivered_with(
|
||||||
to: [{nil, "enterprise@plausible.io"}],
|
to: [{nil, "enterprise@plausible.io"}],
|
||||||
@ -309,8 +309,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "starts grace period when plan is outgrown", %{user: user} do
|
test "starts grace period when plan is outgrown", %{user: user} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
penultimate_cycle: %{date_range: @date_range, total: 1_100_000},
|
||||||
@ -326,7 +326,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -335,8 +335,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "checks usage one day after the last_bill_date", %{
|
test "checks usage one day after the last_bill_date", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -350,7 +350,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub)
|
CheckUsage.perform(nil, usage_stub)
|
||||||
|
|
||||||
assert_email_delivered_with(
|
assert_email_delivered_with(
|
||||||
to: [user],
|
to: [user],
|
||||||
@ -361,8 +361,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
test "does not check exactly one month after last_bill_date", %{
|
test "does not check exactly one month after last_bill_date", %{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -376,7 +376,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: ~D[2021-03-28]
|
last_bill_date: ~D[2021-03-28]
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub, ~D[2021-03-28])
|
CheckUsage.perform(nil, usage_stub, ~D[2021-03-28])
|
||||||
|
|
||||||
assert_no_emails_delivered()
|
assert_no_emails_delivered()
|
||||||
end
|
end
|
||||||
@ -385,8 +385,8 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
%{
|
%{
|
||||||
user: user
|
user: user
|
||||||
} do
|
} do
|
||||||
quota_stub =
|
usage_stub =
|
||||||
Plausible.Billing.Quota
|
Plausible.Billing.Quota.Usage
|
||||||
|> stub(:monthly_pageview_usage, fn _user ->
|
|> stub(:monthly_pageview_usage, fn _user ->
|
||||||
%{
|
%{
|
||||||
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
penultimate_cycle: %{date_range: @date_range, total: 11_000},
|
||||||
@ -400,7 +400,7 @@ defmodule Plausible.Workers.CheckUsageTest do
|
|||||||
last_bill_date: ~D[2021-06-29]
|
last_bill_date: ~D[2021-06-29]
|
||||||
)
|
)
|
||||||
|
|
||||||
CheckUsage.perform(nil, quota_stub, ~D[2021-08-30])
|
CheckUsage.perform(nil, usage_stub, ~D[2021-08-30])
|
||||||
|
|
||||||
assert_email_delivered_with(
|
assert_email_delivered_with(
|
||||||
to: [user],
|
to: [user],
|
||||||
|
Loading…
Reference in New Issue
Block a user