mirror of
https://github.com/plausible/analytics.git
synced 2024-12-23 01:22:15 +03:00
Switch on teams schema in choose plan view behind FF (#4838)
* Switch on teams schema in choose plan view behind FF * Proxy via Read adapter where applicable for billing context * Proxy remaining plan-related functions * Switch enterprise_configured?/1 tests to use the adapter * Format * Update SiteLocker tests * Actually use `has_active_subscription?/1` billing adapter --------- Co-authored-by: Adam Rutkowski <hq@mtod.org>
This commit is contained in:
parent
7b49dd33c7
commit
380dc00d1a
@ -6,14 +6,14 @@ defmodule Plausible.Billing do
|
||||
alias Plausible.Billing.{Subscription, Plans, Quota}
|
||||
alias Plausible.Auth.User
|
||||
|
||||
@spec active_subscription_for(integer()) :: Subscription.t() | nil
|
||||
def active_subscription_for(user_id) do
|
||||
user_id |> active_subscription_query() |> Repo.one()
|
||||
@spec active_subscription_for(User.t()) :: Subscription.t() | nil
|
||||
def active_subscription_for(user) do
|
||||
user |> active_subscription_query() |> Repo.one()
|
||||
end
|
||||
|
||||
@spec has_active_subscription?(integer()) :: boolean()
|
||||
def has_active_subscription?(user_id) do
|
||||
user_id |> active_subscription_query() |> Repo.exists?()
|
||||
@spec has_active_subscription?(User.t()) :: boolean()
|
||||
def has_active_subscription?(user) do
|
||||
user |> active_subscription_query() |> Repo.exists?()
|
||||
end
|
||||
|
||||
def subscription_created(params) do
|
||||
@ -41,7 +41,7 @@ defmodule Plausible.Billing do
|
||||
end
|
||||
|
||||
def change_plan(user, new_plan_id) do
|
||||
subscription = active_subscription_for(user.id)
|
||||
subscription = active_subscription_for(user)
|
||||
plan = Plans.find(new_plan_id)
|
||||
|
||||
limit_checking_opts =
|
||||
@ -283,9 +283,9 @@ defmodule Plausible.Billing do
|
||||
"subscription_cancelled__#{user.id}"
|
||||
end
|
||||
|
||||
defp active_subscription_query(user_id) do
|
||||
defp active_subscription_query(user) do
|
||||
from(s in Subscription,
|
||||
where: s.user_id == ^user_id and s.status == ^Subscription.Status.active(),
|
||||
where: s.user_id == ^user.id and s.status == ^Subscription.Status.active(),
|
||||
order_by: [desc: s.inserted_at],
|
||||
limit: 1
|
||||
)
|
||||
|
@ -28,21 +28,20 @@ defmodule Plausible.Billing.Plans do
|
||||
@business_tier_launch ~N[2023-11-08 12:00:00]
|
||||
def business_tier_launch, do: @business_tier_launch
|
||||
|
||||
@spec growth_plans_for(User.t()) :: [Plan.t()]
|
||||
@spec growth_plans_for(Subscription.t()) :: [Plan.t()]
|
||||
@doc """
|
||||
Returns a list of growth plans available for the user to choose.
|
||||
Returns a list of growth plans available for the subscription to choose.
|
||||
|
||||
As new versions of plans are introduced, users who were on old plans can
|
||||
As new versions of plans are introduced, subscriptions which were on old plans can
|
||||
still choose from old plans.
|
||||
"""
|
||||
def growth_plans_for(%User{} = user) do
|
||||
user = Plausible.Users.with_subscription(user)
|
||||
owned_plan = get_regular_plan(user.subscription)
|
||||
def growth_plans_for(subscription) do
|
||||
owned_plan = get_regular_plan(subscription)
|
||||
|
||||
cond do
|
||||
Application.get_env(:plausible, :environment) in ["dev", "staging"] -> @sandbox_plans
|
||||
is_nil(owned_plan) -> @plans_v4
|
||||
user.subscription && Subscriptions.expired?(user.subscription) -> @plans_v4
|
||||
subscription && Subscriptions.expired?(subscription) -> @plans_v4
|
||||
owned_plan.kind == :business -> @plans_v4
|
||||
owned_plan.generation == 1 -> @plans_v1 |> drop_high_plans(owned_plan)
|
||||
owned_plan.generation == 2 -> @plans_v2 |> drop_high_plans(owned_plan)
|
||||
@ -52,21 +51,20 @@ defmodule Plausible.Billing.Plans do
|
||||
|> Enum.filter(&(&1.kind == :growth))
|
||||
end
|
||||
|
||||
def business_plans_for(%User{} = user) do
|
||||
user = Plausible.Users.with_subscription(user)
|
||||
owned_plan = get_regular_plan(user.subscription)
|
||||
def business_plans_for(subscription) do
|
||||
owned_plan = get_regular_plan(subscription)
|
||||
|
||||
cond do
|
||||
Application.get_env(:plausible, :environment) in ["dev", "staging"] -> @sandbox_plans
|
||||
user.subscription && Subscriptions.expired?(user.subscription) -> @plans_v4
|
||||
subscription && Subscriptions.expired?(subscription) -> @plans_v4
|
||||
owned_plan && owned_plan.generation < 4 -> @plans_v3
|
||||
true -> @plans_v4
|
||||
end
|
||||
|> Enum.filter(&(&1.kind == :business))
|
||||
end
|
||||
|
||||
def available_plans_for(%User{} = user, opts \\ []) do
|
||||
plans = growth_plans_for(user) ++ business_plans_for(user)
|
||||
def available_plans_for(subscription, opts \\ []) do
|
||||
plans = growth_plans_for(subscription) ++ business_plans_for(subscription)
|
||||
|
||||
plans =
|
||||
if Keyword.get(opts, :with_prices) do
|
||||
@ -220,18 +218,16 @@ defmodule Plausible.Billing.Plans do
|
||||
def suggest(user, usage_during_cycle) do
|
||||
cond do
|
||||
usage_during_cycle > @enterprise_level_usage -> :enterprise
|
||||
Plausible.Auth.enterprise_configured?(user) -> :enterprise
|
||||
true -> suggest_by_usage(user, usage_during_cycle)
|
||||
Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(user) -> :enterprise
|
||||
true -> Plausible.Teams.Adapter.Read.Billing.suggest_by_usage(user, usage_during_cycle)
|
||||
end
|
||||
end
|
||||
|
||||
defp suggest_by_usage(user, usage_during_cycle) do
|
||||
user = Plausible.Users.with_subscription(user)
|
||||
|
||||
def suggest_by_usage(subscription, usage_during_cycle) do
|
||||
available_plans =
|
||||
if business_tier?(user.subscription),
|
||||
do: business_plans_for(user),
|
||||
else: growth_plans_for(user)
|
||||
if business_tier?(subscription),
|
||||
do: business_plans_for(subscription),
|
||||
else: growth_plans_for(subscription)
|
||||
|
||||
Enum.find(available_plans, &(usage_during_cycle < &1.monthly_pageview_limit))
|
||||
end
|
||||
|
@ -67,10 +67,11 @@ defmodule Plausible.Billing.SiteLocker do
|
||||
|
||||
@spec send_grace_period_end_email(Plausible.Auth.User.t()) :: Plausible.Mailer.result()
|
||||
def send_grace_period_end_email(user) do
|
||||
usage = Plausible.Billing.Quota.Usage.monthly_pageview_usage(user)
|
||||
usage = Plausible.Teams.Adapter.Read.Billing.monthly_pageview_usage(user)
|
||||
suggested_plan = Plausible.Billing.Plans.suggest(user, usage.last_cycle.total)
|
||||
|
||||
PlausibleWeb.Email.dashboard_locked(user, usage, suggested_plan)
|
||||
user
|
||||
|> PlausibleWeb.Email.dashboard_locked(usage, suggested_plan)
|
||||
|> Plausible.Mailer.send()
|
||||
end
|
||||
end
|
||||
|
@ -4,6 +4,22 @@ defmodule Plausible.Teams.Adapter.Read.Billing do
|
||||
"""
|
||||
use Plausible.Teams.Adapter
|
||||
|
||||
def enterprise_configured?(nil), do: false
|
||||
|
||||
def enterprise_configured?(user) do
|
||||
switch(user,
|
||||
team_fn: &Plausible.Teams.Billing.enterprise_configured?/1,
|
||||
user_fn: &Plausible.Auth.enterprise_configured?/1
|
||||
)
|
||||
end
|
||||
|
||||
def has_active_subscription?(user) do
|
||||
switch(user,
|
||||
team_fn: &Plausible.Teams.Billing.has_active_subscription?/1,
|
||||
user_fn: &Plausible.Billing.has_active_subscription?/1
|
||||
)
|
||||
end
|
||||
|
||||
def get_subscription(user) do
|
||||
case user_or_team(user) do
|
||||
%{subscription: subscription} -> subscription
|
||||
@ -131,4 +147,9 @@ defmodule Plausible.Teams.Adapter.Read.Billing do
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def suggest_by_usage(user, usage_during_cycle) do
|
||||
subscription = get_subscription(user)
|
||||
Plausible.Billing.Plans.suggest_by_usage(subscription, usage_during_cycle)
|
||||
end
|
||||
end
|
||||
|
@ -8,6 +8,13 @@ defmodule Plausible.Teams.Adapter.Read.Ownership do
|
||||
alias Plausible.Auth
|
||||
alias Plausible.Site.Memberships.Invitations
|
||||
|
||||
def all_pending_site_transfers(email, user) do
|
||||
switch(user,
|
||||
team_fn: fn _ -> Plausible.Teams.Memberships.all_pending_site_transfers(email) end,
|
||||
user_fn: fn _ -> Plausible.Site.Memberships.all_pending_ownerships(email) end
|
||||
)
|
||||
end
|
||||
|
||||
def get_owner(site, user) do
|
||||
switch(user,
|
||||
team_fn: fn team ->
|
||||
|
@ -12,10 +12,28 @@ defmodule Plausible.Teams.Billing do
|
||||
alias Plausible.Billing.{Plan, Plans, EnterprisePlan, Feature}
|
||||
alias Plausible.Billing.Feature.{Goals, Props, StatsAPI}
|
||||
|
||||
require Plausible.Billing.Subscription.Status
|
||||
|
||||
@team_member_limit_for_trials 3
|
||||
@limit_sites_since ~D[2021-05-05]
|
||||
@site_limit_for_trials 10
|
||||
|
||||
def enterprise_configured?(nil), do: false
|
||||
|
||||
def enterprise_configured?(%Teams.Team{} = team) do
|
||||
team
|
||||
|> Ecto.assoc(:enterprise_plan)
|
||||
|> Repo.exists?()
|
||||
end
|
||||
|
||||
def has_active_subscription?(nil), do: false
|
||||
|
||||
def has_active_subscription?(team) do
|
||||
team
|
||||
|> active_subscription_query()
|
||||
|> Repo.exists?()
|
||||
end
|
||||
|
||||
def check_needs_to_upgrade(nil), do: {:needs_to_upgrade, :no_trial}
|
||||
|
||||
def check_needs_to_upgrade(team) do
|
||||
@ -350,4 +368,13 @@ defmodule Plausible.Teams.Billing do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp active_subscription_query(team) do
|
||||
from(s in Plausible.Billing.Subscription,
|
||||
where:
|
||||
s.team_id == ^team.id and s.status == ^Plausible.Billing.Subscription.Status.active(),
|
||||
order_by: [desc: s.inserted_at],
|
||||
limit: 1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -7,6 +7,26 @@ defmodule Plausible.Teams.Memberships do
|
||||
alias Plausible.Repo
|
||||
alias Plausible.Teams
|
||||
|
||||
def all_pending_site_transfers(email) do
|
||||
email
|
||||
|> pending_site_transfers_query()
|
||||
|> Repo.all()
|
||||
|> Enum.map(fn transfer ->
|
||||
%Plausible.Auth.Invitation{
|
||||
site_id: transfer.site_id,
|
||||
email: transfer.email,
|
||||
invitation_id: transfer.transfer_id,
|
||||
role: :owner
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
def any_pending_site_transfers?(email) do
|
||||
email
|
||||
|> pending_site_transfers_query()
|
||||
|> Repo.exists?()
|
||||
end
|
||||
|
||||
def get(team, user) do
|
||||
result =
|
||||
from(tm in Teams.Membership,
|
||||
@ -127,4 +147,8 @@ defmodule Plausible.Teams.Memberships do
|
||||
membership -> {:ok, membership}
|
||||
end
|
||||
end
|
||||
|
||||
defp pending_site_transfers_query(email) do
|
||||
from st in Teams.SiteTransfer, where: st.email == ^email
|
||||
end
|
||||
end
|
||||
|
@ -189,7 +189,7 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
</div>
|
||||
<.styled_link
|
||||
:if={
|
||||
not (Plausible.Auth.enterprise_configured?(@user) &&
|
||||
not (Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(@user) &&
|
||||
Subscriptions.halted?(@subscription))
|
||||
}
|
||||
id="#upgrade-or-change-plan-link"
|
||||
|
@ -9,14 +9,16 @@ defmodule PlausibleWeb.BillingController do
|
||||
plug PlausibleWeb.RequireAccountPlug
|
||||
|
||||
def ping_subscription(%Plug.Conn{} = conn, _params) do
|
||||
subscribed? = Billing.has_active_subscription?(conn.assigns.current_user.id)
|
||||
subscribed? =
|
||||
Plausible.Teams.Adapter.Read.Billing.has_active_subscription?(conn.assigns.current_user)
|
||||
|
||||
json(conn, %{is_subscribed: subscribed?})
|
||||
end
|
||||
|
||||
def choose_plan(conn, _params) do
|
||||
current_user = conn.assigns.current_user
|
||||
|
||||
if Plausible.Auth.enterprise_configured?(current_user) do
|
||||
if Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(current_user) do
|
||||
redirect(conn, to: Routes.billing_path(conn, :upgrade_to_enterprise_plan))
|
||||
else
|
||||
render(conn, "choose_plan.html",
|
||||
@ -135,8 +137,8 @@ defmodule PlausibleWeb.BillingController do
|
||||
end
|
||||
end
|
||||
|
||||
defp preview_subscription(%{id: user_id}, new_plan_id) do
|
||||
subscription = Billing.active_subscription_for(user_id)
|
||||
defp preview_subscription(user, new_plan_id) do
|
||||
subscription = Billing.active_subscription_for(user)
|
||||
|
||||
if subscription do
|
||||
with {:ok, preview_info} <- Billing.change_plan_preview(subscription, new_plan_id) do
|
||||
|
@ -8,7 +8,6 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
||||
require Plausible.Billing.Subscription.Status
|
||||
|
||||
alias PlausibleWeb.Components.Billing.{PlanBox, PlanBenefits, Notice, PageviewSlider}
|
||||
alias Plausible.Site
|
||||
alias Plausible.Billing.{Plans, Quota}
|
||||
|
||||
@contact_link "https://plausible.io/contact"
|
||||
@ -19,7 +18,7 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
||||
socket
|
||||
|> assign_new(:pending_ownership_site_ids, fn %{current_user: current_user} ->
|
||||
current_user.email
|
||||
|> Site.Memberships.all_pending_ownerships()
|
||||
|> Plausible.Teams.Adapter.Read.Ownership.all_pending_site_transfers(current_user)
|
||||
|> Enum.map(& &1.site_id)
|
||||
end)
|
||||
|> assign_new(:usage, fn %{
|
||||
@ -31,17 +30,20 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
||||
pending_ownership_site_ids: pending_ownership_site_ids
|
||||
)
|
||||
end)
|
||||
|> assign_new(:owned_plan, fn %{current_user: %{subscription: subscription}} ->
|
||||
|> assign_new(:subscription, fn %{current_user: current_user} ->
|
||||
Plausible.Teams.Adapter.Read.Billing.get_subscription(current_user)
|
||||
end)
|
||||
|> assign_new(:owned_plan, fn %{subscription: subscription} ->
|
||||
Plans.get_regular_plan(subscription, only_non_expired: true)
|
||||
end)
|
||||
|> assign_new(:owned_tier, fn %{owned_plan: owned_plan} ->
|
||||
if owned_plan, do: Map.get(owned_plan, :kind), else: nil
|
||||
end)
|
||||
|> assign_new(:current_interval, fn %{current_user: current_user} ->
|
||||
current_user_subscription_interval(current_user.subscription)
|
||||
|> assign_new(:current_interval, fn %{subscription: subscription} ->
|
||||
current_user_subscription_interval(subscription)
|
||||
end)
|
||||
|> assign_new(:available_plans, fn %{current_user: current_user} ->
|
||||
Plans.available_plans_for(current_user, with_prices: true, customer_ip: remote_ip)
|
||||
|> assign_new(:available_plans, fn %{subscription: subscription} ->
|
||||
Plans.available_plans_for(subscription, with_prices: true, customer_ip: remote_ip)
|
||||
end)
|
||||
|> assign_new(:recommended_tier, fn %{usage: usage, available_plans: available_plans} ->
|
||||
highest_growth_plan = List.last(available_plans.growth)
|
||||
@ -102,8 +104,8 @@ defmodule PlausibleWeb.Live.ChoosePlan do
|
||||
class="pb-6"
|
||||
pending_ownership_count={length(@pending_ownership_site_ids)}
|
||||
/>
|
||||
<Notice.subscription_past_due class="pb-6" subscription={@current_user.subscription} />
|
||||
<Notice.subscription_paused class="pb-6" subscription={@current_user.subscription} />
|
||||
<Notice.subscription_past_due class="pb-6" subscription={@subscription} />
|
||||
<Notice.subscription_paused class="pb-6" subscription={@subscription} />
|
||||
<Notice.upgrade_ineligible :if={not Quota.eligible_for_upgrade?(@usage)} />
|
||||
<div class="mx-auto max-w-4xl text-center">
|
||||
<p class="text-4xl font-bold tracking-tight lg:text-5xl">
|
||||
|
@ -6,7 +6,9 @@
|
||||
<div class="flex flex-col gap-y-2">
|
||||
<Notice.active_grace_period
|
||||
:if={Plausible.Auth.GracePeriod.active?(@conn.assigns.current_user)}
|
||||
enterprise?={Plausible.Auth.enterprise_configured?(@conn.assigns.current_user)}
|
||||
enterprise?={
|
||||
Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(@conn.assigns.current_user)
|
||||
}
|
||||
grace_period_end={grace_period_end(@conn.assigns.current_user)}
|
||||
/>
|
||||
|
||||
|
@ -43,12 +43,20 @@ defmodule Plausible.AuthTest do
|
||||
end
|
||||
|
||||
test "enterprise_configured?/1 returns whether the user has an enterprise plan" do
|
||||
user_without_plan = insert(:user)
|
||||
user_with_plan = insert(:user, enterprise_plan: build(:enterprise_plan))
|
||||
user_without_plan = new_user()
|
||||
user_with_plan = new_user() |> subscribe_to_enterprise_plan()
|
||||
|
||||
assert Auth.enterprise_configured?(user_with_plan)
|
||||
refute Auth.enterprise_configured?(user_without_plan)
|
||||
refute Auth.enterprise_configured?(nil)
|
||||
user_with_plan_no_subscription =
|
||||
new_user() |> subscribe_to_enterprise_plan(subscription?: false)
|
||||
|
||||
assert Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(user_with_plan)
|
||||
|
||||
assert Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(
|
||||
user_with_plan_no_subscription
|
||||
)
|
||||
|
||||
refute Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(user_without_plan)
|
||||
refute Plausible.Teams.Adapter.Read.Billing.enterprise_configured?(nil)
|
||||
end
|
||||
|
||||
describe "create_api_key/3" do
|
||||
|
@ -531,9 +531,9 @@ defmodule Plausible.BillingTest do
|
||||
paused = insert(:subscription, user: insert(:user), status: Subscription.Status.paused())
|
||||
user_without_subscription = insert(:user)
|
||||
|
||||
assert Billing.active_subscription_for(active.user_id).id == active.id
|
||||
assert Billing.active_subscription_for(paused.user_id) == nil
|
||||
assert Billing.active_subscription_for(user_without_subscription.id) == nil
|
||||
assert Billing.active_subscription_for(active.user).id == active.id
|
||||
assert Billing.active_subscription_for(paused.user) == nil
|
||||
assert Billing.active_subscription_for(user_without_subscription) == nil
|
||||
end
|
||||
|
||||
test "has_active_subscription?/1 returns whether the user has an active subscription" do
|
||||
@ -541,8 +541,8 @@ defmodule Plausible.BillingTest do
|
||||
paused = insert(:subscription, user: insert(:user), status: Subscription.Status.paused())
|
||||
user_without_subscription = insert(:user)
|
||||
|
||||
assert Billing.has_active_subscription?(active.user_id)
|
||||
refute Billing.has_active_subscription?(paused.user_id)
|
||||
refute Billing.has_active_subscription?(user_without_subscription.id)
|
||||
assert Billing.has_active_subscription?(active.user)
|
||||
refute Billing.has_active_subscription?(paused.user)
|
||||
refute Billing.has_active_subscription?(user_without_subscription)
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule Plausible.Billing.PlansTest do
|
||||
use Plausible.DataCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
@legacy_plan_id "558746"
|
||||
@ -9,56 +10,49 @@ defmodule Plausible.Billing.PlansTest do
|
||||
|
||||
describe "getting subscription plans for user" do
|
||||
test "growth_plans_for/1 returns v1 plans for a user on a legacy plan" do
|
||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @legacy_plan_id))
|
||||
new_user()
|
||||
|> subscribe_to_plan(@legacy_plan_id)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(1)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns v1 plans for users who are already on v1 pricing" do
|
||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(1)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns v2 plans for users who are already on v2 pricing" do
|
||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v2_plan_id)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(2)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns v4 plans for invited users with trial_expiry = nil" do
|
||||
insert(:user, trial_expiry_date: nil)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns v4 plans for users whose trial started after the business tiers release" do
|
||||
insert(:user, trial_expiry_date: ~D[2023-12-24])
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns v4 plans for expired legacy subscriptions" do
|
||||
subscription =
|
||||
build(:subscription,
|
||||
paddle_plan_id: @v1_plan_id,
|
||||
status: :deleted,
|
||||
next_bill_date: ~D[2023-11-10]
|
||||
)
|
||||
|
||||
insert(:user, subscription: subscription)
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id, status: :deleted, next_bill_date: ~D[2023-11-10])
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 shows v4 plans for everyone else" do
|
||||
insert(:user)
|
||||
new_user()
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 does not return business plans" do
|
||||
insert(:user)
|
||||
new_user()
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> Enum.each(fn plan ->
|
||||
assert plan.kind != :business
|
||||
@ -66,64 +60,61 @@ defmodule Plausible.Billing.PlansTest do
|
||||
end
|
||||
|
||||
test "growth_plans_for/1 returns the latest generation of growth plans for a user with a business subscription" do
|
||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @v3_business_plan_id))
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v3_business_plan_id)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.growth_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v3 business plans for a user on a legacy plan" do
|
||||
insert(:user, subscription: build(:subscription, paddle_plan_id: @legacy_plan_id))
|
||||
new_user()
|
||||
|> subscribe_to_plan(@legacy_plan_id)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(3)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v3 business plans for a v2 subscriber" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
business_plans = Plans.business_plans_for(user)
|
||||
business_plans = Plans.business_plans_for(user.subscription)
|
||||
|
||||
assert Enum.all?(business_plans, &(&1.kind == :business))
|
||||
assert_generation(business_plans, 3)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v4 plans for invited users with trial_expiry = nil" do
|
||||
insert(:user, trial_expiry_date: nil)
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v4 plans for users whose trial started after the business tiers release" do
|
||||
insert(:user, trial_expiry_date: ~D[2023-12-24])
|
||||
new_user(trial_expiry_date: nil)
|
||||
|> Repo.preload(:subscription)
|
||||
|> Map.fetch!(:subscription)
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v4 plans for expired legacy subscriptions" do
|
||||
subscription =
|
||||
build(:subscription,
|
||||
paddle_plan_id: @v2_plan_id,
|
||||
status: :deleted,
|
||||
next_bill_date: ~D[2023-11-10]
|
||||
)
|
||||
user =
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v2_plan_id, status: :deleted, next_bill_date: ~D[2023-11-10])
|
||||
|
||||
insert(:user, subscription: subscription)
|
||||
user.subscription
|
||||
|> Plans.business_plans_for()
|
||||
|> assert_generation(4)
|
||||
end
|
||||
|
||||
test "business_plans_for/1 returns v4 business plans for everyone else" do
|
||||
user = insert(:user)
|
||||
business_plans = Plans.business_plans_for(user)
|
||||
user = new_user() |> Repo.preload(:subscription)
|
||||
business_plans = Plans.business_plans_for(user.subscription)
|
||||
|
||||
assert Enum.all?(business_plans, &(&1.kind == :business))
|
||||
assert_generation(business_plans, 4)
|
||||
end
|
||||
|
||||
test "available_plans returns all plans for user with prices when asked for" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
%{growth: growth_plans, business: business_plans} =
|
||||
Plans.available_plans_for(user, with_prices: true, customer_ip: "127.0.0.1")
|
||||
Plans.available_plans_for(user.subscription, with_prices: true, customer_ip: "127.0.0.1")
|
||||
|
||||
assert Enum.find(growth_plans, fn plan ->
|
||||
(%Money{} = plan.monthly_cost) && plan.monthly_product_id == @v2_plan_id
|
||||
@ -135,9 +126,9 @@ defmodule Plausible.Billing.PlansTest do
|
||||
end
|
||||
|
||||
test "available_plans returns all plans without prices by default" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v2_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v2_plan_id)
|
||||
|
||||
assert %{growth: [_ | _], business: [_ | _]} = Plans.available_plans_for(user)
|
||||
assert %{growth: [_ | _], business: [_ | _]} = Plans.available_plans_for(user.subscription)
|
||||
end
|
||||
|
||||
test "latest_enterprise_plan_with_price/1" do
|
||||
@ -190,7 +181,7 @@ defmodule Plausible.Billing.PlansTest do
|
||||
|
||||
describe "suggested_plan/2" do
|
||||
test "returns suggested plan based on usage" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v1_plan_id)
|
||||
|
||||
assert %Plausible.Billing.Plan{
|
||||
monthly_pageview_limit: 100_000,
|
||||
@ -212,13 +203,16 @@ defmodule Plausible.Billing.PlansTest do
|
||||
end
|
||||
|
||||
test "returns nil when user has enterprise-level usage" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
user = new_user() |> subscribe_to_plan(@v1_plan_id)
|
||||
assert :enterprise == Plans.suggest(user, 100_000_000)
|
||||
end
|
||||
|
||||
test "returns nil when user is on an enterprise plan" do
|
||||
user = insert(:user, subscription: build(:subscription, paddle_plan_id: @v1_plan_id))
|
||||
_enterprise_plan = insert(:enterprise_plan, user_id: user.id, billing_interval: :yearly)
|
||||
user =
|
||||
new_user()
|
||||
|> subscribe_to_plan(@v1_plan_id)
|
||||
|> subscribe_to_enterprise_plan(billing_interval: :yearly, subscription?: false)
|
||||
|
||||
assert :enterprise == Plans.suggest(user, 10_000)
|
||||
end
|
||||
end
|
||||
|
@ -112,16 +112,9 @@ defmodule Plausible.Billing.SiteLockerTest do
|
||||
|
||||
test "locks all sites if user has active subscription but grace period has ended" do
|
||||
grace_period = %Plausible.Auth.GracePeriod{end_date: Timex.shift(Timex.today(), days: -1)}
|
||||
user = insert(:user, grace_period: grace_period)
|
||||
|
||||
insert(:subscription, status: Subscription.Status.active(), user: user)
|
||||
|
||||
site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner)
|
||||
]
|
||||
)
|
||||
user = new_user(grace_period: grace_period)
|
||||
subscribe_to_plan(user, "123")
|
||||
site = new_site(owner: user)
|
||||
|
||||
assert SiteLocker.update_sites_for(user) == {:locked, :grace_period_ended_now}
|
||||
|
||||
@ -131,15 +124,9 @@ defmodule Plausible.Billing.SiteLockerTest do
|
||||
@tag :teams
|
||||
test "syncs grace period end with teams" do
|
||||
grace_period = %Plausible.Auth.GracePeriod{end_date: Timex.shift(Timex.today(), days: -1)}
|
||||
user = insert(:user, grace_period: grace_period)
|
||||
|
||||
insert(:subscription, status: Subscription.Status.active(), user: user)
|
||||
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner)
|
||||
]
|
||||
)
|
||||
user = new_user(grace_period: grace_period)
|
||||
subscribe_to_plan(user, "123")
|
||||
new_site(owner: user)
|
||||
|
||||
assert SiteLocker.update_sites_for(user) == {:locked, :grace_period_ended_now}
|
||||
|
||||
@ -151,15 +138,9 @@ defmodule Plausible.Billing.SiteLockerTest do
|
||||
|
||||
test "sends email if grace period has ended" do
|
||||
grace_period = %Plausible.Auth.GracePeriod{end_date: Timex.shift(Timex.today(), days: -1)}
|
||||
user = insert(:user, grace_period: grace_period)
|
||||
|
||||
insert(:subscription, status: Subscription.Status.active(), user: user)
|
||||
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner)
|
||||
]
|
||||
)
|
||||
user = new_user(grace_period: grace_period)
|
||||
subscribe_to_plan(user, "123")
|
||||
new_site(owner: user)
|
||||
|
||||
assert SiteLocker.update_sites_for(user) == {:locked, :grace_period_ended_now}
|
||||
|
||||
@ -170,21 +151,14 @@ defmodule Plausible.Billing.SiteLockerTest do
|
||||
end
|
||||
|
||||
test "does not send grace period email if site is already locked" do
|
||||
user =
|
||||
insert(:user,
|
||||
grace_period: %Plausible.Auth.GracePeriod{
|
||||
end_date: Timex.shift(Timex.today(), days: -1),
|
||||
is_over: false
|
||||
}
|
||||
)
|
||||
grace_period = %Plausible.Auth.GracePeriod{
|
||||
end_date: Timex.shift(Timex.today(), days: -1),
|
||||
is_over: false
|
||||
}
|
||||
|
||||
insert(:subscription, status: Subscription.Status.active(), user: user)
|
||||
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, user: user, role: :owner)
|
||||
]
|
||||
)
|
||||
user = new_user(grace_period: grace_period)
|
||||
subscribe_to_plan(user, "123")
|
||||
new_site(owner: user)
|
||||
|
||||
assert SiteLocker.update_sites_for(user) == {:locked, :grace_period_ended_now}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
defmodule PlausibleWeb.BillingControllerTest do
|
||||
use PlausibleWeb.ConnCase, async: true
|
||||
use Plausible.Teams.Test
|
||||
import Plausible.Test.Support.HTML
|
||||
require Plausible.Billing.Subscription.Status
|
||||
alias Plausible.Billing.Subscription
|
||||
@ -12,7 +13,8 @@ defmodule PlausibleWeb.BillingControllerTest do
|
||||
|
||||
test "redirects to enterprise upgrade page if user has an enterprise plan configured",
|
||||
%{conn: conn, user: user} do
|
||||
insert(:enterprise_plan, user: user, paddle_plan_id: "123")
|
||||
subscribe_to_enterprise_plan(user, paddle_plan_id: "123")
|
||||
|
||||
conn = get(conn, Routes.billing_path(conn, :choose_plan))
|
||||
assert redirected_to(conn) == Routes.billing_path(conn, :upgrade_to_enterprise_plan)
|
||||
end
|
||||
|
@ -245,11 +245,11 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
user: user
|
||||
} do
|
||||
previous_owner = insert(:user)
|
||||
site = insert(:site, members: [previous_owner])
|
||||
site = new_site(owner: previous_owner)
|
||||
|
||||
insert(:goal, site: site, currency: :USD, event_name: "Purchase")
|
||||
|
||||
insert(:invitation, email: user.email, inviter: previous_owner, role: :owner, site: site)
|
||||
invite_transfer(site, user, inviter: previous_owner)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -259,31 +259,16 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
|
||||
test "recommends Business when team member limit for Growth exceeded due to pending ownerships",
|
||||
%{conn: conn, user: user} do
|
||||
_owned_site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, role: :owner, user: user),
|
||||
build(:site_membership, role: :admin, user: insert(:user)),
|
||||
build(:site_membership, role: :admin, user: insert(:user))
|
||||
]
|
||||
)
|
||||
owned_site = new_site(owner: user)
|
||||
add_guest(owned_site, role: :editor)
|
||||
add_guest(owned_site, role: :editor)
|
||||
|
||||
previous_owner = insert(:user)
|
||||
previous_owner = new_user()
|
||||
|
||||
pending_ownership_site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, role: :owner, user: previous_owner),
|
||||
build(:site_membership, role: :viewer, user: insert(:user))
|
||||
]
|
||||
)
|
||||
pending_ownership_site = new_site(owner: previous_owner)
|
||||
add_guest(pending_ownership_site, role: :viewer)
|
||||
|
||||
insert(:invitation,
|
||||
email: user.email,
|
||||
inviter: previous_owner,
|
||||
role: :owner,
|
||||
site: pending_ownership_site
|
||||
)
|
||||
invite_transfer(pending_ownership_site, user, inviter: previous_owner)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -298,15 +283,10 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
insert_list(9, :site, members: [user])
|
||||
assert 10 = Plausible.Billing.Quota.Usage.site_usage(user)
|
||||
|
||||
another_user = insert(:user)
|
||||
pending_ownership_site = insert(:site, members: [another_user])
|
||||
another_user = new_user()
|
||||
pending_ownership_site = new_site(owner: another_user)
|
||||
|
||||
insert(:invitation,
|
||||
email: user.email,
|
||||
site: pending_ownership_site,
|
||||
role: :owner,
|
||||
inviter: another_user
|
||||
)
|
||||
invite_transfer(pending_ownership_site, user, inviter: another_user)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -463,28 +443,18 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
build(:pageview, timestamp: yesterday)
|
||||
])
|
||||
|
||||
another_user = insert(:user)
|
||||
another_user = new_user()
|
||||
|
||||
pending_site =
|
||||
insert(:site,
|
||||
memberships: [
|
||||
build(:site_membership, role: :owner, user: another_user),
|
||||
build(:site_membership, role: :admin, user: build(:user)),
|
||||
build(:site_membership, role: :viewer, user: build(:user)),
|
||||
build(:site_membership, role: :viewer, user: build(:user))
|
||||
]
|
||||
)
|
||||
pending_site = new_site(owner: another_user)
|
||||
add_guest(pending_site, role: :editor)
|
||||
add_guest(pending_site, role: :viewer)
|
||||
add_guest(pending_site, role: :viewer)
|
||||
|
||||
populate_stats(pending_site, [
|
||||
build(:pageview, timestamp: yesterday)
|
||||
])
|
||||
|
||||
insert(:invitation,
|
||||
site: pending_site,
|
||||
inviter: another_user,
|
||||
email: user.email,
|
||||
role: :owner
|
||||
)
|
||||
invite_transfer(pending_site, user, inviter: another_user)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -507,12 +477,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
|
||||
Plausible.Props.allow(pending_site, ["author"])
|
||||
|
||||
insert(:invitation,
|
||||
site: pending_site,
|
||||
inviter: another_user,
|
||||
email: user.email,
|
||||
role: :owner
|
||||
)
|
||||
invite_transfer(pending_site, user, inviter: another_user)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -644,18 +609,16 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
insert_list(49, :site, members: [user])
|
||||
for _ <- 1..49 do
|
||||
new_site(owner: user)
|
||||
end
|
||||
|
||||
assert 50 = Plausible.Billing.Quota.Usage.site_usage(user)
|
||||
|
||||
another_user = insert(:user)
|
||||
pending_ownership_site = insert(:site, members: [another_user])
|
||||
another_user = new_user()
|
||||
pending_ownership_site = new_site(owner: another_user)
|
||||
|
||||
insert(:invitation,
|
||||
email: user.email,
|
||||
site: pending_ownership_site,
|
||||
role: :owner,
|
||||
inviter: another_user
|
||||
)
|
||||
invite_transfer(pending_ownership_site, user, inviter: another_user)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -1102,9 +1065,9 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
conn: conn,
|
||||
user: user
|
||||
} do
|
||||
old_owner = insert(:user)
|
||||
site = insert(:site, members: [old_owner])
|
||||
insert(:invitation, site_id: site.id, inviter: old_owner, email: user.email, role: :owner)
|
||||
old_owner = new_user()
|
||||
site = new_site(owner: old_owner)
|
||||
invite_transfer(site, user, inviter: old_owner)
|
||||
|
||||
{:ok, _lv, doc} = get_liveview(conn)
|
||||
|
||||
@ -1146,15 +1109,14 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
|
||||
)
|
||||
end
|
||||
|
||||
defp create_subscription_for(user, subscription_options) do
|
||||
insert(:subscription, Keyword.put(subscription_options, :user, user))
|
||||
{:ok, user: Plausible.Users.with_subscription(user)}
|
||||
defp create_subscription_for(user, subscription_opts) do
|
||||
{paddle_plan_id, subscription_opts} = Keyword.pop(subscription_opts, :paddle_plan_id)
|
||||
user = subscribe_to_plan(user, paddle_plan_id, subscription_opts)
|
||||
{:ok, user: user}
|
||||
end
|
||||
|
||||
defp subscribe_free_10k(%{user: user}) do
|
||||
Plausible.Billing.Subscription.free(%{user_id: user.id})
|
||||
|> Repo.insert!()
|
||||
|
||||
user = subscribe_to_plan(user, "free_10k")
|
||||
{:ok, user: user}
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,7 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
|
||||
use Plausible.DataCase
|
||||
use Bamboo.Test
|
||||
use Oban.Testing, repo: Plausible.Repo
|
||||
use Plausible.Teams.Test
|
||||
alias Plausible.Workers.SendTrialNotifications
|
||||
|
||||
test "does not send a notification if user didn't create a site" do
|
||||
@ -220,10 +221,9 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
|
||||
end
|
||||
|
||||
test "does not suggest a plan when user is switching to an enterprise plan" do
|
||||
user = insert(:user)
|
||||
user = new_user()
|
||||
usage = %{total: 10_000, custom_events: 0}
|
||||
|
||||
insert(:enterprise_plan, user: user, paddle_plan_id: "enterprise-plan-id")
|
||||
subscribe_to_enterprise_plan(user, paddle_plan_id: "enterprise-plan-id")
|
||||
|
||||
email = PlausibleWeb.Email.trial_upgrade_email(user, "today", usage)
|
||||
assert email.html_body =~ "please reply back to this email to get a quote for your volume"
|
||||
|
Loading…
Reference in New Issue
Block a user