From c1385c70029b1c4fea0ece04abbf686366ac0e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frane=20Poli=C4=87?= <16856471+fPolic@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:48:58 +0100 Subject: [PATCH] fix(core-flows): cart validate sales channel (#11024) --- .../store/shipping-option.spec.ts | 26 ------------------- .../src/cart/steps/validate-sales-channel.ts | 20 ++++++++++++++ .../src/cart/workflows/create-carts.ts | 7 ++--- .../src/cart/workflows/update-cart.ts | 16 ++++++++---- 4 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 packages/core/core-flows/src/cart/steps/validate-sales-channel.ts diff --git a/integration-tests/http/__tests__/shipping-option/store/shipping-option.spec.ts b/integration-tests/http/__tests__/shipping-option/store/shipping-option.spec.ts index 9261db2b2d..c2479ffde4 100644 --- a/integration-tests/http/__tests__/shipping-option/store/shipping-option.spec.ts +++ b/integration-tests/http/__tests__/shipping-option/store/shipping-option.spec.ts @@ -313,32 +313,6 @@ medusaIntegrationTestRunner({ ) }) - it("should throw when required fields of a cart are not present", async () => { - cart = ( - await api.post( - `/store/carts`, - { - region_id: region.id, - currency_code: "usd", - sales_channel_id: null, - email: "test@admin.com", - items: [], - }, - storeHeaders - ) - ).data.cart - - const { response } = await api - .get(`/store/shipping-options?cart_id=${cart.id}`, storeHeaders) - .catch((e) => e) - - expect(response.data).toEqual({ - type: "invalid_data", - message: - "Field(s) are required to have value to continue - sales_channel_id", - }) - }) - it("should throw error when cart_id is not passed as a parameter", async () => { const { response } = await api .get(`/store/shipping-options`, storeHeaders) diff --git a/packages/core/core-flows/src/cart/steps/validate-sales-channel.ts b/packages/core/core-flows/src/cart/steps/validate-sales-channel.ts new file mode 100644 index 0000000000..e35de21069 --- /dev/null +++ b/packages/core/core-flows/src/cart/steps/validate-sales-channel.ts @@ -0,0 +1,20 @@ +import { MedusaError } from "@medusajs/framework/utils" +import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" + +import { SalesChannelDTO } from "@medusajs/types" + +export const validateSalesChannelStep = createStep( + "validate-sales-channel", + async (data: { salesChannel: SalesChannelDTO }) => { + const { salesChannel } = data + + if (!salesChannel?.id) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Sales channel is required when creating a cart. Either provide a sales channel ID or set the default sales channel for the store." + ) + } + + return new StepResponse(void 0) + } +) diff --git a/packages/core/core-flows/src/cart/workflows/create-carts.ts b/packages/core/core-flows/src/cart/workflows/create-carts.ts index 16f166644c..e27ae38ca1 100644 --- a/packages/core/core-flows/src/cart/workflows/create-carts.ts +++ b/packages/core/core-flows/src/cart/workflows/create-carts.ts @@ -35,6 +35,7 @@ import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory" import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-collection" import { updateCartPromotionsWorkflow } from "./update-cart-promotions" import { updateTaxLinesWorkflow } from "./update-tax-lines" +import { validateSalesChannelStep } from "../steps/validate-sales-channel" /** * The data to create the cart, along with custom data that's passed to the workflow's hooks. @@ -96,6 +97,8 @@ export const createCartWorkflow = createWorkflow( }) ) + validateSalesChannelStep({ salesChannel }) + // TODO: This is on par with the context used in v1.*, but we can be more flexible. const pricingContext = transform( { input, region, customerData }, @@ -155,9 +158,7 @@ export const createCartWorkflow = createWorkflow( data_.email = data.input?.email ?? data.customerData.customer.email } - if (data.salesChannel?.id) { - data_.sales_channel_id = data.salesChannel.id - } + data_.sales_channel_id = data.salesChannel!.id // If there is only one country in the region, we prepare a shipping address with that country's code. if ( diff --git a/packages/core/core-flows/src/cart/workflows/update-cart.ts b/packages/core/core-flows/src/cart/workflows/update-cart.ts index dc648045fe..dfe2a64e27 100644 --- a/packages/core/core-flows/src/cart/workflows/update-cart.ts +++ b/packages/core/core-flows/src/cart/workflows/update-cart.ts @@ -28,6 +28,7 @@ import { updateCartsStep, } from "../steps" import { refreshCartItemsWorkflow } from "./refresh-cart-items" +import { validateSalesChannelStep } from "../steps/validate-sales-channel" /** * The data to update the cart, along with custom data that's passed to the workflow's hooks. @@ -89,6 +90,7 @@ export const updateCartWorkflow = createWorkflow( "id", "email", "customer_id", + "sales_channel_id", "shipping_address.*", "region.*", "region.countries.*", @@ -97,8 +99,10 @@ export const updateCartWorkflow = createWorkflow( throw_if_key_not_found: true, }).config({ name: "get-cart" }) - const customerDataInput = transform({ input, cartToUpdate }, (data) => { + const cartDataInput = transform({ input, cartToUpdate }, (data) => { return { + sales_channel_id: + data.input.sales_channel_id ?? data.cartToUpdate.sales_channel_id, customer_id: data.cartToUpdate.customer_id, email: data.input.email ?? data.cartToUpdate.email, } @@ -106,14 +110,16 @@ export const updateCartWorkflow = createWorkflow( const [salesChannel, customer] = parallelize( findSalesChannelStep({ - salesChannelId: input.sales_channel_id, + salesChannelId: cartDataInput.sales_channel_id, }), findOrCreateCustomerStep({ - customerId: customerDataInput.customer_id, - email: customerDataInput.email, + customerId: cartDataInput.customer_id, + email: cartDataInput.email, }) ) + validateSalesChannelStep({ salesChannel }) + const newRegion = when({ input }, (data) => { return !!data.input.region_id }).then(() => { @@ -200,7 +206,7 @@ export const updateCartWorkflow = createWorkflow( } if (isDefined(updateCartData.sales_channel_id)) { - data_.sales_channel_id = data.salesChannel?.id || null + data_.sales_channel_id = data.salesChannel!.id } return data_