Skip to content

Commit b5c5ab8

Browse files
authored
ignore irrelevant paddle webhook (plausible#4240)
1 parent fe9f734 commit b5c5ab8

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

lib/plausible/billing/billing.ex

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,22 @@ defmodule Plausible.Billing do
137137
defp handle_subscription_updated(params) do
138138
subscription = Repo.get_by(Subscription, paddle_subscription_id: params["subscription_id"])
139139

140-
if subscription do
140+
# In a situation where the subscription is paused and a payment succeeds, we
141+
# get notified of two "subscription_updated" webhook alerts from Paddle at the
142+
# same time.
143+
#
144+
# * one with an `old_status` of "paused", and a `status` of "past_due"
145+
# * the other with an `old_status` of "past_due", and a `status` of "active"
146+
#
147+
# https://developer.paddle.com/classic/guides/zg9joji1mzu0mduy-payment-failures
148+
#
149+
# Relying on the time when the webhooks are sent has caused issues where
150+
# subscriptions have ended up `past_due` after a successful payment. Therefore,
151+
# we're now explicitly ignoring the first webhook (with the update that's not
152+
# relevant to us).
153+
irrelevant? = params["old_status"] == "paused" && params["status"] == "past_due"
154+
155+
if subscription && not irrelevant? do
141156
subscription
142157
|> Subscription.changeset(format_subscription(params))
143158
|> Repo.update!()

test/plausible/billing/billing_test.exs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,21 @@ defmodule Plausible.BillingTest do
212212
assert subscription.next_bill_amount == "12.00"
213213
end
214214

215+
test "status update from 'paused' to 'past_due' is ignored" do
216+
user = insert(:user)
217+
subscription = insert(:subscription, user: user, status: Subscription.Status.paused())
218+
219+
%{@subscription_updated_params | "old_status" => "paused", "status" => "past_due"}
220+
|> Map.merge(%{
221+
"subscription_id" => subscription.paddle_subscription_id,
222+
"passthrough" => user.id
223+
})
224+
|> Billing.subscription_updated()
225+
226+
subscription = Repo.get_by(Subscription, user_id: user.id)
227+
assert subscription.status == Subscription.Status.paused()
228+
end
229+
215230
test "unlocks sites if subscription is changed from past_due to active" do
216231
user = insert(:user)
217232
subscription = insert(:subscription, user: user, status: Subscription.Status.past_due())

0 commit comments

Comments
 (0)