Skip to content

[BUG] Shipping promotion discount uses stale shipping amount when cart items change (V2) #14484

@fogine

Description

@fogine

Bug Description

When using automatic promotions that apply a percentage discount to shipping methods (e.g., "Free shipping for orders >= $100"), the promotion discount is calculated using the old shipping amount instead of the newly calculated amount after cart items change.

This occurs because in refreshCartItemsWorkflow, the updateCartPromotionsWorkflow fetches cart data that contains the stale shipping method amount before refreshCartShippingMethodsWorkflow changes are visible.

Steps to Reproduce

  1. Create a calculated shipping option with a fulfillment provider that calculates shipping based on cart items (e.g., $4.79 + $1.50 per additional item)
  2. Create an automatic promotion for free shipping:
    {
      code: "FREE-SHIPPING-OVER-100",
      type: "standard",
      status: "active",
      is_automatic: true,
      rules: [{ attribute: "item_total", operator: "gte", values: ["100"] }],
      application_method: {
        type: "percentage",
        target_type: "shipping_methods",
        value: 100,  // 100% off
        allocation: "across"
      }
    }
  3. Add items to cart until item_total >= $100 with a shipping method selected

Expected Behavior

  • Shipping price recalculates (e.g., $9.29 → $10.79)
  • Promotion applies 100% discount on new amount ($10.79)
  • shipping_total = $0

Actual Behavior

  • Shipping price recalculates to $10.79
  • Promotion applies 100% discount on old amount ($9.29)
  • shipping_total = $1.50 (the difference)

Technical Analysis

In packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts:

// Line 243-245: Shipping methods are refreshed (price updated in DB)
refreshCartShippingMethodsWorkflow.runAsStep({
  input: refreshCartInput,
})

// Line 287-293: Promotions are computed
updateCartPromotionsWorkflow.runAsStep({
  input: {
    cart_id: input.cart_id,  // Fetches cart again
    promo_codes: cartPromoCodes,
    action: PromotionActions.REPLACE,
  },
})

The issue is that updateCartPromotionsWorkflow fetches cart data via useRemoteQueryStep, but the shipping method amount updated by refreshCartShippingMethodsWorkflow is not yet visible (likely due to transaction isolation within the workflow).

The promotion computation in packages/modules/promotion/src/utils/compute-actions/shipping-methods.ts uses method.subtotal (line 60, 66) which contains the stale value.

Environment

  • Medusa version: v2.x (latest)
  • Using calculated shipping options with custom fulfillment provider

Suggested Fix

Either:

  1. Pass the updated cart object from refreshCartShippingMethodsWorkflow to updateCartPromotionsWorkflow instead of re-fetching
  2. Or ensure the workflow step changes are flushed/committed before subsequent steps fetch data
  3. Or recalculate shipping prices within the promotion computation workflow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions