mirror of
https://github.com/plausible/analytics.git
synced 2024-11-26 23:27:54 +03:00
Track billing cycles (#697)
* Add dummy check usage worker * Add and persist last_bill_date * Remove name clash * Correct timing and suggestions for over limit emails * Fix tests for trial upgrade notifications
This commit is contained in:
parent
77628d04c9
commit
a8cb187e8d
@ -65,7 +65,8 @@ defmodule Plausible.Billing do
|
||||
changeset =
|
||||
Subscription.changeset(subscription, %{
|
||||
next_bill_amount: amount,
|
||||
next_bill_date: api_subscription["next_payment"]["date"]
|
||||
next_bill_date: api_subscription["next_payment"]["date"],
|
||||
last_bill_date: params["event_time"]
|
||||
})
|
||||
|
||||
Repo.update(changeset)
|
||||
@ -133,6 +134,10 @@ defmodule Plausible.Billing do
|
||||
pageviews + custom_events
|
||||
end
|
||||
|
||||
def last_two_billing_months_usage(_user) do
|
||||
{1, 2}
|
||||
end
|
||||
|
||||
def usage_breakdown(user) do
|
||||
user = Repo.preload(user, :sites)
|
||||
|
||||
|
@ -1,44 +1,67 @@
|
||||
defmodule Plausible.Billing.Plans do
|
||||
@plans %{
|
||||
monthly: %{
|
||||
"10k": %{product_id: "558018", due_now: "$6"},
|
||||
"100k": %{product_id: "558745", due_now: "$12"},
|
||||
"200k": %{product_id: "597485", due_now: "$18"},
|
||||
"500k": %{product_id: "597487", due_now: "$27"},
|
||||
"1m": %{product_id: "597642", due_now: "$48"},
|
||||
"2m": %{product_id: "597309", due_now: "$69"},
|
||||
"5m": %{product_id: "597311", due_now: "$99"},
|
||||
"10m": %{product_id: "642352", due_now: "$150"},
|
||||
"20m": %{product_id: "642355", due_now: "$225"}
|
||||
},
|
||||
yearly: %{
|
||||
"10k": %{product_id: "572810", due_now: "$48"},
|
||||
"100k": %{product_id: "590752", due_now: "$96"},
|
||||
"200k": %{product_id: "597486", due_now: "$144"},
|
||||
"500k": %{product_id: "597488", due_now: "$216"},
|
||||
"1m": %{product_id: "597643", due_now: "$384"},
|
||||
"2m": %{product_id: "597310", due_now: "$552"},
|
||||
"5m": %{product_id: "597312", due_now: "$792"},
|
||||
"10m": %{product_id: "642354", due_now: "$1200"},
|
||||
"20m": %{product_id: "642356", due_now: "$1800"}
|
||||
}
|
||||
}
|
||||
@monthly_plans [
|
||||
%{product_id: "558018", cost: "$6", limit: 10_000, cycle: "monthly"},
|
||||
%{product_id: "558745", cost: "$12", limit: 100_000, cycle: "monthly"},
|
||||
%{product_id: "597485", cost: "$18", limit: 200_000, cycle: "monthly"},
|
||||
%{product_id: "597487", cost: "$27", limit: 500_000, cycle: "monthly"},
|
||||
%{product_id: "597642", cost: "$48", limit: 1_000_000, cycle: "monthly"},
|
||||
%{product_id: "597309", cost: "$69", limit: 2_000_000, cycle: "monthly"},
|
||||
%{product_id: "597311", cost: "$99", limit: 5_000_000, cycle: "monthly"},
|
||||
%{product_id: "642352", cost: "$150", limit: 10_000_000, cycle: "monthly"},
|
||||
%{product_id: "642355", cost: "$225", limit: 20_000_000, cycle: "monthly"}
|
||||
]
|
||||
|
||||
@yearly_plans [
|
||||
%{product_id: "572810", cost: "$48", limit: 10_000, cycle: "yearly"},
|
||||
%{product_id: "590752", cost: "$96", limit: 100_000, cycle: "yearly"},
|
||||
%{product_id: "597486", cost: "$144", limit: 200_000, cycle: "yearly"},
|
||||
%{product_id: "597488", cost: "$216", limit: 500_000, cycle: "yearly"},
|
||||
%{product_id: "597643", cost: "$384", limit: 1_000_000, cycle: "yearly"},
|
||||
%{product_id: "597310", cost: "$552", limit: 2_000_000, cycle: "yearly"},
|
||||
%{product_id: "597312", cost: "$792", limit: 5_000_000, cycle: "yearly"},
|
||||
%{product_id: "642354", cost: "$1200", limit: 10_000_000, cycle: "yearly"},
|
||||
%{product_id: "642356", cost: "$1800", limit: 20_000_000, cycle: "yearly"}
|
||||
]
|
||||
|
||||
@all_plans @monthly_plans ++ @yearly_plans
|
||||
|
||||
def plans do
|
||||
@plans
|
||||
monthly =
|
||||
@monthly_plans
|
||||
|> Enum.map(fn plan -> {String.to_atom(number_format(plan[:limit])), plan} end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
yearly =
|
||||
@yearly_plans
|
||||
|> Enum.map(fn plan -> {String.to_atom(number_format(plan[:limit])), plan} end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
%{
|
||||
monthly: monthly,
|
||||
yearly: yearly
|
||||
}
|
||||
end
|
||||
|
||||
def suggested_plan_name(usage) do
|
||||
plan = suggested_plan(usage)
|
||||
number_format(plan[:limit]) <> "/mo"
|
||||
end
|
||||
|
||||
def suggested_plan_cost(usage) do
|
||||
plan = suggested_plan(usage)
|
||||
plan[:cost] <> "/mo"
|
||||
end
|
||||
|
||||
defp suggested_plan(usage) do
|
||||
Enum.find(@monthly_plans, fn plan -> usage < plan[:limit] end)
|
||||
end
|
||||
|
||||
def allowance(subscription) do
|
||||
allowed_volume = %{
|
||||
"free_10k" => 10_000,
|
||||
"558018" => 10_000,
|
||||
"572810" => 10_000,
|
||||
"558745" => 100_000,
|
||||
"590752" => 100_000,
|
||||
"558746" => 1_000_000,
|
||||
"590753" => 1_000_000
|
||||
}
|
||||
Enum.find(@all_plans, fn plan -> plan[:product_id] == subscription.paddle_plan_id end)
|
||||
|> Map.fetch!(:limit)
|
||||
end
|
||||
|
||||
allowed_volume[subscription.paddle_plan_id]
|
||||
defp number_format(num) do
|
||||
PlausibleWeb.StatsView.large_number_format(num)
|
||||
end
|
||||
end
|
||||
|
@ -12,6 +12,8 @@ defmodule Plausible.Billing.Subscription do
|
||||
:next_bill_date,
|
||||
:user_id
|
||||
]
|
||||
|
||||
@optional_fields [:last_bill_date]
|
||||
@valid_statuses ["active", "past_due", "deleted", "paused"]
|
||||
|
||||
schema "subscriptions" do
|
||||
@ -22,6 +24,7 @@ defmodule Plausible.Billing.Subscription do
|
||||
field :status, :string
|
||||
field :next_bill_amount, :string
|
||||
field :next_bill_date, :date
|
||||
field :last_bill_date, :date
|
||||
|
||||
belongs_to :user, Plausible.Auth.User
|
||||
|
||||
@ -30,7 +33,7 @@ defmodule Plausible.Billing.Subscription do
|
||||
|
||||
def changeset(model, attrs \\ %{}) do
|
||||
model
|
||||
|> cast(attrs, @required_fields)
|
||||
|> cast(attrs, @required_fields ++ @optional_fields)
|
||||
|> validate_required(@required_fields)
|
||||
|> validate_inclusion(:status, @valid_statuses)
|
||||
|> unique_constraint(:paddle_subscription_id)
|
||||
|
@ -112,6 +112,18 @@ defmodule PlausibleWeb.Email do
|
||||
})
|
||||
end
|
||||
|
||||
def over_limit_email(user, usage) do
|
||||
base_email()
|
||||
# Temporary testing
|
||||
|> to(["uku@plausible.io", "marko@plausible.io"])
|
||||
|> tag("over-limit")
|
||||
|> subject("You have outgrown your Plausible subscription tier ")
|
||||
|> render("over_limit.html", %{
|
||||
user: user,
|
||||
usage: usage
|
||||
})
|
||||
end
|
||||
|
||||
def cancellation_email(user) do
|
||||
base_email()
|
||||
|> to(user.email)
|
||||
|
@ -60,7 +60,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-right">
|
||||
<div class="mb-4 text-sm font-medium dark:text-gray-100">Due today: <b x-text="window.plans[billingCycle][volume].due_now">$6</b></div>
|
||||
<div class="mb-4 text-sm font-medium dark:text-gray-100">Due today: <b x-text="window.plans[billingCycle][volume].cost">$6</b></div>
|
||||
<span class="inline-flex rounded-md shadow-sm">
|
||||
<button type="button" data-theme="none" :data-product="window.plans[billingCycle][volume].product_id" data-email="<%= @conn.assigns[:current_user].email %>" data-disable-logout="true" data-passthrough="<%= @conn.assigns[:current_user].id %>" data-success="/billing/upgrade-success" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent paddle_button leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<svg fill="currentColor" viewBox="0 0 20 20" class="inline w-4 h-4 mr-2"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"></path></svg>
|
||||
|
32
lib/plausible_web/templates/email/over_limit.html.eex
Normal file
32
lib/plausible_web/templates/email/over_limit.html.eex
Normal file
@ -0,0 +1,32 @@
|
||||
Hey <%= user_salutation(@user) %>,
|
||||
<br /><br />
|
||||
Thanks for being a Plausible Analytics subscriber!
|
||||
<br /><br />
|
||||
This is a friendly reminder that your traffic has exceeded your subscription tier two months in a row. Congrats on all that traffic!
|
||||
<br /><br />
|
||||
We don't enforce any hard limits at the moment, we're still counting your stats and you have access to your dashboard, but we kindly ask you to upgrade your subscription plan to accommodate your new traffic levels.
|
||||
<br /><br />
|
||||
In the last month, your account has used <%= @usage %> billable pageviews.
|
||||
<%= if @usage <= 20_000_000 do %>
|
||||
|
||||
Based on that we recommend you select the <%= Plausible.Billing.Plans.suggested_plan_name(@usage) %> plan which runs at <%= Plausible.Billing.Plans.suggested_plan_cost(@usage) %>. You can also go with yearly billing to get 33% off.
|
||||
<br /><br />
|
||||
You can upgrade your subscription using our self-serve platform. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
|
||||
<br /><br />
|
||||
<a href="https://plausible.io/settings">Click here</a> to go to your site settings. You can upgrade your subscription tier by clicking the 'change plan' link.
|
||||
<% else %>
|
||||
This is more than our standard plans, so please reply back to this email to get a quote for your volume.
|
||||
<% end %>
|
||||
<br /><br />
|
||||
Were the last two months extraordinary and you don't expect these higher traffic levels to continue? Reply to this email and we'll figure it out.
|
||||
<br /><br />
|
||||
Have questions or need help with anything? Just reply to this email and we'll gladly help.
|
||||
<br /><br />
|
||||
Thanks again for using our product and for your support!
|
||||
<br /><br />
|
||||
Uku and Marko
|
||||
<br /><br />
|
||||
--
|
||||
<br /><br />
|
||||
<%= plausible_url() %><br />
|
||||
{{{ pm:unsubscribe }}}
|
@ -3,8 +3,8 @@ Hey <%= user_salutation(@user) %>,
|
||||
Thanks for exploring Plausible, a simple and privacy-friendly alternative to Google Analytics. Your free 30-day trial is ending <%= @day %>, but you can keep using Plausible by upgrading to a paid plan.
|
||||
<br /><br />
|
||||
In the last month, your account has used <%= PlausibleWeb.AuthView.delimit_integer(@usage) %> billable pageviews<%= if @custom_events > 0, do: " and custom events in total", else: "" %>.
|
||||
<%= if @usage <= 4_500_000 do %>
|
||||
Based on that we recommend you select the <%= suggested_plan_name(@usage) %> plan which runs at <%= suggested_plan_cost(@usage) %>.
|
||||
<%= if @usage <= 20_000_000 do %>
|
||||
Based on that we recommend you select the <%= Plausible.Billing.Plans.suggested_plan_name(@usage) %> plan which runs at <%= Plausible.Billing.Plans.suggested_plan_cost(@usage) %>.
|
||||
|
||||
You can also go with yearly billing to get 33% off on your plan.
|
||||
<br /><br />
|
||||
|
@ -20,60 +20,4 @@ defmodule PlausibleWeb.EmailView do
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def suggested_plan_name(usage) do
|
||||
cond do
|
||||
usage <= 9_000 ->
|
||||
"10k/mo"
|
||||
|
||||
usage <= 90_000 ->
|
||||
"100k/mo"
|
||||
|
||||
usage <= 180_000 ->
|
||||
"200k/mo"
|
||||
|
||||
usage <= 450_000 ->
|
||||
"500k/mo"
|
||||
|
||||
usage <= 900_000 ->
|
||||
"1m/mo"
|
||||
|
||||
usage <= 1_800_000 ->
|
||||
"2m/mo"
|
||||
|
||||
usage <= 4_500_000 ->
|
||||
"5m/mo"
|
||||
|
||||
true ->
|
||||
throw("Huge account")
|
||||
end
|
||||
end
|
||||
|
||||
def suggested_plan_cost(usage) do
|
||||
cond do
|
||||
usage <= 9_000 ->
|
||||
"$6/mo"
|
||||
|
||||
usage <= 90_000 ->
|
||||
"$12/mo"
|
||||
|
||||
usage <= 180_000 ->
|
||||
"$18/mo"
|
||||
|
||||
usage <= 450_000 ->
|
||||
"$27/mo"
|
||||
|
||||
usage <= 900_000 ->
|
||||
"$48/mo"
|
||||
|
||||
usage <= 1_800_000 ->
|
||||
"$69/mo"
|
||||
|
||||
usage <= 4_500_000 ->
|
||||
"$99/mo"
|
||||
|
||||
true ->
|
||||
throw("Huge account")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
61
lib/workers/check_usage.ex
Normal file
61
lib/workers/check_usage.ex
Normal file
@ -0,0 +1,61 @@
|
||||
defmodule Plausible.Workers.CheckUsage do
|
||||
use Plausible.Repo
|
||||
use Oban.Worker, queue: :check_usage
|
||||
|
||||
defmacro yesterday() do
|
||||
quote do
|
||||
fragment("now() - INTERVAL '1 day'")
|
||||
end
|
||||
end
|
||||
|
||||
defmacro last_day_of_month(day) do
|
||||
quote do
|
||||
fragment(
|
||||
"(date_trunc('month', ?::date) + interval '1 month' - interval '1 day')::date",
|
||||
unquote(day)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defmacro day_of_month(date) do
|
||||
quote do
|
||||
fragment("EXTRACT(day from ?::date)", unquote(date))
|
||||
end
|
||||
end
|
||||
|
||||
defmacro least(left, right) do
|
||||
quote do
|
||||
fragment("least(?, ?)", unquote(left), unquote(right))
|
||||
end
|
||||
end
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(_args, _job, billing_mod \\ Plausible.Billing) do
|
||||
yesterday = Timex.today() |> Timex.shift(days: -1)
|
||||
|
||||
active_subscribers =
|
||||
Repo.all(
|
||||
from u in Plausible.Auth.User,
|
||||
join: s in Plausible.Billing.Subscription,
|
||||
on: s.user_id == u.id,
|
||||
where: s.status == "active",
|
||||
# Accounts for situations like last_bill_date==2021-01-31 AND today==2021-03-01. Since February never reaches the 31st day, the account is checked on 2021-03-01.
|
||||
where:
|
||||
least(day_of_month(s.last_bill_date), day_of_month(last_day_of_month(^yesterday))) ==
|
||||
day_of_month(^yesterday),
|
||||
preload: [subscription: s]
|
||||
)
|
||||
|
||||
for subscriber <- active_subscribers do
|
||||
allowance = Plausible.Billing.Plans.allowance(subscriber.subscription)
|
||||
{last_last_month, last_month} = billing_mod.last_two_billing_months_usage(subscriber)
|
||||
|
||||
if last_last_month > allowance && last_month > allowance do
|
||||
template = PlausibleWeb.Email.over_limit_email(subscriber, last_month)
|
||||
Plausible.Mailer.send_email(template)
|
||||
end
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
@ -0,0 +1,9 @@
|
||||
defmodule Plausible.Repo.Migrations.AddLastPaymentDetails do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:subscriptions) do
|
||||
add :last_bill_date, :date
|
||||
end
|
||||
end
|
||||
end
|
@ -220,18 +220,20 @@ defmodule Plausible.BillingTest do
|
||||
end
|
||||
|
||||
describe "subscription_payment_succeeded" do
|
||||
test "sets the next bill amount and date" do
|
||||
test "sets the next bill amount and date, last bill date" do
|
||||
user = insert(:user)
|
||||
subscription = insert(:subscription, user: user)
|
||||
|
||||
Billing.subscription_payment_succeeded(%{
|
||||
"alert_name" => "subscription_payment_succeeded",
|
||||
"subscription_id" => subscription.paddle_subscription_id
|
||||
"subscription_id" => subscription.paddle_subscription_id,
|
||||
"event_time" => "2019-06-10 09:40:20"
|
||||
})
|
||||
|
||||
subscription = Repo.get_by(Plausible.Billing.Subscription, user_id: user.id)
|
||||
assert subscription.next_bill_date == ~D[2019-07-10]
|
||||
assert subscription.next_bill_amount == "6.00"
|
||||
assert subscription.last_bill_date == ~D[2019-06-10]
|
||||
end
|
||||
|
||||
test "ignores if the subscription cannot be found" do
|
||||
|
13
test/plausible/billing/plans_test.exs
Normal file
13
test/plausible/billing/plans_test.exs
Normal file
@ -0,0 +1,13 @@
|
||||
defmodule Plausible.Billing.PlansTest do
|
||||
use Plausible.DataCase
|
||||
use Bamboo.Test, shared: true
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
test "suggested plan name" do
|
||||
assert Plans.suggested_plan_name(110_000) == "200k/mo"
|
||||
end
|
||||
|
||||
test "suggested plan cost" do
|
||||
assert Plans.suggested_plan_cost(110_000) == "$18/mo"
|
||||
end
|
||||
end
|
146
test/workers/check_usage_test.exs
Normal file
146
test/workers/check_usage_test.exs
Normal file
@ -0,0 +1,146 @@
|
||||
defmodule Plausible.Workers.CheckUsageTest do
|
||||
use Plausible.DataCase
|
||||
use Bamboo.Test
|
||||
import Double
|
||||
import Plausible.TestUtils
|
||||
alias Plausible.Workers.CheckUsage
|
||||
alias Plausible.Billing.Plans
|
||||
|
||||
setup [:create_user, :create_site]
|
||||
@paddle_id_10k Plans.plans()[:monthly][:"10k"][:product_id]
|
||||
|
||||
test "ignores user without subscription" do
|
||||
CheckUsage.perform(nil, nil)
|
||||
|
||||
assert_no_emails_delivered()
|
||||
end
|
||||
|
||||
test "ignores user with subscription but no usage", %{user: user} do
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil)
|
||||
|
||||
assert_no_emails_delivered()
|
||||
end
|
||||
|
||||
test "does not send an email if account has been over the limit for one billing month", %{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {9_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_no_emails_delivered()
|
||||
end
|
||||
|
||||
test "sends an email when an account is over their limit for two consecutive billing months", %{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {11_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
# to: [user],
|
||||
subject: "You have outgrown your Plausible subscription tier "
|
||||
)
|
||||
end
|
||||
|
||||
describe "timing" do
|
||||
test "checks usage one day after the last_bill_date", %{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {11_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
# to: [user],
|
||||
subject: "You have outgrown your Plausible subscription tier "
|
||||
)
|
||||
end
|
||||
|
||||
test "for yearly subscriptions, does not check exactly one month after last_bill_date", %{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {11_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), months: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_no_emails_delivered()
|
||||
end
|
||||
|
||||
test "for yearly subscriptions, checks usage one month + one day after the last_bill_date", %{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {11_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), months: -1, days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
# to: [user],
|
||||
subject: "You have outgrown your Plausible subscription tier "
|
||||
)
|
||||
end
|
||||
|
||||
test "for yearly subscriptions, checks usage multiple months + one day after the last_bill_date",
|
||||
%{
|
||||
user: user
|
||||
} do
|
||||
billing_stub =
|
||||
stub(Plausible.Billing, :last_two_billing_months_usage, fn _user -> {11_000, 11_000} end)
|
||||
|
||||
insert(:subscription,
|
||||
user: user,
|
||||
paddle_plan_id: @paddle_id_10k,
|
||||
last_bill_date: Timex.shift(Timex.today(), months: -2, days: -1)
|
||||
)
|
||||
|
||||
CheckUsage.perform(nil, nil, billing_stub)
|
||||
|
||||
assert_email_delivered_with(
|
||||
# to: [user],
|
||||
subject: "You have outgrown your Plausible subscription tier "
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
@ -134,10 +134,24 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
|
||||
assert email.html_body =~ "we recommend you select the 5m/mo plan which runs at $99/mo."
|
||||
end
|
||||
|
||||
test "suggests 10m/mo plan" do
|
||||
user = insert(:user)
|
||||
|
||||
email = PlausibleWeb.Email.trial_upgrade_email(user, "today", {9_000_000, 0})
|
||||
assert email.html_body =~ "we recommend you select the 10m/mo plan which runs at $150/mo."
|
||||
end
|
||||
|
||||
test "suggests 20m/mo plan" do
|
||||
user = insert(:user)
|
||||
|
||||
email = PlausibleWeb.Email.trial_upgrade_email(user, "today", {19_000_000, 0})
|
||||
assert email.html_body =~ "we recommend you select the 20m/mo plan which runs at $225/mo."
|
||||
end
|
||||
|
||||
test "does not suggest a plan above that" do
|
||||
user = insert(:user)
|
||||
|
||||
email = PlausibleWeb.Email.trial_upgrade_email(user, "today", {10_000_000, 0})
|
||||
email = PlausibleWeb.Email.trial_upgrade_email(user, "today", {50_000_000, 0})
|
||||
assert email.html_body =~ "please reply back to this email to get a quote for your volume"
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user