Skip to content

Commit

Permalink
Ignore Stripe failed payment webhooks for incomplete subscriptions (#…
Browse files Browse the repository at this point in the history
…1121)

Since incomplete subscriptions are just pending and are currently being
created by a customer in the browser, the JavaScript will handle these
events. We can safely ignore them server-side and prevent sending
duplicates.

Stripe Checkout's payment intents are also only usable inside Checkout,
so if they were to be used to complete the charge, they may raise an error.
  • Loading branch information
excid3 authored Dec 20, 2024
1 parent 7a8f373 commit c06a4e7
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 12 deletions.
3 changes: 2 additions & 1 deletion lib/pay/stripe/webhooks/payment_action_required.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ def call(event)

object = event.data.object

# Don't send email on incomplete Stripe subscriptions since they're just getting created and the JavaScript will handle SCA
pay_subscription = Pay::Subscription.find_by_processor_and_id(:stripe, object.subscription)
return if pay_subscription.nil?
return if pay_subscription.nil? || pay_subscription.status == "incomplete"

if Pay.send_email?(:payment_action_required, pay_subscription)
Pay.mailer.with(
Expand Down
3 changes: 2 additions & 1 deletion lib/pay/stripe/webhooks/payment_failed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ def call(event)

object = event.data.object

# Don't send email on incomplete Stripe subscriptions since they're just getting created and the JavaScript will handle SCA
pay_subscription = Pay::Subscription.find_by_processor_and_id(:stripe, object.subscription)
return if pay_subscription.nil?
return if pay_subscription.nil? || pay_subscription.status == "incomplete"

if Pay.send_email?(:payment_failed, pay_subscription)
Pay.mailer.with(
Expand Down
16 changes: 6 additions & 10 deletions test/pay/stripe/webhooks/payment_action_required_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,20 @@ class Pay::Stripe::Webhooks::PaymentActionRequiredTest < ActiveSupport::TestCase
@event = stripe_event("invoice.payment_action_required")

# Create user and subscription
@pay_customer = pay_customers(:stripe)
@pay_customer.update(processor_id: @event.data.object.customer)
@subscription = @pay_customer.subscriptions.create!(
processor_id: @event.data.object.subscription,
name: "default",
processor_plan: "some-plan",
status: "requires_action"
)
pay_customers(:stripe).update!(processor_id: @event.data.object.customer)
end

test "it sends an email" do
Pay::Stripe::Subscription.sync @event.data.object.subscription, object: fake_stripe_subscription(id: @event.data.object.subscription, customer: @event.data.object.customer, status: :past_due)

assert_enqueued_jobs 1 do
Pay::Stripe::Webhooks::PaymentActionRequired.new.call(@event)
end
end

test "ignores if subscription doesn't exist" do
@subscription.destroy!
test "skips email if subscription is incomplete" do
Pay::Stripe::Subscription.sync @event.data.object.subscription, object: fake_stripe_subscription(id: @event.data.object.subscription, customer: @event.data.object.customer, status: :incomplete)

assert_no_enqueued_jobs do
Pay::Stripe::Webhooks::PaymentActionRequired.new.call(@event)
end
Expand Down
7 changes: 7 additions & 0 deletions test/pay/stripe/webhooks/payment_failed_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class Pay::Stripe::Webhooks::PaymentFailedTest < ActiveSupport::TestCase
end
end

test "skips email if subscription is incomplete" do
create_subscription(processor_id: @payment_failed_event.data.object.subscription)
assert_no_enqueued_jobs do
Pay::Stripe::Webhooks::PaymentFailed.new.call(@payment_failed_event)
end
end

private

def create_subscription(processor_id:)
Expand Down

0 comments on commit c06a4e7

Please sign in to comment.