defmodule Plausible.Workers.CheckUsageTest do use Plausible.DataCase, async: true use Bamboo.Test import Double alias Plausible.Workers.CheckUsage setup [:create_user, :create_site] @paddle_id_10k "558018" @date_range Date.range(Timex.today(), Timex.today()) test "ignores user without subscription" do CheckUsage.perform(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) assert_no_emails_delivered() 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", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 9_000}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_no_emails_delivered() assert Repo.reload(user).grace_period == nil end test "does not send an email if account is over the limit by less than 10%", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 10_999}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_no_emails_delivered() assert Repo.reload(user).grace_period == nil end test "sends an email when an account is over their limit for two consecutive billing months", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_email_delivered_with( to: [user], subject: "[Action required] You have outgrown your Plausible subscription tier" ) assert Repo.reload(user).grace_period.end_date == Timex.shift(Timex.today(), days: 7) end test "sends an email suggesting enterprise plan when usage is greater than 10M ", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000_000}, last_cycle: %{date_range: @date_range, total: 11_000_000} } end) insert(:subscription, user: user, paddle_plan_id: @paddle_id_10k, last_bill_date: Timex.shift(Timex.today(), days: -1) ) CheckUsage.perform(nil, quota_stub) assert_delivered_email_matches(%{html_body: html_body}) assert html_body =~ "Your usage exceeds our standard plans, so please reply back to this email for a tailored quote" end test "skips checking users who already have a grace period", %{user: user} do %{grace_period: existing_grace_period} = user |> Plausible.Auth.GracePeriod.start_changeset() |> Repo.update!() quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_no_emails_delivered() assert Repo.reload(user).grace_period.id == existing_grace_period.id end test "recommends a plan to upgrade to", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_delivered_email_matches(%{ html_body: html_body }) assert html_body =~ "We recommend you upgrade to the 100k/mo plan" end describe "enterprise customers" do test "checks billable pageview usage for enterprise customer, sends usage information to enterprise@plausible.io", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 1_100_000}, last_cycle: %{date_range: @date_range, total: 1_100_000} } end) enterprise_plan = insert(:enterprise_plan, user: user, monthly_pageview_limit: 1_000_000) insert(:subscription, user: user, paddle_plan_id: enterprise_plan.paddle_plan_id, last_bill_date: Timex.shift(Timex.today(), days: -1) ) CheckUsage.perform(nil, quota_stub) assert_email_delivered_with( to: [{nil, "enterprise@plausible.io"}], subject: "#{user.email} has outgrown their enterprise plan" ) end test "checks site limit for enterprise customer, sends usage information to enterprise@plausible.io", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 1}, last_cycle: %{date_range: @date_range, total: 1} } end) enterprise_plan = insert(:enterprise_plan, user: user, site_limit: 2) insert(:site, members: [user]) insert(:site, members: [user]) insert(:site, members: [user]) insert(:subscription, user: user, paddle_plan_id: enterprise_plan.paddle_plan_id, last_bill_date: Timex.shift(Timex.today(), days: -1) ) CheckUsage.perform(nil, quota_stub) assert_email_delivered_with( to: [{nil, "enterprise@plausible.io"}], subject: "#{user.email} has outgrown their enterprise plan" ) end test "starts grace period when plan is outgrown", %{user: user} do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 1_100_000}, last_cycle: %{date_range: @date_range, total: 1_100_000} } end) enterprise_plan = insert(:enterprise_plan, user: user, monthly_pageview_limit: 1_000_000) insert(:subscription, user: user, paddle_plan_id: enterprise_plan.paddle_plan_id, last_bill_date: Timex.shift(Timex.today(), days: -1) ) CheckUsage.perform(nil, quota_stub) assert user |> Repo.reload() |> Plausible.Auth.GracePeriod.active?() end end describe "timing" do test "checks usage one day after the last_bill_date", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 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, quota_stub) assert_email_delivered_with( to: [user], subject: "[Action required] You have outgrown your Plausible subscription tier" ) end test "does not check exactly one month after last_bill_date", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 11_000} } end) insert(:subscription, user: user, paddle_plan_id: @paddle_id_10k, last_bill_date: ~D[2021-03-28] ) CheckUsage.perform(nil, quota_stub, ~D[2021-03-28]) assert_no_emails_delivered() end test "for yearly subscriptions, checks usage multiple months + one day after the last_bill_date", %{ user: user } do quota_stub = Plausible.Billing.Quota |> stub(:monthly_pageview_usage, fn _user -> %{ penultimate_cycle: %{date_range: @date_range, total: 11_000}, last_cycle: %{date_range: @date_range, total: 11_000} } end) insert(:subscription, user: user, paddle_plan_id: @paddle_id_10k, last_bill_date: ~D[2021-06-29] ) CheckUsage.perform(nil, quota_stub, ~D[2021-08-30]) assert_email_delivered_with( to: [user], subject: "[Action required] You have outgrown your Plausible subscription tier" ) end end end