CartTransform Merge Operations seem unstable with quantities greater than 1 in-cart

nelsonmaze
Shopify Partner
5 0 0

Describe the bug

Line Item issues begin to occur with any multiple of a CartTransform Merge "bundle" being added to the cart (either by incrementing via form submission on the cart page or via cart AJAX API). Adding any other line items and bundles only exacerbates the issue.

 

Partner app dashboard logs indicate that function invocations are occurring where the cart line item inputs are being modified outside of the function's execution, along with potentially extra function invocations being made along the way (accelerating the duplication issues).

 

Steps to reproduce

 

Assumptions

  • Latest Dawn theme installed (little to no modifications to it that would impact this)
  • You have deployed a Function that uses MergeOperation to implement bundles in-cart
  • You have a Function configuration active that can create a bundle in-cart with multiple variants
    • For the purposes of this example, assume the bundle can be created from 3 products, with any of their 4 variants each, being valid components of the bundle.
    • You have access to your Function's log outputs from the Shopify Partner Dashboard


Steps

 

  1. Add 1 of each of the component products to the cart to manually create the bundle in-cart.
    • (2/3 bundle products added to cart)
      324933434-249ce8ed-6eb3-4bdd-91ac-300895a9e70a.png

       

    • (3/3 bundle products added to cart)
      324933722-fbbbfd6a-a8f3-448f-99e1-07cb3cf8bebb.png

       



    • Note that this first invocation/interaction properly results in a single bundle being rendered in cart. This is also evident in the partner logs. (3 products input results in 1 Merge Operation with the 3 required component line items in the correct quantities).

      FirstBundleInput.json
      FirstBundleOutput.json


  2. From the cart page, increment the bundle to 2 via the "+" button. The page will update and result in:

    • Another line item being added with a price of $0.00 and quantity of 2 

    • The first bundle's line item being updated to a quantity of 2

      324939246-0571c18f-9d75-4604-8bdc-b7ab4c3de05e.png

       

    • Note that this is not the theme rendering things incorrectly - the returned response from the Cart AJAX API clearly returns an "empty" bundle line item at $0.00: CartResponse_2_Bundles.json

    • This is also not the result of incorrect Function output, as the logs correctly display 2 merge operations, each for a group of 3 line items:
      SecondBundleInput.json
      SecondBundleOutput.json

    • Note that the "empty" line item is not found anywhere in the Function input/output logs.


  3. Proceed to checkout via the checkout button on the cart page with the current cart of 2 bundles and 2 "empty" bundles.

    • Note that this results in 2 function invocations, each with completely different inputs that seem to indicate line items were further cloned/duplicated between each invocation:

      First Checkout Visit, First Input: FirstCheckoutVisitInput.json
      First Checkout Visit, First Output: FirstCheckoutVisitOutput.json

      First Checkout Visit, Second Input: FirstCheckoutVisit_SecondInput.json
      First Checkout Visit, Second Output: FirstCheckoutVisit_SecondOutput.json
    • These function invocations with modified inputs result in the cart now being completely different from even the original "2" line items (Cart AJAX API line items JSON found here

      324948697-6f38028e-9084-4c0c-a664-eadcdb884b60.png

    • The expected outputs of the function are still technically correct - but the input varying is what is resulting in this behavior between invocations, not the function execution itself.

    • The only user interaction here between function invocations was the visit to checkout.


  4. Navigate back to the cart page, and attempt to "correct" the cart by deleting a line item (any of them)

    • This only results in a continuation of the duplication issues, which after 2 attempts finally results in such a large quantity of line items that the runtime instruction count limit is exceeded, finally resulting in all bundles being broken up, as shown in the cart.

      324953785-9bdc997b-187f-46da-8752-693ad1f696eb.png
    •  The Function input/output logs of this are below:
      DeleteAttemptInput: DeleteAttemptInput.json
      DeleteAttemptOutput: DeleteAttemptOutput.json

Expected behavior

  • Adding/deleting multiple mergeOperation bundles to the cart should behave the same as adding/deleting multiple "normal" variants to the cart (via form submission or cart AJAX API).

  • Incrementing and decrementing the quantity of mergeOperation bundles should behave the same as with "normal" variants and should increment/decrement the underlying component variants in the cart properly.

  • Line items should not duplicate without user interaction and the pricing should be consistent with multiple bundles added to the cart.

  • Merge Operations should not result in bug/artifact line items being added to the cart response JSON.

 

Environment

  • Latest Product Discount Function API for Rust (04/2024) - tested newest RC and unstable. Same situation.
  • Latest Version Dawn theme (for frontend testing purposes)
  • Latest Shopify CLI
  • Shopify Plus Sandbox Store

 

Additional context


This is occurring in multiple Shopify Plus environments.

 

The issue is not the code - this is a simple step-through similar to the function example for merge operations. Duplication is also not possible with the existing API, as documented at time of writing.

 

I have passed various combinations of parameters required by Merge Operation, including the image, parent variant, title, etc. No changes here impact the behavior described above.

 

The metafield configuration being passed is not the issue, it is simply compressed in the above examples. The Function above panics with an invalid configuration.

 

 

 

Replies 9 (9)

siddhantbajaj
Shopify Staff
6 1 1

Hey @nelsonmaze 

as the logs correctly display 2 merge operations, each for a group of 3 line items

I would actually expect the function to output only 1 merge operation that specify the bundle composition. You don't need additional merge operation every time the component quantity is increased. We will perform the calculation on end to determine the quantity of parent by looking at the bundle composition from merge operation and the quantity of component present in the cart.

For example in your case, just outputting a single merge operation like below should be enough:

{parent_variant_id: ID, cart_lines: [{id: ID, quantity: 1},{id: ID, quantity: 1}] }

To learn more visit the Shopify Help Center or the Community Blog.

nelsonmaze
Shopify Partner
5 0 0

Hi @siddhantbajaj ,

 

This example simplifies the issue a bit, but the reason I expect it to output multiple MergeOperations is for the use case of two bundles of distinct makeups being handled by the same Function.

 

If I have 3 products I'd like to have qualify for this bundle, each with size variations S/M, I would expect the same Function invocation to be able to handle 2 distinct combinations of these product variants. 

 

I've added a check to the code to prevent the same operation from being added in this sense, but the same duplication issues still occur.

 

Implementing something that outputs a single Merge for two distinct makeups results in something like the below output, which does not result in the two distinct bundles, but a single "combined" one:

 

{
  "operations": [
    {
      "merge": {
        "attributes": [
          {
            "key": "_bundle_id",
            "value": "string_id_3"
          }
        ],
        "cartLines": [
          {
            "cartLineId": "gid://shopify/CartLine/ee4bfc32-07e7-42ba-9fc4-83fa4ea15aec",
            "quantity": 1
          },
          {
            "cartLineId": "gid://shopify/CartLine/5a4ea6cd-f483-4105-8519-3ab4e0f9ad48",
            "quantity": 2
          },
          {
            "cartLineId": "gid://shopify/CartLine/6df9c4f9-4bdc-45d8-a48b-0c2423875e3d",
            "quantity": 2
          },
          {
            "cartLineId": "gid://shopify/CartLine/79c88b3f-6ebf-4268-990d-e2870645a64b",
            "quantity": 1
          }
        ],
        "parentVariantId": "gid://shopify/ProductVariant/45722712867048",
        "title": "Total Robot Bundle Product"
      }
    }
  ]
}

 

nelsonmaze
Shopify Partner
5 0 0

Seeing now that this approach seems in conflict with the docs:

 

nelsonmaze_0-1714527338078.png

 

 

However, even when assigning line item properties to distinguish "duplicate" bundle components, the same duplication issues still occur with quantities greater than 1 for any merged bundle.

 

Is there any reason merge operations must be limited by the cart line target instead of remaining quantities on the cart line targets?

 

Also - is there any limitation on the amount of CartTransforms that can be active on a store at any given time?

 

 

siddhantbajaj
Shopify Staff
6 1 1

You can handle that case in multiple iterations. In the first function invocation, you can output a single merge operations targeting a limited quantity of a cart line. This will split the line into 2 parts, one part becomes a part of the bundle. In the next function execution, your input will now have two lines for the same variant and now you can out 2 merge operations for each line respectively.

Yes we do have a limitation of maximum 1 cart transform per shop for a single app. 

To learn more visit the Shopify Help Center or the Community Blog.

nelsonmaze
Shopify Partner
5 0 0

Even with added checks to prevent duplicate bundle merge operations, there are still pricing issues in-cart, with the cart object requiring checkout visits to finally show the correct pricing. In this example, the two bundles in-cart have their quantities incrementing/decrementing fine, but the pricing for the second bundle gets zeroed out upon any cart modification.

nelsonmaze_0-1714683796643.png

 

Even modifying the unrelated non-bundle product quantity results in the second unique bundle's pricing to go to $0.00.

 

Meanwhile, visiting checkout results in the correct pricing being calculated:

nelsonmaze_1-1714683858616.png

 

Navigating back to cart from checkout is the only way to get the "correct" pricing to display properly.

 

sevenminds
Shopify Partner
12 0 1

I can confirm incorrect prices on bundles (when there are a few of them in the cart) and that navigating to checkout fixes them. We have customers complaining about this issue.

siddhantbajaj
Shopify Staff
6 1 1

I have a hunch that your function is outputting two merge operations that target the same cart line, which is causing these price inconsistencies. Can you confirm if that is the case?

To learn more visit the Shopify Help Center or the Community Blog.

sevenminds
Shopify Partner
12 0 1

In our case, we have four cart lines. The first two are merged into one bundle, and the remaining two are merged into another. The second bundle has an incorrect price until we navigate to the checkout page.

nelsonmaze
Shopify Partner
5 0 0

This is indeed the case for these scenarios - but I don't see distinguishing cart lines with unique properties as a feasible solution to allowing customers to build bundles manually.

 

In the situation where a user manually constructs an example bundle of:

- T-shirt (S) x 1

- Hat (M) x 1

 

and triggers a bundle, and then follows up with another addition of:

 

- T-shirt (L) x 1

- Hat (M) x 1

 

In order to prevent the two hats from causing a cart line overlap issue, a unique property could be assigned, but that would result in every hat the customer adds to the cart being in their own cart line, which is undesirable here.

 

Forcing the checkout form to trigger function invocations to be able to fetch the corrected pricing also does not sound like a great solution to this, but might be able to serve as a workaround.

 

The ideal state here is that the cart additions above result in two separate bundle line items, each with their own T-Shirt/Hat bundle components, despite Hat being pulled from a single cart line.