Problem/Motivation
We currently have the AvailabilityManager API with no default implementation. Drupal Commerce out of the box provides products that can be published or not. We could add an availability manager which checks if the order item references an unpublished variation.
Proposed resolution
Add an availability checker that checks if the purchasable entity implements \Drupal\Core\Entity\EntityPublishedInterface. If it does, return the value of isPublished.
Remaining tasks
Consider notes in the following issues:
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #41 | 3088598-41.patch | 12.11 KB | khiminrm |
| #36 | 3088598-disable.patch | 595 bytes | pfrenssen |
| #19 | 3088598-19.patch | 12.47 KB | jsacksick |
| #17 | 3088598-17.patch | 2.09 KB | jsacksick |
| #9 | 3088598-9.patch | 7.96 KB | mglaman |
Comments
Comment #2
mglamanThis doesn't need to belong in Order since AvailabilityManager is a base API. Here is the patch.
Comment #3
mglamanFixes coding standard violations.
Comment #4
jsacksick commentedI think this works... The only concern probably here I guess is "BC", but it's probably fine... Does this actually mean that unpublished products can be purchased by default?
Comment #5
mglamanKicking to Needs Work to follow up a discussion with bojanz. We have a logic check in \Drupal\commerce_product\ProductVariationStorage::loadEnabled that also checks if the user has
viewaccess to the entity.We should replicate that check as well. In B2B contexts a product was published but only available in certain catalogs/contexts, so it was "unpublished" to regular users. That is one of the reasons we have the loadEnabled method.
Rename to PurchasableEntityChecker or something, PurchasableEntityAccessChecker
We should perform
Comment #6
mglamanComment #7
mglamanHere is a patch which uses the entity access call, with a performance optimization if the entity is publishable.
Comment #8
mglamanI had to fix a test that was missing user permissions to view products and broken variation backreference, which always failed entity access checks.
Comment #9
mglamanReroll fixing phpcs for unused import.
Comment #10
mglaman🤔I wonder if this should be postponed on #3088597: Add a constraint to purchased_entity which checks the availability manager to see what kind of impacts it has on our tests.
Comment #11
mglamanYeah, this is going be postponed until #3088597: Add a constraint to purchased_entity which checks the availability manager lands. There's no knowing what effects it will have on the tests and is "useless" until the availability manager is integrated into the add to cart form.
Comment #12
mglamanThe constraint landed, so we can try this out.
Comment #13
mglamanPurchasedEntityConstraintValidatorTest needs to have anonymous users with proper permissions.
Comment #14
mglamanThis also needs to be updated for #3138952: Make the AvailabilityManager order aware
Comment #15
thiagomoraesp commentedHello everyone, the patch is still needed on commerce 8.x-2.28 ?
Comment #16
jsacksick commentedYes, and it's using the "old" API which is now deprecated, there's an availability checker defined in Commerce API that can be copied.
Comment #17
jsacksick commentedAttaching the availability checker, copied from Commerce API. Some tests could fail, didn't copy the tests from the patch from @mglaman.
Comment #19
jsacksick commentedAttached patch should fix the existing tests and copied/adapted the test from @mglaman to work with the non legacy availability manager/checker.
Just wondering if we won't get bug reports about products disappearing from the cart with no explanation...
Also, once this goes in, we need to remove the same checker from Commerce API and bump the minimum required Commerce version.
Comment #20
jsacksick commentedComment #23
jsacksick commentedCommitted! @mglaman: Thanks for the initial patch!
Comment #24
agoradesign commentedAllowing to present messages, when the user visits the cart page next time, would be a nice feature in the future :) like Amazon does for things like "The price for the product in your cart has changed to xxx"
Comment #26
rhovland@agoradesign I added a followup issue for this messaging #3276343: Display a message when a cart item is removed due to new availability manager checks
Comment #27
agoradesign commentedgreat! thanks :)
Comment #28
fenstratJust noting that this availability checker here made selling inaccessible products impossible.
Admittedly I have an odd use case for this: product isn't available in the default situation which is online (i.e. hook_entity_access for the product returns
AccessResult::forbidden()), but is available for admin to sell via retail/POS (i.e. for a different store where hook_entity_access returnsAccessResult::allowed()). So in this case this new EntityAccessibleAvailabilityChecker always returnsAvailabilityResult::unavailable()as$purchasable_entity->access('view') === FALSE. There doesn't seem to be any way to override that as once one checker returns unavailable any other checker cannot override that. Appreciate that is the way this was designed, but it is a limitation.Comment #29
agoradesign commentedyou can implmenent a ServiceProvider that removes this service
Comment #30
fenstrat@agoradesign of course, nice idea, thanks.
Very simple alter in your ServiceProvider in case anyone comes across this in future:
Comment #31
jsacksick commentedDecided to revert this for now, considering the amount of issues that were opened since this got committed.
Comment #32
agoradesign commentedShouldn't we keep it, but add a config whether to enable it? Defaulting it to true, only updating existing sites to false? Because in my eyes, the old behaviour (w/o the checker) was simply wrong and unexpected to 99% of the store owners. I was a little bit surprised, when I first realized that I have to implement a custom availability checker to prevent disabled product variations (in existing carts) to be purchased. I guess no one really expects that.
Comment #33
rhovlandSo if this is getting some more work it needs to log order item removal. It also needs to notify the user that the item was removed from their order and why.
Comment #34
jsacksick commented@agoradesign: Well, this is a needed functionality IMO, but perhaps too late to include in 2.x, and probably require a more polish in order to be considered "fully functional" (logging deletion, displaying messages)...
Comment #35
agoradesign commentedagree :)
Comment #36
pfrenssenHere is a quick patch to temporarily disable this feature for people who are using 8.x-2.30 which shipped with this feature.
Comment #37
lisastreeter commentedI'm also going to need to remove with ServiceProvider or the quick patch in #36.
This is problematic:
If an admin user is placing an order in the backend, the customer in
$contextis not the person placing the order. The admin user should be able to add a product to the order even if it's not visible to the customer on the website. (For admin-only products, we leave the products unpublished but publish the variation, so the$purchasable_entity->isPublished()check is ok.)So my feedback is that we shouldn't assume that the user adding an item to an order is doing so as a customer with a cart.
Comment #38
jsacksick commentedperhaps it should be
$order->getCustomer();instead indeed, but wondering if we shouldn't be more explicit, and just check that both the variation and the product are published.Comment #39
lisastreeter commented$order->getCustomer()would still be problematic for my site, for backend order creation/management. Also, isn't$contextusing$order->getCustomer()aleady?The variation+product published check would also be problematic for us. But perhaps in the more general case, these conditions make sense. We'd just disable this code for ourselves.
Essentially, we want to be able to hide products/variations from the customer that are not available in our "product catalog." They should be neither viewable on product pages nor purchasable by the typical, anonymous/authenticated user. But in the backend, administrative users should be able to add the products to an order. For adding products to an order administratively, we use a custom form with an
entity_autocompleteelement for the variation selection and aviewproviding the options. That works fine without this availability checker.Some products like this are always in this "internal only" state; others may switch from public to private because of certain conditions. For instance, we could discontinue a product but continue to allow certain customers to purchase remaining inventory. So we'd want to unpublish it on the website. And then at some point in the future, the product could come back. Or we could make some product by special request (since we're a manufacturing company) which we want to sell but not merchandise on our website.
Comment #40
zevior commentedI have another use case which i'd like to add. I have a multi-domain commerce site using the domain module. The payment provider only provides one notify url option. So the notify url will always be on the 'default' domain. On that domain the domain access module will say (for a lot of products that don't have the default domain selected) that there is no view access on the products in the cart.
Comment #41
khiminrm commentedRe-rolled the patch from #19 to the latest 2.x-dev, because it failed to apply on commerce_order.services.yml.
Comment #42
anybody@jsacksick shouldn't this target 3.0.x then based on #34 and get finished to be merged into that before release? (Just read through the comments and you wrote "Well, this is a needed functionality IMO")
I'll leave changing the target version to you.
Comment #43
zaporylieThis is a valid addition. However, with 3.x already released, we missed the opportunity to introduce it in a new major version—especially since it might not be backward compatible. That said, this is actually a good thing. We should ideally avoid introducing backward-incompatible changes even between major versions, when possible.
I believe this new checker can still be added, as long as it only affects new sites and existing sites retain their current behavior.
To make it easier for our core audience—ambitious site builders—to enable or disable availability rules and checkers as needed, I’ve proposed #3520439: Expose Availability Checkers in the Admin UI.