mirror of
https://github.com/plausible/analytics.git
synced 2024-12-27 03:21:37 +03:00
9d97dc1912
* Move limit enforcement to accepting site ownerhsip transfer * enforce pageview limit on ownership transfer accept * Refactor plan limit check logic * Extract `ensure_can_take_ownership` to `Invitations` context and refactor * Improve styling of exceeded limits notice in invitation dialog and disable button * styling improvements to notice * make transfer_ownership return transfer to self error * do not allow transferring to user without active subscription WIP * Add missing typespec and improve existing ones * Fix formatting * Explicitly label direct match on function argument for clarity * Slightly refactor `CreateInvitation.bulk_transfer_ownership_direct` * Exclude quota enforcement tests from small build test suite * Remove unused return type from `invite_error()` union type * Do not block plan upgrade when there's pending ownership transfer * Don't block and only warn about missing features on transfer * Remove `x-init` attribute used for debugging * Add tests for `Quota.monthly_pageview_usage/2` * Test and improve site admin ownership transfer actions * Extend tests for `AcceptInvitation.transfer_ownership` * Test transfer ownership controller level accept action error cases * Test choosing plan by user without sites but with a pending ownership transfer * Test invitation x-data in sites LV * Remove sitelocker trigger in invitation acceptance code and simplify logic * Add Quota test for `user.allow_next_upgrade_override` being set * ignore pageview limit only when subscribing to plan * Use sandbox Paddle instance for staging * Use sandbox paddle key for staging and dev --------- Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
158 lines
4.9 KiB
Elixir
158 lines
4.9 KiB
Elixir
defmodule PlausibleWeb.BillingController do
|
|
use PlausibleWeb, :controller
|
|
use Plausible.Repo
|
|
require Logger
|
|
require Plausible.Billing.Subscription.Status
|
|
alias Plausible.Billing
|
|
alias Plausible.Billing.{Plans, Subscription}
|
|
|
|
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 choose_plan(conn, _params) do
|
|
user = conn.assigns.current_user
|
|
|
|
if Plausible.Auth.enterprise_configured?(user) do
|
|
redirect(conn, to: Routes.billing_path(conn, :upgrade_to_enterprise_plan))
|
|
else
|
|
render(conn, "choose_plan.html",
|
|
skip_plausible_tracking: true,
|
|
user: user,
|
|
layout: {PlausibleWeb.LayoutView, "focus.html"},
|
|
connect_live_socket: true
|
|
)
|
|
end
|
|
end
|
|
|
|
def upgrade_to_enterprise_plan(conn, _params) do
|
|
user = Plausible.Users.with_subscription(conn.assigns.current_user)
|
|
|
|
{latest_enterprise_plan, price} = Plans.latest_enterprise_plan_with_price(user)
|
|
|
|
subscription_resumable? = Plausible.Billing.Subscriptions.resumable?(user.subscription)
|
|
|
|
subscribed_to_latest? =
|
|
subscription_resumable? &&
|
|
user.subscription.paddle_plan_id == latest_enterprise_plan.paddle_plan_id
|
|
|
|
cond do
|
|
Subscription.Status.in?(user.subscription, [
|
|
Subscription.Status.past_due(),
|
|
Subscription.Status.paused()
|
|
]) ->
|
|
redirect(conn, to: Routes.auth_path(conn, :user_settings))
|
|
|
|
subscribed_to_latest? ->
|
|
render(conn, "change_enterprise_plan_contact_us.html",
|
|
skip_plausible_tracking: true,
|
|
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
|
)
|
|
|
|
true ->
|
|
render(conn, "upgrade_to_enterprise_plan.html",
|
|
user: user,
|
|
latest_enterprise_plan: latest_enterprise_plan,
|
|
price: price,
|
|
subscription_resumable: subscription_resumable?,
|
|
contact_link: "https://plausible.io/contact",
|
|
skip_plausible_tracking: true,
|
|
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
|
)
|
|
end
|
|
end
|
|
|
|
def upgrade_success(conn, _params) do
|
|
render(conn, "upgrade_success.html", layout: {PlausibleWeb.LayoutView, "focus.html"})
|
|
end
|
|
|
|
def change_plan_preview(conn, %{"plan_id" => new_plan_id}) do
|
|
user = conn.assigns.current_user
|
|
|
|
case preview_subscription(user, 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,
|
|
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
|
)
|
|
|
|
_ ->
|
|
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,
|
|
user_id: 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
|
|
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} ->
|
|
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} ->
|
|
# https://developer.paddle.com/api-reference/intro/api-error-codes
|
|
"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
|