| defmodule PlausibleWeb.BillingController do |
| use PlausibleWeb, :controller |
| use Plausible.Repo |
|
|
| require Logger |
| require Plausible.Billing.Subscription.Status |
| require Plausible.Billing |
|
|
| alias Plausible.Billing |
| alias Plausible.Billing.Subscription |
|
|
| plug PlausibleWeb.RequireAccountPlug |
|
|
| plug Plausible.Plugs.AuthorizeTeamAccess, Billing.allowed_roles() |
|
|
| def ping_subscription(%Plug.Conn{} = conn, _params) do |
| subscribed? = Plausible.Teams.Billing.has_active_subscription?(conn.assigns.current_team) |
|
|
| json(conn, %{is_subscribed: subscribed?}) |
| end |
|
|
| def choose_plan(conn, _params) do |
| team = conn.assigns.current_team |
|
|
| if Plausible.Teams.Billing.enterprise_configured?(team) do |
| redirect(conn, to: Routes.billing_path(conn, :upgrade_to_enterprise_plan)) |
| else |
| render(conn, "choose_plan.html", |
| live_module: PlausibleWeb.Live.ChoosePlan, |
| hide_header?: true, |
| disable_global_notices?: true, |
| skip_plausible_tracking: true, |
| connect_live_socket: true |
| ) |
| end |
| end |
|
|
| def upgrade_to_enterprise_plan(conn, _params) do |
| team = conn.assigns.current_team |
| subscription = Plausible.Teams.Billing.get_subscription(team) |
|
|
| {latest_enterprise_plan, price} = |
| Plausible.Teams.Billing.latest_enterprise_plan_with_price( |
| team, |
| PlausibleWeb.RemoteIP.get(conn) |
| ) |
|
|
| subscription_resumable? = |
| Plausible.Billing.Subscriptions.resumable?(subscription) |
|
|
| subscribed_to_latest? = |
| subscription_resumable? && |
| subscription.paddle_plan_id == latest_enterprise_plan.paddle_plan_id |
|
|
| cond do |
| Subscription.Status.in?(subscription, [ |
| Subscription.Status.past_due(), |
| Subscription.Status.paused() |
| ]) -> |
| redirect(conn, to: Routes.settings_path(conn, :subscription)) |
|
|
| subscribed_to_latest? -> |
| render(conn, "change_enterprise_plan_contact_us.html", skip_plausible_tracking: true) |
|
|
| true -> |
| render(conn, "upgrade_to_enterprise_plan.html", |
| latest_enterprise_plan: latest_enterprise_plan, |
| price: price, |
| subscription_resumable: subscription_resumable?, |
| contact_link: "https://plausible.io/contact", |
| skip_plausible_tracking: true |
| ) |
| end |
| end |
|
|
| def upgrade_success(conn, _params) do |
| render(conn, "upgrade_success.html", disable_global_notices?: true) |
| end |
|
|
| def change_plan_preview(conn, %{"plan_id" => new_plan_id}) do |
| team = conn.assigns.current_team |
| current_user = conn.assigns.current_user |
| subscription = Plausible.Teams.Billing.active_subscription_for(team) |
|
|
| case preview_subscription(subscription, new_plan_id) do |
| {:ok, {subscription, preview_info}} -> |
| render(conn, "change_plan_preview.html", |
| back_link: Routes.billing_path(conn, :choose_plan), |
| skip_plausible_tracking: true, |
| subscription: subscription, |
| preview_info: preview_info |
| ) |
|
|
| _ -> |
| msg = |
| "Something went wrong with loading your plan change information. Please try again, or contact us at support@plausible.io if the issue persists." |
|
|
| Sentry.capture_message("Error loading change plan preview", |
| extra: %{ |
| message: msg, |
| new_plan_id: new_plan_id, |
| team_id: team.id, |
| user_id: current_user.id |
| } |
| ) |
|
|
| conn |
| |> put_flash(:error, msg) |
| |> redirect(to: Routes.billing_path(conn, :choose_plan)) |
| end |
| end |
|
|
| def change_plan(conn, %{"new_plan_id" => new_plan_id}) do |
| team = conn.assigns.current_team |
|
|
| case Plausible.Teams.Billing.change_plan(team, new_plan_id) do |
| {:ok, _subscription} -> |
| conn |
| |> put_flash(:success, "Plan changed successfully") |
| |> redirect(to: Routes.settings_path(conn, :subscription)) |
|
|
| {:error, e} -> |
| msg = |
| case e do |
| {:over_plan_limits, exceeded_limits} -> |
| "Unable to subscribe to this plan because the following limits are exceeded: #{PlausibleWeb.TextHelpers.pretty_list(exceeded_limits)}" |
|
|
| %{"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, |
| team_id: team.id, |
| user_id: conn.assigns.current_user.id |
| } |
| ) |
|
|
| conn |
| |> put_flash(:error, msg) |
| |> redirect(to: Routes.settings_path(conn, :subscription)) |
| end |
| end |
|
|
| defp preview_subscription(nil, _new_plan_id), do: {:error, :no_subscription} |
|
|
| defp preview_subscription(subscription, new_plan_id) do |
| with {:ok, preview_info} <- Billing.change_plan_preview(subscription, new_plan_id) do |
| {:ok, {subscription, preview_info}} |
| end |
| end |
| end |
|
|