Skip to content
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

Order interceptor #2123

Closed
michaelbromley opened this issue Apr 13, 2023 · 9 comments
Closed

Order interceptor #2123

michaelbromley opened this issue Apr 13, 2023 · 9 comments

Comments

@michaelbromley
Copy link
Member

Is your feature request related to a problem? Please describe.
In some more advanced use-cases a need has emerged to be able to intercept operations on an order and do some validation or take some other side-effectful action.

Use-case: Product bundles

Ref: #236

Let's say we want to create a plugin that allows us to group multiple product variants into a "bundle" that can get purchased at a special price. We want to ensure that the entire bundle is added or removed at once, and not allow the bundle to be added and then have individual variants from that bundle removed.

Allowing us to intercept the "add item", "adjust quantity", "remove item" operations would let us enforce this constraint.

Use-case: Min, max quantities

We want to enforce a rule that a certain product has a minimum and maximum quantity that may be purchased in a single order (this is independent of stock control). Using validation allows us to enforce these constraints when the customer attempts to update the order contents.

Describe the solution you'd like

We should extend the OrderOptions interface to allow an array of OrderInterceptor objects which would look roughly like this:

interface OrderInterceptor extends InjectableStrategy {

  // Resolving to a string would signify an error, which would prevent the action from
  // taking place
  willAddItemToOrder(
    ctx: RequestContext, 
    order: Order, 
    productVariantId: ID, 
    quantity: number, 
    customFields: Record<string, any>): Promise<void | string>;

  // Args omitted for brevity
  didAddItemToOrder(...): Promise<void>;
  
  willAdjustOrderLine(...): Promise<void | string>;
  didAdjustOrderLine(...): Promise<void>;
  
  willRemoveItemFromOrder(...): Promise<void | string>;
  didRemoveItemFromOrder(...): Promise<void>;
}

So taking the min, max use-case, we could define the willAddItemToOrder hook to check the variant's custom fields for min, max values, and if the quantity being added does not fall within this range, we can return an error message.

Describe alternatives you've considered
An alternative is to re-implement the various graphql mutations that update order contents, but this is tedious, error-prone and does not handle instances where the OrderService APIs are used directly elsewhere.

@michaelbromley
Copy link
Member Author

A generalized version of this that is also worth considering would be to allow interceptors for all GraphQL operations.

This would allow users to "decorate" any existing operation. Could an existing NestJS mechanism be used for this? This could be the low-level implementation upon which the order interceptor is built.

As part of this task we'd need a working demo of product bundling plugin as well as a docs guide.

@michaelbromley michaelbromley moved this from 📅 Planned to 🤔 Under consideration in Vendure OS Roadmap Mar 19, 2024
@michaelbromley
Copy link
Member Author

Another use-case:

  • Protecting mutations with a Captcha. E.g. a Recaptcha plugin can intercept calls to addItemToOrder and reject if they fail a Recaptcha test

@michaelbromley michaelbromley moved this from 🤔 Under consideration to 📅 Planned in Vendure OS Roadmap Jul 22, 2024
@mschipperheyn
Copy link
Collaborator

Just a little tangent on the interface. What about wouldAddItemToOrder? We have a number of products that are age restricted or dependent on the previous purchase of other products. We have a plugin that processes the ability of a current user to add a product to his cart and display the ui accordingly. wouldAddItemToOrder would be a kind of dry run version where you throw a productVariant in there to know if it's addeable without requiring you to try and fail.

@martijnvdbrug
Copy link
Collaborator

A generalized version of this that is also worth considering would be to allow interceptors for all GraphQL operations.

This would allow users to "decorate" any existing operation. Could an existing NestJS mechanism be used for this? This could be the low-level implementation upon which the order interceptor is built.

As part of this task we'd need a working demo of product bundling plugin as well as a docs guide.

@michaelbromley Is there any timeline estimate on this feature?

We are currently in the midst of developing a product bundle plugin, and would like to contribute, as long as the release of this feature is somewhere in the coming months :-)

  • We can contribute on a working demo of the product bundles with this new API, if the API is available somewhere?
  • Is the product bundle expected to be part of core, or would you like a demo to see if the new API is sufficient for this usecase?

@martijnvdbrug
Copy link
Collaborator

martijnvdbrug commented Jul 24, 2024

Just a little tangent on the interface. What about wouldAddItemToOrder? We have a number of products that are age restricted or dependent on the previous purchase of other products. We have a plugin that processes the ability of a current user to add a product to his cart and display the ui accordingly. wouldAddItemToOrder would be a kind of dry run version where you throw a productVariant in there to know if it's addeable without requiring you to try and fail.

We do something similar in this plugins. If you throw an error, the transaction is rolled back, so no items are added. The benefit of this is that you don't have to do a dry run first, and repeat the action if the dry run succeeds

@michaelbromley
Copy link
Member Author

Hi @martijnvdbrug

I can't give a better estimate than "it's on the list for v3.x". It certainly won't be within 1 month. Perhaps 2 for a pre-release, but maybe 3 or more. I'll coordinate with you when I have a better idea of feature priority for the next minor.

@michaelbromley
Copy link
Member Author

Another use case:

  • Preventing products being added to cart when already in other active carts

Some shops have very limited stocks and if another active order already has that variant, they can then prevent it being added to another order (in a given time window)

@dlhck dlhck added this to the v3.1 milestone Sep 23, 2024
@dlhck dlhck removed the next minor label Sep 24, 2024
@dlhck
Copy link
Collaborator

dlhck commented Sep 28, 2024

@martijnvdbrug now there is an ETA available!

@michaelbromley michaelbromley self-assigned this Oct 31, 2024
@michaelbromley michaelbromley moved this from 📅 Planned to ♻️ In progress in Vendure OS Roadmap Nov 15, 2024
@michaelbromley michaelbromley pinned this issue Nov 15, 2024
@michaelbromley
Copy link
Member Author

@mschipperheyn

Just a little tangent on the interface. What about wouldAddItemToOrder? We have a number of products that are age restricted or dependent on the previous purchase of other products. We have a plugin that processes the ability of a current user to add a product to his cart and display the ui accordingly. wouldAddItemToOrder would be a kind of dry run version where you throw a productVariant in there to know if it's addeable without requiring you to try and fail.

I would see this as out of scope, since you can create a custom query that provides this functionality. You could even use a shared service for the actual logic, that you use in the OrderInterpector as well. In this way the custom query is just a thin wrapper around the shared business logic.

michaelbromley added a commit that referenced this issue Nov 25, 2024
michaelbromley added a commit that referenced this issue Nov 25, 2024
@michaelbromley michaelbromley mentioned this issue Nov 25, 2024
5 tasks
@dlhck dlhck unpinned this issue Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: ♻️ In progress
Development

No branches or pull requests

4 participants