134 lines
3.6 KiB
Elixir
134 lines
3.6 KiB
Elixir
defmodule Plausible.Billing do
|
|
use Plausible.Repo
|
|
alias Plausible.Billing.{Subscription, Plans, PaddleApi}
|
|
@paddle_api Application.fetch_env!(:plausible, :paddle_api)
|
|
|
|
def active_subscription_for(user_id) do
|
|
Repo.get_by(Subscription, user_id: user_id, status: "active")
|
|
end
|
|
|
|
def subscription_created(params) do
|
|
changeset = Subscription.changeset(%Subscription{}, format_subscription(params))
|
|
|
|
Repo.insert(changeset)
|
|
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)
|
|
end
|
|
|
|
def subscription_cancelled(params) do
|
|
subscription = Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
|
|
|
|
if subscription do
|
|
changeset = Subscription.changeset(subscription, %{
|
|
status: params["status"]
|
|
})
|
|
|
|
Repo.update(changeset)
|
|
else
|
|
{:ok, nil}
|
|
end
|
|
end
|
|
|
|
def subscription_payment_succeeded(params) do
|
|
subscription = Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
|
|
|
|
if subscription do
|
|
{:ok, api_subscription} = @paddle_api.get_subscription(subscription.paddle_subscription_id)
|
|
amount = :erlang.float_to_binary(api_subscription["next_payment"]["amount"] / 1, decimals: 2)
|
|
|
|
changeset = Subscription.changeset(subscription, %{
|
|
next_bill_amount: amount,
|
|
next_bill_date: api_subscription["next_payment"]["date"]
|
|
})
|
|
|
|
Repo.update(changeset)
|
|
else
|
|
{:ok, nil}
|
|
end
|
|
end
|
|
|
|
def change_plan(user, new_plan) do
|
|
subscription = active_subscription_for(user.id)
|
|
|
|
res = PaddleApi.update_subscription(subscription.paddle_subscription_id, %{
|
|
plan_id: Plans.paddle_id_for_plan(new_plan)
|
|
})
|
|
|
|
case res do
|
|
{:ok, response} ->
|
|
Subscription.changeset(subscription, %{
|
|
paddle_plan_id: Integer.to_string(response["plan_id"])
|
|
}) |> Repo.update
|
|
e -> e
|
|
end
|
|
end
|
|
|
|
def needs_to_upgrade?(user) do
|
|
if Timex.before?(trial_end_date(user), Timex.today()) do
|
|
!active_subscription_for(user.id)
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def coupon_for(user) do
|
|
if was_beta_user(user) do
|
|
"8FE5AF26"
|
|
end
|
|
end
|
|
|
|
def was_beta_user(user) do
|
|
Timex.before?(user.inserted_at, ~D[2019-04-25])
|
|
end
|
|
|
|
def trial_days_left(user) do
|
|
if Timex.before?(user.inserted_at, ~D[2019-04-24]) do
|
|
Timex.diff(~D[2019-05-25], Timex.today, :days) + 1
|
|
else
|
|
30 - Timex.diff(Timex.today, user.inserted_at, :days)
|
|
end
|
|
end
|
|
|
|
def trial_end_date(user) do
|
|
if Timex.before?(user.inserted_at, ~D[2019-04-25]) do
|
|
~D[2019-05-25]
|
|
else
|
|
Timex.shift(user.inserted_at, days: 30) |> NaiveDateTime.to_date
|
|
end
|
|
end
|
|
|
|
def usage(user) do
|
|
user = Repo.preload(user, :sites)
|
|
Enum.reduce(user.sites, 0, fn site, total ->
|
|
total + site_usage(site)
|
|
end)
|
|
end
|
|
|
|
defp site_usage(site) do
|
|
Repo.aggregate(from(
|
|
p in Plausible.Pageview,
|
|
where: p.hostname == ^site.domain,
|
|
where: p.inserted_at >= fragment("now() - '30 days'::interval")
|
|
), :count, :id
|
|
)
|
|
end
|
|
|
|
defp format_subscription(params) do
|
|
%{
|
|
paddle_subscription_id: params["subscription_id"],
|
|
paddle_plan_id: params["subscription_plan_id"],
|
|
cancel_url: params["cancel_url"],
|
|
update_url: params["update_url"],
|
|
user_id: params["passthrough"],
|
|
status: params["status"],
|
|
next_bill_date: params["next_bill_date"],
|
|
next_bill_amount: params["unit_price"] || params["new_unit_price"]
|
|
}
|
|
end
|
|
end
|