Remove grace period if user upgrades

This commit is contained in:
Uku Taht 2021-11-04 11:05:33 +02:00
parent ec2a4a1a65
commit e9cb8eb4e2
7 changed files with 158 additions and 32 deletions

View File

@ -4,6 +4,15 @@ defimpl Bamboo.Formatter, for: Plausible.Auth.User do
end
end
defmodule Plausible.Auth.GracePeriod do
use Ecto.Schema
embedded_schema do
field :end_date, :date
field :allowance_required, :integer
end
end
defmodule Plausible.Auth.User do
use Ecto.Schema
import Ecto.Changeset
@ -17,9 +26,9 @@ defmodule Plausible.Auth.User do
field :name, :string
field :last_seen, :naive_datetime
field :trial_expiry_date, :date
field :grace_period_end, :date
field :theme, :string
field :email_verified, :boolean
embeds_one :grace_period, Plausible.Auth.GracePeriod, on_replace: :update
has_many :site_memberships, Plausible.Site.Membership
has_many :sites, through: [:site_memberships, :site]
@ -80,8 +89,17 @@ defmodule Plausible.Auth.User do
change(user, trial_expiry_date: Timex.today() |> Timex.shift(days: -1))
end
def start_grace_period(user) do
change(user, grace_period_end: Timex.today() |> Timex.shift(days: 7))
def start_grace_period(user, allowance_required) do
grace_period = %Plausible.Auth.GracePeriod{
end_date: Timex.today() |> Timex.shift(days: 7),
allowance_required: allowance_required
}
change(user, grace_period: grace_period)
end
def remove_grace_period(user) do
change(user, grace_period: nil)
end
defp trial_expiry() do

View File

@ -17,20 +17,29 @@ defmodule Plausible.Billing do
changeset = Subscription.changeset(%Subscription{}, format_subscription(params))
Repo.insert(changeset)
|> check_lock_status
|> maybe_adjust_api_key_limits
Repo.insert(changeset) |> after_subscription_update
end
def subscription_updated(params) do
subscription = Repo.get_by!(Subscription, paddle_subscription_id: params["subscription_id"])
changeset = Subscription.changeset(subscription, format_subscription(params))
Repo.update(changeset)
Repo.update(changeset) |> after_subscription_update
end
defp after_subscription_update({:ok, subscription}) do
user =
Repo.get(Plausible.Auth.User, subscription.user_id)
|> Map.put(:subscription, subscription)
{:ok, user}
|> maybe_remove_grace_period
|> check_lock_status
|> maybe_adjust_api_key_limits
end
defp after_subscription_update(err), do: err
def subscription_cancelled(params) do
subscription =
Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
@ -114,7 +123,7 @@ defmodule Plausible.Billing do
subscription_active = subscription_is_active?(user.subscription)
grace_period_ended =
user.grace_period_end && Timex.before?(user.grace_period_end, Timex.today())
user.grace_period && Timex.before?(user.grace_period.end_date, Timex.today())
cond do
trial_is_over && !subscription_active -> {true, :no_active_subscription}
@ -225,31 +234,48 @@ defmodule Plausible.Billing do
defp present?(nil), do: false
defp present?(_), do: true
defp check_lock_status({:ok, subscription}) do
user =
Repo.get(Plausible.Auth.User, subscription.user_id)
|> Map.put(:subscription, subscription)
defp maybe_remove_grace_period({:ok, user}) do
alias Plausible.Auth.GracePeriod
case user.grace_period do
%GracePeriod{allowance_required: allowance_required} ->
new_allowance = Plausible.Billing.Plans.allowance(user.subscription)
if new_allowance > allowance_required do
Plausible.Auth.User.remove_grace_period(user)
|> Repo.update()
else
{:ok, user}
end
_ ->
{:ok, user}
end
end
defp maybe_remove_grace_period(err), do: err
defp check_lock_status({:ok, user}) do
Plausible.Billing.SiteLocker.check_sites_for(user)
{:ok, subscription}
{:ok, user}
end
defp check_lock_status(err), do: err
defp maybe_adjust_api_key_limits({:ok, subscription}) do
defp maybe_adjust_api_key_limits({:ok, user}) do
plan =
Repo.get_by(Plausible.Billing.EnterprisePlan,
user_id: subscription.user_id,
paddle_plan_id: subscription.paddle_plan_id
user_id: user.id,
paddle_plan_id: user.subscription.paddle_plan_id
)
if plan do
user_id = subscription.user_id
user_id = user.id
api_keys = from(key in Plausible.Auth.ApiKey, where: key.user_id == ^user_id)
Repo.update_all(api_keys, set: [hourly_request_limit: plan.hourly_api_request_limit])
end
{:ok, subscription}
{:ok, user}
end
defp maybe_adjust_api_key_limits(err), do: err

