From 28fae96ceed68e2c15c3f27316c5b8601f06c478 Mon Sep 17 00:00:00 2001 From: Nicolas Gorga <62995075+NicolasGorga@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:58:41 -0300 Subject: [PATCH] fix(core-flows): Avoid throwing if no prices found for variant when adding to cart custom price item (#14528) * Avoid throwing prices not found error when line item is custom unit price * Add changeset * Avoid throwing upo variant price validation for custom priced item variants --- .changeset/pretty-planes-switch.md | 5 + .../cart/store/cart.workflows.spec.ts | 97 +++++++++++++++++++ .../src/cart/steps/get-variant-price-sets.ts | 13 ++- .../get-variants-and-items-with-prices.ts | 9 +- 4 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 .changeset/pretty-planes-switch.md diff --git a/.changeset/pretty-planes-switch.md b/.changeset/pretty-planes-switch.md new file mode 100644 index 0000000000..50dae109b0 --- /dev/null +++ b/.changeset/pretty-planes-switch.md @@ -0,0 +1,5 @@ +--- +"@medusajs/core-flows": patch +--- + +fix(core-flows): Avoid throwing if no prices found for variant when adding to cart custom price item diff --git a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts index 18ff6214a1..0b010e34c8 100644 --- a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts @@ -2474,6 +2474,103 @@ medusaIntegrationTestRunner({ ]) }) + it("should add item to cart with unit_price when variant has no price set", async () => { + const salesChannel = await scModuleService.createSalesChannels({ + name: "Webshop", + }) + + const location = await stockLocationModule.createStockLocations({ + name: "Warehouse", + }) + + let cart = await cartModuleService.createCarts({ + currency_code: "usd", + sales_channel_id: salesChannel.id, + }) + + const [product] = await productModule.createProducts([ + { + title: "Test product", + status: ProductStatus.PUBLISHED, + variants: [ + { + title: "Test variant", + }, + ], + }, + ]) + + const inventoryItem = await inventoryModule.createInventoryItems({ + sku: "inv-1234", + }) + + await inventoryModule.createInventoryLevels([ + { + inventory_item_id: inventoryItem.id, + location_id: location.id, + stocked_quantity: 2, + reserved_quantity: 0, + }, + ]) + + await remoteLink.create([ + { + [Modules.SALES_CHANNEL]: { + sales_channel_id: salesChannel.id, + }, + [Modules.STOCK_LOCATION]: { + stock_location_id: location.id, + }, + }, + { + [Modules.PRODUCT]: { + variant_id: product.variants[0].id, + }, + [Modules.INVENTORY]: { + inventory_item_id: inventoryItem.id, + }, + }, + ]) + + cart = await cartModuleService.retrieveCart(cart.id, { + select: ["id", "region_id", "currency_code", "sales_channel_id"], + }) + + // Add item with unit_price specified even though variant has no price set + await addToCartWorkflow(appContainer).run({ + input: { + items: [ + { + variant_id: product.variants[0].id, + quantity: 1, + unit_price: 5000, + }, + ], + cart_id: cart.id, + }, + }) + + cart = await cartModuleService.retrieveCart(cart.id, { + relations: ["items"], + }) + + expect(cart).toEqual( + expect.objectContaining({ + id: cart.id, + currency_code: "usd", + items: expect.arrayContaining([ + expect.objectContaining({ + unit_price: 5000, + is_custom_price: true, + quantity: 1, + title: "Test product", + subtitle: "Test variant", + }), + ]), + }) + ) + }) + describe("setPricingContext hook", () => { it("should use context provided by the hook", async () => { const salesChannel = await scModuleService.createSalesChannels({ diff --git a/packages/core/core-flows/src/cart/steps/get-variant-price-sets.ts b/packages/core/core-flows/src/cart/steps/get-variant-price-sets.ts index d3641f1654..bff1e6314f 100644 --- a/packages/core/core-flows/src/cart/steps/get-variant-price-sets.ts +++ b/packages/core/core-flows/src/cart/steps/get-variant-price-sets.ts @@ -91,13 +91,15 @@ async function fetchVariantPriceSets( } /** - * Validates that all variants have price sets and throws error for missing ones + * Validates that all variants without a custom price have price sets and throws error for missing ones */ function validateVariantPriceSets( - variantPriceSets: VariantPriceSetData[] + variantPriceSets: VariantPriceSetData[], + variantsWithCustomPrice: string[] = [] ): void { + const variantsWithCustomPriceSet = new Set(variantsWithCustomPrice) const notFound = variantPriceSets - .filter((v) => !v.price_set?.id) + .filter((v) => !v.price_set?.id && !variantsWithCustomPriceSet.has(v.id)) .map((v) => v.id) if (notFound.length) { @@ -287,7 +289,10 @@ export const getVariantPriceSetsStep = createStep( const variantIds = bulkData.map((item) => item.variantId) const variantPriceSets = await fetchVariantPriceSets(query, variantIds) - validateVariantPriceSets(variantPriceSets) + const variantsWithCustomPrice = bulkData + .filter((item) => !!item.context?.is_custom_price) + .map((item) => item.variantId) + validateVariantPriceSets(variantPriceSets, variantsWithCustomPrice) // Map variant IDs to price set IDs const variantToPriceSetId = new Map() diff --git a/packages/core/core-flows/src/cart/workflows/get-variants-and-items-with-prices.ts b/packages/core/core-flows/src/cart/workflows/get-variants-and-items-with-prices.ts index 348b39c4f2..101c99150e 100644 --- a/packages/core/core-flows/src/cart/workflows/get-variants-and-items-with-prices.ts +++ b/packages/core/core-flows/src/cart/workflows/get-variants-and-items-with-prices.ts @@ -125,6 +125,7 @@ export const getVariantsAndItemsWithPrices = createWorkflow( context: { ...baseContext, quantity: item.quantity, + is_custom_price: !!item.unit_price, }, } }) @@ -180,7 +181,10 @@ export const getVariantsAndItemsWithPrices = createWorkflow( calculatedPriceSet = calculatedPriceSets[item_.variant_id!] } - if (!calculatedPriceSet && item_.variant_id) { + const isCustomPrice = + item_.is_custom_price ?? isDefined(item?.unit_price) + + if (!calculatedPriceSet && item_.variant_id && !isCustomPrice) { priceNotFound.push(item_.variant_id) } @@ -198,9 +202,6 @@ export const getVariantsAndItemsWithPrices = createWorkflow( variant.calculated_price = calculatedPriceSet } - const isCustomPrice = - item_.is_custom_price ?? isDefined(item?.unit_price) - const input: PrepareLineItemDataInput = { item: item_, variant: variant,