diff --git a/lib/plausible/billing/billing.ex b/lib/plausible/billing/billing.ex index 04d5ef331bda..2c09d8bce058 100644 --- a/lib/plausible/billing/billing.ex +++ b/lib/plausible/billing/billing.ex @@ -12,93 +12,28 @@ defmodule Plausible.Billing do user_id |> active_subscription_query() |> Repo.exists?() end - defp active_subscription_query(user_id) do - from s in Subscription, - where: s.user_id == ^user_id and s.status == "active", - order_by: [desc: s.inserted_at], - limit: 1 - end - def subscription_created(params) do - params = - if present?(params["passthrough"]) do - params - else - user = Repo.get_by(Plausible.Auth.User, email: params["email"]) - Map.put(params, "passthrough", user && user.id) - end - - changeset = Subscription.changeset(%Subscription{}, format_subscription(params)) - - Repo.insert(changeset) |> after_subscription_update + Repo.transaction(fn -> + handle_subscription_created(params) + end) 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) |> after_subscription_update + Repo.transaction(fn -> + handle_subscription_updated(params) + end) end - defp after_subscription_update({:ok, subscription}) do - user = - Repo.get(Plausible.Auth.User, subscription.user_id) - |> Map.put(:subscription, subscription) - - user - |> maybe_remove_grace_period - |> check_lock_status - |> maybe_adjust_api_key_limits - end - - defp after_subscription_update(err), do: err - def subscription_cancelled(params) do - subscription = - Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"]) - |> Repo.preload(:user) - - if subscription do - changeset = - Subscription.changeset(subscription, %{ - status: params["status"] - }) - - case Repo.update(changeset) do - {:ok, updated} -> - PlausibleWeb.Email.cancellation_email(subscription.user) - |> Plausible.Mailer.send() - - {:ok, updated} - - err -> - err - end - else - {:ok, nil} - end + Repo.transaction(fn -> + handle_subscription_cancelled(params) + 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"], - last_bill_date: api_subscription["last_payment"]["date"] - }) - - Repo.update(changeset) - else - {:ok, nil} - end + Repo.transaction(fn -> + handle_subscription_payment_succeeded(params) + end) end def change_plan(user, new_plan_id) do @@ -247,6 +182,71 @@ defmodule Plausible.Billing do end end + defp handle_subscription_created(params) do + params = + if present?(params["passthrough"]) do + params + else + user = Repo.get_by(Plausible.Auth.User, email: params["email"]) + Map.put(params, "passthrough", user && user.id) + end + + %Subscription{} + |> Subscription.changeset(format_subscription(params)) + |> Repo.insert!() + |> after_subscription_update() + end + + defp handle_subscription_updated(params) do + Subscription + |> Repo.get_by!(paddle_subscription_id: params["subscription_id"]) + |> Subscription.changeset(format_subscription(params)) + |> Repo.update!() + |> after_subscription_update() + end + + defp handle_subscription_cancelled(params) do + subscription = + Subscription + |> Repo.get_by(paddle_subscription_id: params["subscription_id"]) + |> Repo.preload(:user) + + if subscription do + changeset = + Subscription.changeset(subscription, %{ + status: params["status"] + }) + + updated = Repo.update!(changeset) + + subscription + |> Map.fetch!(:user) + |> PlausibleWeb.Email.cancellation_email() + |> Plausible.Mailer.send() + + updated + end + end + + defp handle_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) + + subscription + |> Subscription.changeset(%{ + next_bill_amount: amount, + next_bill_date: api_subscription["next_payment"]["date"], + last_bill_date: api_subscription["last_payment"]["date"] + }) + |> Repo.update!() + end + end + defp has_active_enterprise_subscription(user) do Plausible.Repo.exists?( from(s in Plausible.Billing.Subscription, @@ -287,24 +287,22 @@ defmodule Plausible.Billing do if new_allowance > allowance_required do user |> Plausible.Auth.GracePeriod.remove_changeset() - |> Repo.update() + |> Repo.update!() else - {:ok, user} + user end _ -> - {:ok, user} + user end end - defp check_lock_status({:ok, user}) do + defp check_lock_status(user) do Plausible.Billing.SiteLocker.check_sites_for(user) - {:ok, user} + user end - defp check_lock_status(err), do: err - - defp maybe_adjust_api_key_limits({:ok, user}) do + defp maybe_adjust_api_key_limits(user) do plan = Repo.get_by(Plausible.Billing.EnterprisePlan, user_id: user.id, @@ -317,10 +315,27 @@ defmodule Plausible.Billing do Repo.update_all(api_keys, set: [hourly_request_limit: plan.hourly_api_request_limit]) end - {:ok, user} + user end - defp maybe_adjust_api_key_limits(err), do: err - def paddle_api(), do: Application.fetch_env!(:plausible, :paddle_api) + + defp active_subscription_query(user_id) do + from s in Subscription, + where: s.user_id == ^user_id and s.status == "active", + order_by: [desc: s.inserted_at], + limit: 1 + end + + defp after_subscription_update(subscription) do + user = + Plausible.Auth.User + |> Repo.get!(subscription.user_id) + |> Map.put(:subscription, subscription) + + user + |> maybe_remove_grace_period() + |> check_lock_status() + |> maybe_adjust_api_key_limits() + end end diff --git a/lib/plausible_web/controllers/api/paddle_controller.ex b/lib/plausible_web/controllers/api/paddle_controller.ex index 5d1798f287df..3a4d6e753b2a 100644 --- a/lib/plausible_web/controllers/api/paddle_controller.ex +++ b/lib/plausible_web/controllers/api/paddle_controller.ex @@ -68,8 +68,8 @@ defmodule PlausibleWeb.Api.PaddleController do json(conn, "") end - defp webhook_response({:error, changeset}, conn, _params) do - Logger.error("Error processing Paddle webhook: #{inspect(changeset)}") + defp webhook_response({:error, details}, conn, _params) do + Logger.error("Error processing Paddle webhook: #{inspect(details)}") conn |> send_resp(400, "") |> halt end