-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Don't display inactive payment methods on frontend or backend #1801
Don't display inactive payment methods on frontend or backend #1801
Conversation
scope :available_to_store, -> (store) { (store.present? && store.payment_methods.empty?) ? self : store.payment_methods } | ||
scope :available_to_store, -> (store) do | ||
raise ArgumentError, "You must provide a store" if store.nil? | ||
(store.payment_methods.empty?) ? all : where(id: store.payment_method_ids) |
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.
Don't use parentheses around a method call.
Omit parentheses for ternary conditions.
@@ -17,7 +17,10 @@ class PaymentMethod < Spree::Base | |||
scope :active, -> { where(active: true) } | |||
scope :available_to_users, -> { where(available_to_users: true) } | |||
scope :available_to_admin, -> { where(available_to_admin: true) } | |||
scope :available_to_store, -> (store) { (store.present? && store.payment_methods.empty?) ? self : store.payment_methods } | |||
scope :available_to_store, -> (store) do |
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.
Do not use spaces between -> and opening brace in lambda literals
5eee81d
to
f400308
Compare
scope :available_to_store, ->(store) do | ||
raise ArgumentError, "You must provide a store" if store.nil? | ||
store.payment_methods.empty? ? all : where(id: store.payment_method_ids) | ||
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.
The whole method is not very clearly written. It's sort of all in-reverse. I think it should be just:
scope :available_to_store, -> (store) { where(store: store) }
That should also work if store is nil
.
The raise ArgumentError
is not much improvement over the Undefined method payment_methods
on Nil:Class
that one would usually get.
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.
Thanks for the feedback!
Unfortunately where(store: store)
doesn't work, because the payment method <-> store association is a has_many :through
.
The reason for the conditional is to keep the existing, or at least expected, behaviour where if the store doesn't have any payment methods, we return all of them instead of an empty collection.
I agree the ArgumentError is not a drastic improvement. I discussed this with @jhawthorn on Friday and would be okay just letting it error the usual way too.
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.
That won't quite work due to the nature of the relationship between stores and payment methods. It could be writen as:
scope :available_to_store, -> (store) { joins(:stores).merge(Spree::Store.where(id: store.id)) }
However, this would mean a divergence from how we typically handle store associations. Normally, if a store doesn't have anything associated to it we assume everything belongs to that store. I believe this decision was made a while back to help handle single store apps by ensuring everything continued to work without having to create the missing associations.
While I'm definitely not opposed to changing that behavior, it would require a larger amount of work and a conscious decision to have all single store apps require some additional configuration behind the scenes.
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.
Absolutely you are both right, I did not see it through, and I am not that familiar with that part of the code. Thanks for the explanation!
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.
Thanks Luuk
This was a 2.1 regression, and I think we should backport it for a 2.1.1 release. |
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.
Nice find, thanks for the fixing this and writing this up!
One nitpick request for removing the nil check but very 👍 other than that.
@@ -17,7 +17,10 @@ class PaymentMethod < Spree::Base | |||
scope :active, -> { where(active: true) } | |||
scope :available_to_users, -> { where(available_to_users: true) } | |||
scope :available_to_admin, -> { where(available_to_admin: true) } | |||
scope :available_to_store, -> (store) { (store.present? && store.payment_methods.empty?) ? self : store.payment_methods } | |||
scope :available_to_store, ->(store) do | |||
raise ArgumentError, "You must provide a store" if store.nil? |
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 agree the ArgumentError is not a drastic improvement. I discussed this with @jhawthorn on Friday and would be okay just letting it error the usual way too.
^ I agree with removing the nil check. The prior code didn't actually protect against nils and as @mtomov mentioned it doesn't really add much and we don't do it in most places
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.
Changing my "Changes Requested" to "Approved" because the nil check isn't a blocker IMO. Personally I'd prefer to see it removed though.
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.
Thanks @luukveenis for doing this. I'd like to have pending
calls on the commits that introduce failing specs, and their respective removals in the commits that fix them. Otherwise, great! :)
@@ -538,6 +538,16 @@ def merge!(other_order, user = nil) | |||
expect(order.available_payment_methods).to include(payment_method) | |||
end | |||
|
|||
it "does not include inactive payment methods" do |
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.
This spec surely wants to have a pending
call to make sure this commit doesn't break the suite, no?
@payment_method = create(:check_payment_method, available_to_admin: true) | ||
end | ||
|
||
it "loads the payment method" do |
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.
Can we have pending
calls for both failing specs in this commit?
I noticed that inactive payment methods were not being filtered out on the frontend. This used to happen in `Spree::PaymentMethod.available`, but in solidusio#1540 this filter was lost.
We use `Spree::Order#available_payment_methods` to determine which payment methods should be displayed on the payment page in checkout. The changes in solidusio#1540 accidentally dropped the scoping for active payment methods, causing inactive payment methods to show up on the frontend. This also required fixing the `available_to_store` scope, which behaved incorrectly. Calling `self` from inside the scope returns the `Spree::PaymentMethod` class itself and not the current scoping as the code implied. This scope will now raise an error if the store parameter is `nil`, return all payment methods in the current scope if the store has no payment methods, and return the payment methods for the store if it does have some.
Payment methods available on the backend used to be scope to active methods only. Unfortunately that functionality was lost in solidusio#1540 because the `available_to_admin` scope isn't limited to active payment methods.
This was the original behaviour in Solidus < 2.1, but the active scope got lost in solidusio#1540. Payment methods used to use the `available` filter which was scoped to active payment methods only. The `available_to_admin` scope isn't limited active payment methods, so we need to add it here.
77fc23f
to
34a50ad
Compare
I've rebased to add :pending to the failing specs (and removed when fixed)
The issue
After upgrading to Solidus 2.1, I noticed that my inactive payment methods were being displayed on the payment page in checkout and the
payments#new
page in the admin. The issue was introduced in #1540 because theSpree::PaymentMethod.available
scope used to filter payment methods byactive
, but the newavailable_to_users
andavailable_to_admin
scopes only look at their respective attributes on the payment method. TheSpree::Order#available_payment_methods
method wasn't updated to include theactive
scope accordingly. Similarly, theload_data
method in the admin payment methods controller is missing theactive
scope.While writing the failing spec for this, I noticed that the
available_to_store
scope was not behaving as expected. It returnedself
if the store did not have any payment methods, which presumably was expected to return the current scope, but actually returns theSpree::PaymentMethod
class constant. This wasn't breaking specs because we chained other scopes that would return payment methods as expected.The fix
I've added the
active
scope to#available_payment_methods
and in#load_data
to ensure we don't include inactive payment methods.I also updated the
available_to_store
scope to raise anArgumentError
if the store provided is nil, and return all payment methods in the current scope if the store doesn't have any payment methods. I added specs that should catch this issue in the future.