View File

@ -96,7 +96,7 @@ defmodule Plausible.Workers.CheckUsage do
)
Plausible.Mailer.send_email_safe(template)
Plausible.Auth.User.start_grace_period(subscriber) |> Repo.update()
Plausible.Auth.User.start_grace_period(subscriber, last_cycle_usage) |> Repo.update()
_ ->
nil

View File

@ -3,7 +3,7 @@ defmodule Plausible.Repo.Migrations.GracePeriodEnd do
def change do
alter table(:users) do
add :grace_period_end, :date
add :grace_period, :map
end
end
end

View File

@ -229,7 +229,8 @@ defmodule Plausible.BillingTest do
end
@subscription_id "subscription-123"
@plan_id "plan-123"
@plan_id_10k "654177"
@plan_id_100k "654178"
describe "subscription_created" do
test "creates a subscription" do
@ -238,7 +239,7 @@ defmodule Plausible.BillingTest do
Billing.subscription_created(%{
"alert_name" => "subscription_created",
"subscription_id" => @subscription_id,
"subscription_plan_id" => @plan_id,
"subscription_plan_id" => @plan_id_10k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"passthrough" => user.id,
@ -263,7 +264,7 @@ defmodule Plausible.BillingTest do
"email" => user.email,
"alert_name" => "subscription_created",
"subscription_id" => @subscription_id,
"subscription_plan_id" => @plan_id,
"subscription_plan_id" => @plan_id_10k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"status" => "active",
@ -285,7 +286,7 @@ defmodule Plausible.BillingTest do
Billing.subscription_created(%{
"alert_name" => "subscription_created",
"subscription_id" => @subscription_id,
"subscription_plan_id" => @plan_id,
"subscription_plan_id" => @plan_id_10k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"passthrough" => user.id,
@ -304,7 +305,7 @@ defmodule Plausible.BillingTest do
plan =
insert(:enterprise_plan,
user: user,
paddle_plan_id: @plan_id,
paddle_plan_id: @plan_id_10k,
hourly_api_request_limit: 10_000
)
@ -313,7 +314,7 @@ defmodule Plausible.BillingTest do
Billing.subscription_created(%{
"alert_name" => "subscription_created",
"subscription_id" => @subscription_id,
"subscription_plan_id" => @plan_id,
"subscription_plan_id" => @plan_id_10k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"passthrough" => user.id,
@ -401,6 +402,66 @@ defmodule Plausible.BillingTest do
assert Repo.reload!(api_key).hourly_request_limit == plan.hourly_api_request_limit
end
test "if user's grace period has ended, upgrading to the proper plan will unlock sites and remove grace period" do
user =
insert(:user,
grace_period: %Plausible.Auth.GracePeriod{
end_date: Timex.shift(Timex.today(), days: -1),
allowance_required: 11_000
}
)
subscription = insert(:subscription, user: user)
site = insert(:site, locked: true, members: [user])
Billing.subscription_updated(%{
"alert_name" => "subscription_updated",
"subscription_id" => subscription.paddle_subscription_id,
"subscription_plan_id" => @plan_id_100k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"passthrough" => user.id,
"old_status" => "past_due",
"status" => "active",
"next_bill_date" => "2019-06-01",
"new_unit_price" => "12.00",
"currency" => "EUR"
})
assert Repo.reload!(site).locked == false
assert Repo.reload!(user).grace_period == nil
end
test "does not remove grace period if upgraded plan allowance is too low" do
user =
insert(:user,
grace_period: %Plausible.Auth.GracePeriod{
end_date: Timex.shift(Timex.today(), days: -1),
allowance_required: 11_000
}
)
subscription = insert(:subscription, user: user)
site = insert(:site, locked: true, members: [user])
Billing.subscription_updated(%{
"alert_name" => "subscription_updated",
"subscription_id" => subscription.paddle_subscription_id,
"subscription_plan_id" => @plan_id_10k,
"update_url" => "update_url.com",
"cancel_url" => "cancel_url.com",
"passthrough" => user.id,
"old_status" => "past_due",
"status" => "active",
"next_bill_date" => "2019-06-01",
"new_unit_price" => "12.00",
"currency" => "EUR"
})
assert Repo.reload!(site).locked == true
assert Repo.reload!(user).grace_period.allowance_required == 11_000
end
end
describe "subscription_cancelled" do

View File

@ -50,7 +50,14 @@ defmodule Plausible.Billing.SiteLockerTest do
end
test "does not lock user who has an active subscription and is on grace period" do
user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: 1))
user =
insert(:user,
grace_period: %Plausible.Auth.GracePeriod{
end_date: Timex.shift(Timex.today(), days: 1),
allowance_required: 10_000
}
)
insert(:subscription, status: "active", user: user)
user = Repo.preload(user, :subscription)
site = insert(:site, members: [user])
@ -79,7 +86,14 @@ defmodule Plausible.Billing.SiteLockerTest do
end
test "locks all sites if user has active subscription but grace period has ended" do
user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: -1))
user =
insert(:user,
grace_period: %Plausible.Auth.GracePeriod{
end_date: Timex.shift(Timex.today(), days: -1),
allowance_required: 10_000
}
)
insert(:subscription, status: "active", user: user)
user = Repo.preload(user, :subscription)
site = insert(:site, members: [user])
@ -90,7 +104,14 @@ defmodule Plausible.Billing.SiteLockerTest do
end
test "sends email if grace period has ended" do
user = insert(:user, grace_period_end: Timex.shift(Timex.today(), days: -1))
user =
insert(:user,
grace_period: %Plausible.Auth.GracePeriod{
end_date: Timex.shift(Timex.today(), days: -1),
allowance_required: 10_000
}
)
insert(:subscription, status: "active", user: user)
user = Repo.preload(user, :subscription)
insert(:site, members: [user])

View File

@ -24,7 +24,7 @@ defmodule Plausible.Workers.CheckUsageTest do
CheckUsage.perform(nil)
assert_no_emails_delivered()
assert Repo.reload(user).grace_period_end == nil
assert Repo.reload(user).grace_period == nil
end
test "does not send an email if account has been over the limit for one billing month", %{
@ -46,7 +46,7 @@ defmodule Plausible.Workers.CheckUsageTest do
CheckUsage.perform(nil, billing_stub)
assert_no_emails_delivered()
assert Repo.reload(user).grace_period_end == nil
assert Repo.reload(user).grace_period == nil
end
test "sends an email when an account is over their limit for two consecutive billing months", %{
@ -72,7 +72,7 @@ defmodule Plausible.Workers.CheckUsageTest do
subject: "[Action required] You have outgrown your Plausible subscription tier"
)
assert Repo.reload(user).grace_period_end == Timex.shift(Timex.today(), days: 7)
assert Repo.reload(user).grace_period.end_date == Timex.shift(Timex.today(), days: 7)
end
describe "enterprise customers" do