chore(core-utils): avoid overfetching to refresh cart (#11602)

What:
 * Not all Cart operations need a full refresh updating items. This PR introduces a flag to force the refresh for special ocasions, like updating the Cart's region, or transfering the Cart to another customer. For all other flows it will update only promotions, taxes and payment collection if needed.
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2025-02-26 10:00:04 +00:00
1 parent eeebb35758
commit fa1793e8e9
7 files changed
+52 -31

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/core-flows": patch
---
chore(core-flows): avoid overfetching to refresh cart
@@ -2068,7 +2068,7 @@ medusaIntegrationTestRunner({
unit_price: 4000,
is_custom_price: true,
quantity: 2,
title: "Test variant",
title: "Test item",
})
)
})
@@ -35,6 +35,11 @@ export const cartFieldsForRefreshSteps = [
"customer.*",
"customer.groups.*",
"promotions.code",
"payment_collection.id",
"payment_collection.raw_amount",
"payment_collection.amount",
"payment_collection.currency_code",
"payment_collection.payment_sessions.id",
]
export const completeCartFields = [
@@ -4,7 +4,6 @@ import {
PromotionActions,
} from "@medusajs/framework/utils"
import {
createHook,
createWorkflow,
transform,
when,
@@ -41,6 +40,10 @@ export type RefreshCartItemsWorkflowInput = {
* These promotion codes will replace previously applied codes.
*/
promo_codes?: string[]
/**
* Force refresh the cart items
*/
force_refresh?: boolean
}
export const refreshCartItemsWorkflowId = "refresh-cart-items"
@@ -66,13 +69,13 @@ export const refreshCartItemsWorkflowId = "refresh-cart-items"
*
* Refresh a cart's details after an update.
*
* @property hooks.validate - This hook is executed before all operations. You can consume this hook to perform any custom validation. If validation fails, you can throw an error to stop the workflow execution.
*/
export const refreshCartItemsWorkflow = createWorkflow(
refreshCartItemsWorkflowId,
(
input: WorkflowData<RefreshCartItemsWorkflowInput>
) => {
(input: WorkflowData<RefreshCartItemsWorkflowInput>) => {
when({ input }, ({ input }) => {
return !!input.force_refresh
}).then(() => {
const cart = useRemoteQueryStep({
entry_point: "cart",
fields: cartFieldsForRefreshSteps,
@@ -88,10 +91,7 @@ export const refreshCartItemsWorkflow = createWorkflow(
return filterObjectByKeys(cart, cartFieldsForPricingContext)
})
const variants = when({ variantIds }, ({ variantIds }) => {
return !!variantIds.length
}).then(() => {
return useRemoteQueryStep({
const variants = useRemoteQueryStep({
entry_point: "variants",
fields: productVariantsFields,
variables: {
@@ -101,18 +101,14 @@ export const refreshCartItemsWorkflow = createWorkflow(
},
},
}).config({ name: "fetch-variants" })
})
validateVariantPricesStep({ variants })
const validate = createHook("validate", {
input,
cart,
})
const lineItems = transform({ cart, variants }, ({ cart, variants }) => {
const items = cart.items.map((item) => {
const variant = (variants ?? []).find((v) => v.id === item.variant_id)!
const variant = (variants ?? []).find(
(v) => v.id === item.variant_id
)!
const input: PrepareLineItemDataInput = {
item,
@@ -143,20 +139,21 @@ export const refreshCartItemsWorkflow = createWorkflow(
id: cart.id,
items: lineItems,
})
})
const refetchedCart = useRemoteQueryStep({
entry_point: "cart",
fields: cartFieldsForRefreshSteps,
variables: { id: cart.id },
variables: { id: input.cart_id },
list: false,
}).config({ name: "refetch–cart" })
refreshCartShippingMethodsWorkflow.runAsStep({
input: { cart_id: cart.id },
input: { cart_id: input.cart_id },
})
updateTaxLinesWorkflow.runAsStep({
input: { cart_id: cart.id },
input: { cart_id: input.cart_id },
})
const cartPromoCodes = transform(
@@ -172,18 +169,16 @@ export const refreshCartItemsWorkflow = createWorkflow(
updateCartPromotionsWorkflow.runAsStep({
input: {
cart_id: cart.id,
cart_id: input.cart_id,
promo_codes: cartPromoCodes,
action: PromotionActions.REPLACE,
},
})
refreshPaymentCollectionForCartWorkflow.runAsStep({
input: { cart_id: cart.id },
input: { cart: refetchedCart },
})
return new WorkflowResponse(refetchedCart, {
hooks: [validate],
})
return new WorkflowResponse(refetchedCart)
}
)
@@ -19,7 +19,11 @@ export type RefreshPaymentCollectionForCartWorklowInput = {
/**
* The cart's ID.
*/
cart_id: string
cart_id?: string
/**
* The Cart reference.
*/
cart?: any
}
export const refreshPaymentCollectionForCartWorkflowId =
@@ -52,7 +56,10 @@ export const refreshPaymentCollectionForCartWorkflowId =
export const refreshPaymentCollectionForCartWorkflow = createWorkflow(
refreshPaymentCollectionForCartWorkflowId,
(input: WorkflowData<RefreshPaymentCollectionForCartWorklowInput>) => {
const cart = useRemoteQueryStep({
const fetchCart = when({ input }, ({ input }) => {
return !input.cart
}).then(() => {
return useRemoteQueryStep({
entry_point: "cart",
fields: [
"id",
@@ -70,6 +77,11 @@ export const refreshPaymentCollectionForCartWorkflow = createWorkflow(
throw_if_key_not_found: true,
list: false,
})
})
const cart = transform({ fetchCart, input }, ({ fetchCart, input }) => {
return input.cart ?? fetchCart
})
const validate = createHook("validate", {
input,
@@ -17,7 +17,7 @@ export type TransferCartCustomerWorkflowInput = {
/**
* The cart's ID.
*/
id: string;
id: string
/**
* The ID of the customer to transfer the cart to.
*/
@@ -108,7 +108,7 @@ export const transferCartCustomerWorkflow = createWorkflow(
updateCartsStep(cartInput)
refreshCartItemsWorkflow.runAsStep({
input: { cart_id: input.id },
input: { cart_id: input.id, force_refresh: true },
})
}
)
@@ -27,8 +27,8 @@ import {
findSalesChannelStep,
updateCartsStep,
} from "../steps"
import { refreshCartItemsWorkflow } from "./refresh-cart-items"
import { validateSalesChannelStep } from "../steps/validate-sales-channel"
import { refreshCartItemsWorkflow } from "./refresh-cart-items"
/**
* The data to update the cart, along with custom data that's passed to the workflow's hooks.
@@ -278,7 +278,11 @@ export const updateCartWorkflow = createWorkflow(
})
const cart = refreshCartItemsWorkflow.runAsStep({
input: { cart_id: cartInput.id, promo_codes: input.promo_codes },
input: {
cart_id: cartInput.id,
promo_codes: input.promo_codes,
force_refresh: !!newRegion,
},
})
const cartUpdated = createHook("cartUpdated", {