analytics/lib/plausible_web/controllers/billing_controller.ex

188 lines
5.5 KiB
Elixir

defmodule PlausibleWeb.BillingController do
use PlausibleWeb, :controller
use Plausible.Repo
alias Plausible.Billing
require Logger
plug PlausibleWeb.RequireAccountPlug
def ping_subscription(%Plug.Conn{} = conn, _params) do
subscribed? = Billing.has_active_subscription?(conn.assigns.current_user.id)
json(conn, %{is_subscribed: subscribed?})
end
def upgrade(conn, _params) do
user =
conn.assigns[:current_user]
|> Repo.preload(:enterprise_plan)
cond do
user.subscription && user.subscription.status == "active" ->
redirect(conn, to: Routes.billing_path(conn, :change_plan_form))
user.enterprise_plan ->
redirect(conn,
to: Routes.billing_path(conn, :upgrade_enterprise_plan, user.enterprise_plan.id)
)
true ->
render(conn, "upgrade.html",
skip_plausible_tracking: true,
usage: Plausible.Billing.usage(user),
user: user,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
end
end
def upgrade_enterprise_plan(conn, %{"plan_id" => plan_id}) do
user = conn.assigns[:current_user]
subscription = user.subscription
plan = Repo.get_by(Plausible.Billing.EnterprisePlan, user_id: user.id, id: plan_id)
cond do
plan && subscription && plan.paddle_plan_id == subscription.paddle_plan_id ->
redirect(conn, to: Routes.billing_path(conn, :change_plan_form))
plan ->
render(conn, "upgrade_to_plan.html",
skip_plausible_tracking: true,
user: user,
plan: plan,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
true ->
render_error(conn, 404)
end
end
def upgrade_success(conn, _params) do
render(conn, "upgrade_success.html", layout: {PlausibleWeb.LayoutView, "focus.html"})
end
def change_plan_form(conn, _params) do
user =
conn.assigns[:current_user]
|> Repo.preload(:enterprise_plan)
subscription = Billing.active_subscription_for(user.id)
cond do
subscription && user.enterprise_plan &&
subscription.paddle_plan_id !== user.enterprise_plan.paddle_plan_id ->
redirect(conn,
to: Routes.billing_path(conn, :change_enterprise_plan, user.enterprise_plan.id)
)
subscription && user.enterprise_plan &&
subscription.paddle_plan_id == user.enterprise_plan.paddle_plan_id ->
render(conn, "change_enterprise_plan_contact_us.html",
skip_plausible_tracking: true,
user: user,
plan: user.enterprise_plan,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
subscription ->
render(conn, "change_plan.html",
skip_plausible_tracking: true,
subscription: subscription,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
true ->
redirect(conn, to: Routes.billing_path(conn, :upgrade))
end
end
def change_enterprise_plan(conn, %{"plan_id" => plan_id}) do
user = conn.assigns[:current_user]
new_plan = Repo.get_by(Plausible.Billing.EnterprisePlan, user_id: user.id, id: plan_id)
cond do
is_nil(user.subscription) ->
redirect(conn, to: "/billing/upgrade")
is_nil(new_plan) || new_plan.paddle_plan_id == user.subscription.paddle_plan_id ->
render_error(conn, 404)
true ->
render(conn, "change_enterprise_plan.html",
skip_plausible_tracking: true,
user: user,
plan: new_plan,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
end
end
def change_plan_preview(conn, %{"plan_id" => new_plan_id}) do
with {:ok, {subscription, preview_info}} <-
preview_subscription(conn.assigns.current_user, new_plan_id) do
render(conn, "change_plan_preview.html",
skip_plausible_tracking: true,
subscription: subscription,
preview_info: preview_info,
layout: {PlausibleWeb.LayoutView, "focus.html"}
)
else
_ ->
redirect(conn, to: "/billing/upgrade")
end
end
def change_plan(conn, %{"new_plan_id" => new_plan_id}) do
case Billing.change_plan(conn.assigns[:current_user], new_plan_id) do
{:ok, _subscription} ->
conn
|> put_flash(:success, "Plan changed successfully")
|> redirect(to: "/settings")
{:error, e} ->
# https://developer.paddle.com/api-reference/intro/api-error-codes
msg =
case e do
%{"code" => 147} ->
"We were unable to charge your card. Click 'update billing info' to update your payment details and try again."
%{"message" => msg} when not is_nil(msg) ->
msg
_ ->
"Something went wrong. Please try again or contact support at support@plausible.io"
end
Sentry.capture_message("Error changing plans",
extra: %{
errors: inspect(e),
message: msg,
new_plan_id: new_plan_id,
user_id: conn.assigns[:current_user].id
}
)
conn
|> put_flash(:error, msg)
|> redirect(to: "/settings")
end
end
defp preview_subscription(%{id: user_id}, new_plan_id) do
subscription = Billing.active_subscription_for(user_id)
if subscription do
with {:ok, preview_info} <- Billing.change_plan_preview(subscription, new_plan_id) do
{:ok, {subscription, preview_info}}
end
else
{:error, :no_subscription}
end
end
def preview_susbcription(_, _) do
{:error, :no_user_id}
end
end