diff --git a/app/webhooks/stripe_charge_succeeded_processor.rb b/app/webhooks/stripe_charge_succeeded_processor.rb index 6114a5e83..5e589cff6 100644 --- a/app/webhooks/stripe_charge_succeeded_processor.rb +++ b/app/webhooks/stripe_charge_succeeded_processor.rb @@ -2,7 +2,10 @@ class StripeChargeSucceededProcessor def call(event) stripe_charge = event.data.object return unless stripe_charge.paid - return if stripe_charge.subscription.present? + # Subscription (membership) charges carry an invoice and are recorded via the + # membership/invoice flow — skip them here. Newer Stripe API versions dropped + # Charge#subscription, so detect them by the presence of an invoice. + return if stripe_charge.invoice.present? return if Payment.exists?(stripe_charge_id: stripe_charge.id) diff --git a/spec/webhooks/stripe_charge_succeeded_processor_spec.rb b/spec/webhooks/stripe_charge_succeeded_processor_spec.rb index 9c1d3afe3..806059e51 100644 --- a/spec/webhooks/stripe_charge_succeeded_processor_spec.rb +++ b/spec/webhooks/stripe_charge_succeeded_processor_spec.rb @@ -18,7 +18,7 @@ billing_details: nil, receipt_email: nil, customer: nil, - subscription: nil, + invoice: nil, to_hash: { "id" => stripe_charge_id, "amount" => 30_00 } ) end @@ -47,8 +47,8 @@ expect { processor.call(event) }.not_to change(ExternalProcessorPayment, :count) end - it "does nothing when the charge belongs to a subscription" do - allow(stripe_charge).to receive(:subscription).and_return("sub_membership") + it "does nothing when the charge belongs to a subscription (has an invoice)" do + allow(stripe_charge).to receive(:invoice).and_return("in_membership") expect { processor.call(event) }.not_to change(ExternalProcessorPayment, :count) end