2021-02-12 11:17:53 +03:00
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
2021-04-26 11:32:18 +03:00
def perform ( _job , billing_mod \\ Plausible.Billing , today \\ Timex . today ( ) ) do
2021-03-29 14:53:34 +03:00
yesterday = today |> Timex . shift ( days : - 1 )
2021-02-12 11:17:53 +03:00
active_subscribers =
Repo . all (
from u in Plausible.Auth.User ,
join : s in Plausible.Billing.Subscription ,
on : s . user_id == u . id ,
2021-10-20 17:49:11 +03:00
left_join : ep in Plausible.Billing.EnterprisePlan ,
on : ep . user_id == u . id ,
2021-12-02 12:42:34 +03:00
where : is_nil ( u . grace_period ) ,
2021-02-12 11:17:53 +03:00
where : s . status == " active " ,
2021-03-01 17:51:57 +03:00
where : not is_nil ( s . last_bill_date ) ,
2021-02-12 11:17:53 +03:00
# 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 ) ,
2021-10-20 17:49:11 +03:00
preload : [ subscription : s , enterprise_plan : ep ]
2021-02-12 11:17:53 +03:00
)
for subscriber <- active_subscribers do
2021-10-22 12:26:07 +03:00
if subscriber . enterprise_plan do
check_enterprise_subscriber ( subscriber , billing_mod )
else
check_regular_subscriber ( subscriber , billing_mod )
end
end
2021-02-12 11:17:53 +03:00
2021-10-22 12:26:07 +03:00
:ok
end
2021-05-11 11:30:47 +03:00
2021-10-22 12:26:07 +03:00
def check_enterprise_subscriber ( subscriber , billing_mod ) do
pageview_limit = check_pageview_limit ( subscriber , billing_mod )
site_limit = check_site_limit ( subscriber )
2021-05-10 12:52:42 +03:00
2021-10-22 12:26:07 +03:00
case { pageview_limit , site_limit } do
{ { :within_limit , _ } , { :within_limit , _ } } ->
nil
2021-10-20 17:49:11 +03:00
2021-10-22 12:26:07 +03:00
{ { _ , { last_cycle , last_cycle_usage } } , { _ , { site_usage , site_allowance } } } ->
template =
2022-09-20 11:46:28 +03:00
PlausibleWeb.Email . enterprise_over_limit_internal_email (
2021-10-22 12:26:07 +03:00
subscriber ,
last_cycle_usage ,
last_cycle ,
site_usage ,
site_allowance
)
2021-10-20 17:49:11 +03:00
2022-10-24 13:13:23 +03:00
Plausible.Mailer . send ( template )
2022-09-20 11:46:28 +03:00
subscriber
|> Plausible.Auth.GracePeriod . start_manual_lock_changeset ( last_cycle_usage )
|> Repo . update ( )
2021-10-22 12:26:07 +03:00
end
end
2021-10-20 17:49:11 +03:00
2021-10-22 12:26:07 +03:00
defp check_regular_subscriber ( subscriber , billing_mod ) do
case check_pageview_limit ( subscriber , billing_mod ) do
{ :over_limit , { last_cycle , last_cycle_usage } } ->
2021-11-23 12:21:22 +03:00
suggested_plan = Plausible.Billing.Plans . suggested_plan ( subscriber , last_cycle_usage )
2021-10-20 17:49:11 +03:00
2021-10-22 12:26:07 +03:00
template =
PlausibleWeb.Email . over_limit_email (
subscriber ,
last_cycle_usage ,
last_cycle ,
suggested_plan
)
2022-10-24 13:13:23 +03:00
Plausible.Mailer . send ( template )
2022-09-20 11:46:28 +03:00
subscriber
|> Plausible.Auth.GracePeriod . start_changeset ( last_cycle_usage )
|> Repo . update ( )
2021-10-22 12:26:07 +03:00
_ ->
nil
2021-02-12 11:17:53 +03:00
end
2021-10-22 12:26:07 +03:00
end
2021-02-12 11:17:53 +03:00
2021-10-22 12:26:07 +03:00
defp check_pageview_limit ( subscriber , billing_mod ) do
2021-11-29 13:04:02 +03:00
allowance =
case Plausible.Billing.Plans . allowance ( subscriber . subscription ) do
allowance when is_number ( allowance ) ->
allowance * 1.1
_allowance ->
Sentry . capture_message ( " Unable to calculate allowance " ,
user : subscriber ,
subscription : subscriber . subscription
)
end
2021-10-22 12:26:07 +03:00
{ _ , last_cycle } = billing_mod . last_two_billing_cycles ( subscriber )
{ last_last_cycle_usage , last_cycle_usage } =
billing_mod . last_two_billing_months_usage ( subscriber )
2021-11-04 12:46:41 +03:00
if last_last_cycle_usage >= allowance && last_cycle_usage >= allowance do
2021-10-22 12:38:47 +03:00
{ :over_limit , { last_cycle , last_cycle_usage } }
2021-10-22 12:26:07 +03:00
else
{ :within_limit , { last_cycle , last_cycle_usage } }
end
end
defp check_site_limit ( subscriber ) do
allowance = subscriber . enterprise_plan . site_limit
2022-09-01 17:09:28 +03:00
total_sites = Plausible.Sites . owned_sites_count ( subscriber )
2021-10-22 12:26:07 +03:00
if total_sites >= allowance do
{ :over_limit , { total_sites , allowance } }
else
{ :within_limit , { total_sites , allowance } }
end
2021-02-12 11:17:53 +03:00
end
end