fix(core-flows): Lock cart on shipping update (#13535)

This commit is contained in:
Oli Juhl
2025-09-17 21:29:45 +02:00
committed by GitHub
parent c847f7d8bf
commit 76497fd40a
4 changed files with 49 additions and 34 deletions

View File

@@ -1,3 +1,4 @@
import { addShippingMethodToCartWorkflow } from "@medusajs/core-flows"
import {
AdminInventoryItem,
AdminProduct,
@@ -242,15 +243,12 @@ export async function createOrderSeeder({
if (!withoutShipping) {
// Create shipping methods for each shipping option so shipping profiles of products in the cart are supported
await Promise.all(
shippingOptions.map(async (so) => {
await api.post(
`/store/carts/${cart.id}/shipping-methods`,
{ option_id: so.id },
storeHeaders
)
})
)
await addShippingMethodToCartWorkflow(container).run({
input: {
cart_id: cart.id,
options: shippingOptions.map((so) => ({ id: so.id })),
},
})
}
const paymentCollection = (

View File

@@ -1,4 +1,5 @@
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
import { AdminShippingOption } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/utils"
import {
adminHeaders,
@@ -9,7 +10,6 @@ import {
import { setupTaxStructure } from "../../../../modules/__tests__/fixtures"
import { createOrderSeeder } from "../../fixtures/order"
import { createShippingOptionSeeder } from "../../fixtures/shipping"
import { AdminShippingOption } from "@medusajs/types"
jest.setTimeout(300000)
@@ -980,23 +980,6 @@ medusaIntegrationTestRunner({
.order
})
it("should find the order querying it by number", async () => {
const userEmail = "tony@stark-industries.com"
const response = (
await api.get(`/admin/orders/?q=non-existing`, adminHeaders)
).data
expect(response.orders).toHaveLength(0)
const response2 = (
await api.get(`/admin/orders/?fields=+email&q=@stark`, adminHeaders)
).data
expect(response2.orders).toHaveLength(1)
expect(response2.orders[0].email).toEqual(userEmail)
})
it("should update stock levels correctly when creating partial fulfillment on an order", async () => {
const orderItemId = order.items.find(
(i) => i.variant_id === productOverride3.variants[0].id

View File

@@ -7,8 +7,10 @@ import {
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { AdditionalData } from "@medusajs/types"
import { emitEventStep } from "../../common/steps/emit-event"
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
import { acquireLockStep, releaseLockStep } from "../../locking"
import {
addShippingMethodToCartStep,
removeShippingMethodFromCartStep,
@@ -20,7 +22,6 @@ import { validateCartShippingOptionsPriceStep } from "../steps/validate-shipping
import { cartFieldsForRefreshSteps } from "../utils/fields"
import { listShippingOptionsForCartWithPricingWorkflow } from "./list-shipping-options-for-cart-with-pricing"
import { refreshCartItemsWorkflow } from "./refresh-cart-items"
import { AdditionalData } from "@medusajs/types"
/**
* The data to add a shipping method to a cart.
@@ -81,7 +82,16 @@ export const addShippingMethodToCartWorkflowId = "add-shipping-method-to-cart"
*/
export const addShippingMethodToCartWorkflow = createWorkflow(
addShippingMethodToCartWorkflowId,
(input: WorkflowData<AddShippingMethodToCartWorkflowInput & AdditionalData>) => {
(
input: WorkflowData<AddShippingMethodToCartWorkflowInput & AdditionalData>
) => {
acquireLockStep({
key: input.cart_id,
timeout: 2,
ttl: 10,
skipOnSubWorkflow: true,
})
const cart = useRemoteQueryStep({
entry_point: "cart",
fields: cartFieldsForRefreshSteps,
@@ -193,17 +203,28 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
}),
addShippingMethodToCartStep({
shipping_methods: shippingMethodInput,
}),
emitEventStep({
eventName: CartWorkflowEvents.UPDATED,
data: { id: input.cart_id },
})
)
refreshCartItemsWorkflow.runAsStep({
input: { cart_id: cart.id, shipping_methods: createdShippingMethods, additional_data: input.additional_data },
input: {
cart_id: cart.id,
shipping_methods: createdShippingMethods,
additional_data: input.additional_data,
},
})
parallelize(
emitEventStep({
eventName: CartWorkflowEvents.UPDATED,
data: { id: input.cart_id },
}),
releaseLockStep({
key: cart.id,
skipOnSubWorkflow: true,
})
)
return new WorkflowResponse(void 0, {
hooks: [validate],
})

View File

@@ -9,6 +9,7 @@ import {
when,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../common"
import { acquireLockStep, releaseLockStep } from "../../locking"
import { getItemTaxLinesStep } from "../../tax/steps/get-item-tax-lines"
import { setTaxLinesForItemsStep } from "../steps"
@@ -139,6 +140,13 @@ export const updateTaxLinesWorkflow = createWorkflow(
return input.cart ?? fetchCart
})
acquireLockStep({
key: cart.id,
timeout: 2,
ttl: 10,
skipOnSubWorkflow: true,
})
const taxLineItems = getItemTaxLinesStep(
transform({ input, cart }, (data) => ({
orderOrCart: data.cart,
@@ -153,5 +161,10 @@ export const updateTaxLinesWorkflow = createWorkflow(
item_tax_lines: taxLineItems.lineItemTaxLines,
shipping_tax_lines: taxLineItems.shippingMethodsTaxLines,
})
releaseLockStep({
key: cart.id,
skipOnSubWorkflow: true,
})
}
)