vendure-ecommerce/vendure

A later invocation of an OrderInterceptor-like concept

Opened this issue · 3 comments

Is your feature request related to a problem? Please describe.
Currently, the OrderInterceptor allows implementors to run checks before order mutations are committed. However, the willAddItemToOrder function does not have visibility into the Order nor OrderLine.

Describe the solution you'd like
Introduce a new function, similar to willAddItemToOrder, that runs at a later stage of the process, after an item has been added to the order (but not yet committed). This function should:

  • Provide access to the OrderLine with a valid id within the current context.
  • Allow implementors to reject the mutation by returning a string, throwing an error, or using a similar mechanism.
  • Trigger a rollback of the transaction if the mutation is rejected.

This additional functionality would enable more complex validations and use cases by allowing checks based on the newly added OrderLine.

Describe alternatives you've considered
We initially implemented a bundle-like concept by overriding Shop API mutations. This approach gave us access to the Order (via activeOrder) and the bundle's OrderLine, allowing us to manage relationships between bundle products and their child items. However, this solution is limited to the Shop API and does not leverage OrderInterceptor functionality.

We also considered extending this approach to the Admin API by overriding draft mutations, aiming for a solution where both Shop API and Admin API would implicitly handle child items. However, after learning about OrderInterceptors, we paused our implementation to explore whether they could provide an alternative.

Additional context
In our current implementation of bundles:

  • We tie child items to their parent (the bundle product).
  • The relative quantities of child items are maintained by noting how many are required for a single bundle and scaling accordingly (e.g., after add, adjust, or remove operations).
  • We reject shop-api attempts to mutate the child items directly.
  • The proposed enhancement to OrderInterceptor could make our implementation more clear and maintainable.

Hi,

Thanks for the good feedback on this new API!

I'm wondering whether we can just keep the existing API but invoke it later:
image

We would need to wrap the getOrCreateOrderLine() call in a transaction and manually roll back in the case that the interceptor returns an error.

Would you be interested in testing this out on your use-case and seeing if it is a viable approach?

Yes, I am interested.

One thought though: in this new flow OrderLine would exist in the OrderInterceptor's willAddItemToOrder func. Which is great. So I can call getExistingOrderLine or getOrCreate and expect a non-undefined. But, that means, in effect getExistingOrderLine would be called. Each call to getExisting is a loop over order.lines, and looks like an async check to compare customFields. I'm not sure how heavy that bit could be (I didn't spelunk deeper, but I suspect the custom fields comparison does some DB checks?).

If that custom field check is considered heavy, I propose two options:

  1. amend WillAddItemToOrderInput and add OrderLine in there. As well as moving it as you suggest.
  2. or, a new optional func on the OrderInterceptor
    • something like willAddLineItemToOrder
    • with its own input interface WillAddLineItemToOrderInput which is basically the original addItem version, plus OrderLine.

I think either version could land exactly where you pointed to, @michaelbromley.

Hi @michaelbromley, I might have a related issue. Here's a high-level summary:

I use resolvers to override the addition flow:

  • The caller invokes the flow with a variantId for a bundle.
  • The resolver detects it’s a bundle and:
  • Calls service.add(bundle-parent).
  • Loops through service.add(bundle-child).

This works.

I attempted a similar flow using OrderInterceptors for adjustOrderLine, but it’s not handling adjustments as expected. While both bundle-parent (triggered by the user) and bundle-children (triggered within my interceptor) hit my interceptor, only the bundle-parent gets adjusted. All my interceptors return successfully (no strings or exceptions thrown), but the adjustments for bundle-children aren’t applied (most noticeably, the quantity is not adjusted). I tried it by calling the singular and plural versions of adjustOrderLine, but neither flow returned error response; all flows appeared to signal success. No logs seemed to indicate errors.

Any intuition about what might be going wrong?