-
-
Notifications
You must be signed in to change notification settings - Fork 65
Webhook development support and generic payment method slug #271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
58902e7
3b0dc86
34380ef
7e977c0
731629d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| web: env RUBY_DEBUG_OPEN=true bin/rails-sandbox server | ||
| watch: bin/rails-sandbox g solidus_stripe:install --force --watch | ||
| stripe: stripe listen --forward-to http://localhost:3000/solidus_stripe/test/webhooks --events charge.refunded,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.canceled |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,18 +14,11 @@ class PaymentMethod < ::Spree::PaymentMethod | |
| validates :available_to_admin, inclusion: { in: [false] } | ||
| validates :preferred_setup_future_usage, inclusion: { in: ['', 'on_session', 'off_session'] } | ||
|
|
||
| has_one :webhook_endpoint, | ||
| class_name: 'SolidusStripe::WebhookEndpoint', | ||
| inverse_of: :payment_method, | ||
| dependent: :destroy | ||
| has_one :slug_entry, class_name: 'SolidusStripe::SlugEntry', inverse_of: :payment_method, dependent: :destroy | ||
|
|
||
| after_create :assign_webhook_endpoint | ||
| after_create :assign_slug | ||
|
|
||
| # @!attribute [r] webhook_endpoint_slug | ||
| # @return [String] The slug of the webhook endpoint for this payment method. | ||
| delegate :slug, | ||
| to: :webhook_endpoint, | ||
| prefix: true | ||
| delegate :slug, to: :slug_entry | ||
|
|
||
| def partial_name | ||
| "stripe" | ||
|
|
@@ -52,6 +45,10 @@ def payment_profiles_supported? | |
| false | ||
| end | ||
|
|
||
| def self.with_slug(slug) | ||
| where(id: SlugEntry.where(slug: slug).select(:payment_method_id)) | ||
| end | ||
|
|
||
| # TODO: re-evaluate the need for this and think of ways to always go throught the intent classes. | ||
| def self.intent_id_for_payment(payment) | ||
| return unless payment | ||
|
|
@@ -70,12 +67,12 @@ def stripe_dashboard_url(intent_id) | |
| end | ||
| end | ||
|
|
||
| private | ||
| def assign_slug | ||
| # If there's only one payment method, we can use a default slug. | ||
| slug = preferred_test_mode ? 'test' : 'live' if self.class.count == 1 | ||
| slug = SecureRandom.hex(16) while SlugEntry.exists?(slug: slug) || slug.nil? | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For sure opinionated, but IMHO using recursion made it simpler (for instance, we didn't need to check for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it was originally moved in order to check the return if slug_entry.present?
slug = preferred_test_mode ? 'test' : 'live'
slug = SecureRandom.hex(16) while SlugEntry.exists?(slug: slug)Although given how rare it is I agree we should do it for readability (vs. performance). |
||
|
|
||
| def assign_webhook_endpoint | ||
| create_webhook_endpoint!( | ||
| slug: WebhookEndpoint.generate_slug | ||
| ) | ||
| create_slug_entry!(slug: slug) | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,8 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| SolidusStripe::Engine.routes.draw do | ||
| scope ':payment_method_id' do | ||
| get :after_confirmation, controller: :intents | ||
| scope ':slug' do | ||
| get :after_confirmation, to: 'intents#after_confirmation' | ||
| post :webhooks, to: 'webhooks#create', format: false | ||
| end | ||
| post '/webhooks/:slug', format: false, to: 'webhooks#create' | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class RenameWebhookEndpointToPaymentMethodSlugEntries < ActiveRecord::Migration[7.0] | ||
| def change | ||
| rename_table :solidus_stripe_webhook_endpoints, :solidus_stripe_slug_entries | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,7 +24,7 @@ class Event | |||||||||
| # @api private | ||||||||||
| class << self | ||||||||||
| def from_request(payload:, signature_header:, slug:, tolerance: default_tolerance) | ||||||||||
| payment_method = SolidusStripe::WebhookEndpoint.payment_method(slug) | ||||||||||
| payment_method = SolidusStripe::PaymentMethod.with_slug(slug).first! | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure to get why we unwrapped the procedure to get the payment method. IMHO, that opens gates to duplication and copy-paste programming.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @waiting-for-dev that's a valid concern. The reason it was moved to a slightly lower-level construct like a scope is that it's more versatile and can be mixed and matched with other scopes without generating extra queries more easily, e.g. in this case solidus_stripe/app/controllers/solidus_stripe/intents_controller.rb Lines 45 to 48 in 731629d
|
||||||||||
| stripe_event = Stripe::Webhook.construct_event( | ||||||||||
| payload, | ||||||||||
| signature_header, | ||||||||||
|
|
||||||||||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,7 +75,7 @@ def signature | |
| end | ||
|
|
||
| def slug | ||
| @payment_method.webhook_endpoint_slug | ||
| @payment_method.slug | ||
| end | ||
| end | ||
| end | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think responsibilities were fairer when that method was part of the
SlugEntryclass, especially considering that the payment method already deals with a lot of stuff (via inheritance from upstream Solidus).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main reason was (I think) having access to
preferred_test_mode(see the other comment), personally I'm fine with both arrangements, with a preference for SlugEntry not needing to know too much about the payment method.