ignore irrelevant paddle webhook (#4240)

This commit is contained in:
RobertJoonas 2024-06-18 11:47:16 +03:00 committed by GitHub
parent fe9f7349e7
commit b5c5ab8e61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View File

@ -137,7 +137,22 @@ defmodule Plausible.Billing do
defp handle_subscription_updated(params) do
subscription = Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
if subscription do
# In a situation where the subscription is paused and a payment succeeds, we
# get notified of two "subscription_updated" webhook alerts from Paddle at the
# same time.
#
# * one with an `old_status` of "paused", and a `status` of "past_due"
# * the other with an `old_status` of "past_due", and a `status` of "active"
#
# https://developer.paddle.com/classic/guides/zg9joji1mzu0mduy-payment-failures
#
# Relying on the time when the webhooks are sent has caused issues where
# subscriptions have ended up `past_due` after a successful payment. Therefore,
# we're now explicitly ignoring the first webhook (with the update that's not
# relevant to us).
irrelevant? = params["old_status"] == "paused" && params["status"] == "past_due"
if subscription && not irrelevant? do
subscription
|> Subscription.changeset(format_subscription(params))
|> Repo.update!()

View File

@ -212,6 +212,21 @@ defmodule Plausible.BillingTest do
assert subscription.next_bill_amount == "12.00"
end
test "status update from 'paused' to 'past_due' is ignored" do
user = insert(:user)
subscription = insert(:subscription, user: user, status: Subscription.Status.paused())
%{@subscription_updated_params | "old_status" => "paused", "status" => "past_due"}
|> Map.merge(%{
"subscription_id" => subscription.paddle_subscription_id,
"passthrough" => user.id
})
|> Billing.subscription_updated()
subscription = Repo.get_by(Subscription, user_id: user.id)
assert subscription.status == Subscription.Status.paused()
end
test "unlocks sites if subscription is changed from past_due to active" do
user = insert(:user)
subscription = insert(:subscription, user: user, status: Subscription.Status.past_due())