From b7044bb3b09bd6e6ae5bb15edc339ce05c3c86b0 Mon Sep 17 00:00:00 2001 From: Riqwan Thamir Date: Tue, 19 Nov 2024 12:44:25 +0100 Subject: [PATCH] feat(core-flows,medusa): Add API to update cart's customer (#10151) what: - adds an endpoint that updates a cart's customer RESOLVES CMRC-718 --- .../http/__tests__/cart/store/cart.spec.ts | 316 +++++++++++++++--- .../__tests__/cart/store/carts.spec.ts | 3 +- .../store/create-customer-addresses.ts | 5 +- .../store/delete-customer-address.spec.ts | 7 +- .../__tests__/customer/store/get-me.spec.ts | 5 +- .../customer/store/list-customer-addresses.ts | 5 +- .../store/update-customer-address.spec.ts | 7 +- .../helpers/create-authenticated-customer.ts | 60 ++-- .../core-flows/src/cart/workflows/index.ts | 1 + .../cart/workflows/update-cart-customer.ts | 98 ++++++ .../api/store/carts/[id]/customer/route.ts | 30 ++ .../medusa/src/api/store/carts/middlewares.ts | 21 +- .../medusa/src/api/store/carts/validators.ts | 5 + 13 files changed, 462 insertions(+), 101 deletions(-) create mode 100644 packages/core/core-flows/src/cart/workflows/update-cart-customer.ts create mode 100644 packages/medusa/src/api/store/carts/[id]/customer/route.ts diff --git a/integration-tests/http/__tests__/cart/store/cart.spec.ts b/integration-tests/http/__tests__/cart/store/cart.spec.ts index 8f244080f7..6b5b9f6c99 100644 --- a/integration-tests/http/__tests__/cart/store/cart.spec.ts +++ b/integration-tests/http/__tests__/cart/store/cart.spec.ts @@ -1,3 +1,4 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { Modules, PriceListStatus, @@ -6,39 +7,19 @@ import { PromotionRuleOperator, PromotionType, } from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { createAdminUser, generatePublishableKey, generateStoreHeaders, } from "../../../../helpers/create-admin-user" import { setupTaxStructure } from "../../../../modules/__tests__/fixtures" +import { createAuthenticatedCustomer } from "../../../../modules/helpers/create-authenticated-customer" jest.setTimeout(100000) const env = { MEDUSA_FF_MEDUSA_V2: true } const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } -const generateStoreHeadersWithCustomer = async ({ - api, - storeHeaders, - customer, -}) => { - const registeredCustomerToken = ( - await api.post("/auth/customer/emailpass/register", { - email: customer.email, - password: "password", - }) - ).data.token - - return { - headers: { - ...storeHeaders.headers, - authorization: `Bearer ${registeredCustomerToken}`, - }, - } -} - const shippingAddressData = { address_1: "test address 1", address_2: "test address 2", @@ -136,23 +117,20 @@ medusaIntegrationTestRunner({ const publishableKey = await generatePublishableKey(appContainer) storeHeaders = generateStoreHeaders({ publishableKey }) - customer = ( - await api.post( - "/admin/customers", - { - first_name: "tony", - email: "tony@stark-industries.com", - }, - adminHeaders - ) - ).data.customer - - storeHeadersWithCustomer = await generateStoreHeadersWithCustomer({ - storeHeaders, - api, - customer, + const result = await createAuthenticatedCustomer(api, storeHeaders, { + first_name: "tony", + last_name: "stark", + email: "tony@stark-industries.com", }) + customer = result.customer + storeHeadersWithCustomer = { + headers: { + ...storeHeaders.headers, + authorization: `Bearer ${result.jwt}`, + }, + } + await setupTaxStructure(appContainer.resolve(Modules.TAX)) region = ( @@ -582,21 +560,17 @@ medusaIntegrationTestRunner({ let otherRegion beforeEach(async () => { - cart = ( - await api.post( - `/store/carts`, - { - email: "tony@stark.com", - currency_code: "usd", - sales_channel_id: salesChannel.id, - region_id: region.id, - shipping_address: shippingAddressData, - items: [{ variant_id: product.variants[0].id, quantity: 1 }], - promo_codes: [promotion.code], - }, - storeHeadersWithCustomer - ) - ).data.cart + const cartData = { + currency_code: "usd", + sales_channel_id: salesChannel.id, + region_id: region.id, + shipping_address: shippingAddressData, + items: [{ variant_id: product.variants[0].id, quantity: 1 }], + promo_codes: [promotion.code], + } + + cart = (await api.post(`/store/carts`, cartData, storeHeaders)).data + .cart otherRegion = ( await api.post( @@ -751,7 +725,7 @@ medusaIntegrationTestRunner({ it("should not generate tax lines if automatic taxes is false", async () => { let updated = await api.post( `/store/carts/${cart.id}`, - { email: "another@tax.com" }, + {}, storeHeaders ) @@ -776,7 +750,7 @@ medusaIntegrationTestRunner({ updated = await api.post( `/store/carts/${cart.id}`, - { email: "another@tax.com", region_id: noAutomaticRegion.id }, + { region_id: noAutomaticRegion.id }, storeHeaders ) @@ -1236,6 +1210,242 @@ medusaIntegrationTestRunner({ }) ) }) + + it("should update email irregardless of registered customer", async () => { + const updateEmailWithoutCustomer = await api.post( + `/store/carts/${cart.id}`, + { email: "tony@stark.com" }, + storeHeaders + ) + + expect(updateEmailWithoutCustomer.data.cart).toEqual( + expect.objectContaining({ + email: "tony@stark.com", + customer: expect.objectContaining({ + email: "tony@stark.com", + }), + }) + ) + + const updateCartCustomer = await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + expect(updateCartCustomer.data.cart).toEqual( + expect.objectContaining({ + email: "tony@stark-industries.com", + customer: expect.objectContaining({ + id: customer.id, + email: "tony@stark-industries.com", + }), + }) + ) + + const updateEmailWithCustomer = await api.post( + `/store/carts/${cart.id}`, + { email: "new@stark.com" }, + storeHeaders + ) + + expect(updateEmailWithCustomer.data.cart).toEqual( + expect.objectContaining({ + email: "new@stark.com", + customer: expect.objectContaining({ + id: customer.id, + email: "tony@stark-industries.com", + }), + }) + ) + }) + }) + + describe("POST /store/carts/:id/customer", () => { + beforeEach(async () => { + cart = ( + await api.post( + `/store/carts`, + { + currency_code: "usd", + sales_channel_id: salesChannel.id, + region_id: region.id, + items: [{ variant_id: product.variants[0].id, quantity: 1 }], + }, + storeHeaders + ) + ).data.cart + }) + + it("should throw 401 when user is not logged in as a customer", async () => { + const { response } = await api + .post(`/store/carts/${cart.id}/customer`, {}, storeHeaders) + .catch((e) => e) + + expect(response.status).toEqual(401) + }) + + it("should throw error when cart does not exist", async () => { + const { response } = await api + .post( + `/store/carts/does-not-exist/customer`, + {}, + storeHeadersWithCustomer + ) + .catch((e) => e) + + expect(response.status).toEqual(404) + expect(response.data.message).toEqual( + "Cart id not found: does-not-exist" + ) + }) + + it("should throw error when trying to update a cart that belongs to a customer that has an account", async () => { + const customerUpdate1 = await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + expect(customerUpdate1.status).toEqual(200) + expect(customerUpdate1.data.cart).toEqual( + expect.objectContaining({ + email: customer.email, + customer: expect.objectContaining({ + id: customer.id, + email: customer.email, + }), + }) + ) + + const { jwt: jwt2 } = await createAuthenticatedCustomer( + api, + storeHeaders, + { + first_name: "tony2", + last_name: "stark", + email: "tony2@stark-industries.com", + } + ) + + const storeHeadersWithCustomer2 = { + headers: { + ...storeHeaders.headers, + authorization: `Bearer ${jwt2}`, + }, + } + + const { response } = await api + .post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer2 + ) + .catch((e) => e) + + expect(response.status).toEqual(400) + expect(response.data.message).toEqual( + "Cannot update cart customer when its assigned to a different customer" + ) + }) + + it("should successfully update cart customer when cart is without customer", async () => { + const updated = await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + expect(updated.status).toEqual(200) + expect(updated.data.cart).toEqual( + expect.objectContaining({ + email: customer.email, + customer: expect.objectContaining({ + id: customer.id, + email: customer.email, + }), + }) + ) + }) + + it("should successfully update cart customer when cart has a guest customer", async () => { + const guestEmail = "tony@guest.com" + const updatedCart = await api.post( + `/store/carts/${cart.id}`, + { email: guestEmail }, + storeHeadersWithCustomer + ) + + expect(updatedCart.status).toEqual(200) + expect(updatedCart.data.cart).toEqual( + expect.objectContaining({ + email: guestEmail, + customer: expect.objectContaining({ + email: guestEmail, + }), + }) + ) + + const updated = await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + expect(updated.status).toEqual(200) + expect(updated.data.cart).toEqual( + expect.objectContaining({ + email: customer.email, + customer: expect.objectContaining({ + id: customer.id, + email: customer.email, + }), + }) + ) + }) + + it("should successfully update cart customer when customer already owns the cart", async () => { + const guestEmail = "tony@guest.com" + + await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + const updatedCart = await api.post( + `/store/carts/${cart.id}`, + { email: guestEmail }, + storeHeadersWithCustomer + ) + + expect(updatedCart.status).toEqual(200) + expect(updatedCart.data.cart).toEqual( + expect.objectContaining({ + email: guestEmail, + customer: expect.objectContaining({ + email: customer.email, + }), + }) + ) + + const updated = await api.post( + `/store/carts/${cart.id}/customer`, + {}, + storeHeadersWithCustomer + ) + + expect(updated.status).toEqual(200) + expect(updated.data.cart).toEqual( + expect.objectContaining({ + email: guestEmail, + customer: expect.objectContaining({ + id: customer.id, + email: customer.email, + }), + }) + ) + }) }) }) }, diff --git a/integration-tests/modules/__tests__/cart/store/carts.spec.ts b/integration-tests/modules/__tests__/cart/store/carts.spec.ts index e40873c772..050dfd7488 100644 --- a/integration-tests/modules/__tests__/cart/store/carts.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/carts.spec.ts @@ -417,7 +417,8 @@ medusaIntegrationTestRunner({ it("should create cart with logged-in customer", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) const response = await api.post( diff --git a/integration-tests/modules/__tests__/customer/store/create-customer-addresses.ts b/integration-tests/modules/__tests__/customer/store/create-customer-addresses.ts index 1c557f0bd0..a212d9caaa 100644 --- a/integration-tests/modules/__tests__/customer/store/create-customer-addresses.ts +++ b/integration-tests/modules/__tests__/customer/store/create-customer-addresses.ts @@ -1,6 +1,6 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { ICustomerModuleService } from "@medusajs/types" import { Modules } from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { generatePublishableKey, generateStoreHeaders, @@ -31,7 +31,8 @@ medusaIntegrationTestRunner({ it("should create a customer address", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) const response = await api.post( diff --git a/integration-tests/modules/__tests__/customer/store/delete-customer-address.spec.ts b/integration-tests/modules/__tests__/customer/store/delete-customer-address.spec.ts index f474c41174..d9825f26e4 100644 --- a/integration-tests/modules/__tests__/customer/store/delete-customer-address.spec.ts +++ b/integration-tests/modules/__tests__/customer/store/delete-customer-address.spec.ts @@ -1,6 +1,6 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { ICustomerModuleService } from "@medusajs/types" import { Modules } from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { generatePublishableKey, generateStoreHeaders, @@ -32,7 +32,8 @@ medusaIntegrationTestRunner({ it("should delete a customer address", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) const address = await customerModuleService.createCustomerAddresses({ @@ -65,7 +66,7 @@ medusaIntegrationTestRunner({ }) it("should fail to delete another customer's address", async () => { - const { jwt } = await createAuthenticatedCustomer(appContainer) + const { jwt } = await createAuthenticatedCustomer(api, storeHeaders) const otherCustomer = await customerModuleService.createCustomers({ first_name: "Jane", diff --git a/integration-tests/modules/__tests__/customer/store/get-me.spec.ts b/integration-tests/modules/__tests__/customer/store/get-me.spec.ts index 17716300b4..19069cf9c5 100644 --- a/integration-tests/modules/__tests__/customer/store/get-me.spec.ts +++ b/integration-tests/modules/__tests__/customer/store/get-me.spec.ts @@ -28,7 +28,8 @@ medusaIntegrationTestRunner({ it("should retrieve auth user's customer", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) const response = await api.get(`/store/customers/me`, { @@ -41,7 +42,7 @@ medusaIntegrationTestRunner({ id: customer.id, first_name: "John", last_name: "Doe", - email: "john@me.com", + email: "tony@start.com", }) ) }) diff --git a/integration-tests/modules/__tests__/customer/store/list-customer-addresses.ts b/integration-tests/modules/__tests__/customer/store/list-customer-addresses.ts index e84c725df8..991a9d7348 100644 --- a/integration-tests/modules/__tests__/customer/store/list-customer-addresses.ts +++ b/integration-tests/modules/__tests__/customer/store/list-customer-addresses.ts @@ -1,6 +1,6 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { ICustomerModuleService } from "@medusajs/types" import { Modules } from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { generatePublishableKey, generateStoreHeaders, @@ -32,7 +32,8 @@ medusaIntegrationTestRunner({ it("should get all customer addresses and its count", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) await customerModuleService.createCustomerAddresses([ diff --git a/integration-tests/modules/__tests__/customer/store/update-customer-address.spec.ts b/integration-tests/modules/__tests__/customer/store/update-customer-address.spec.ts index cc0820aee7..1e422fda8b 100644 --- a/integration-tests/modules/__tests__/customer/store/update-customer-address.spec.ts +++ b/integration-tests/modules/__tests__/customer/store/update-customer-address.spec.ts @@ -1,6 +1,6 @@ +import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { ICustomerModuleService } from "@medusajs/types" import { Modules } from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { generatePublishableKey, generateStoreHeaders, @@ -32,7 +32,8 @@ medusaIntegrationTestRunner({ it.only("should update a customer address", async () => { const { customer, jwt } = await createAuthenticatedCustomer( - appContainer + api, + storeHeaders ) const address = await customerModuleService.createCustomerAddresses({ @@ -66,7 +67,7 @@ medusaIntegrationTestRunner({ }) it("should fail to update another customer's address", async () => { - const { jwt } = await createAuthenticatedCustomer(appContainer) + const { jwt } = await createAuthenticatedCustomer(api, storeHeaders) const otherCustomer = await customerModuleService.createCustomers({ first_name: "Jane", diff --git a/integration-tests/modules/helpers/create-authenticated-customer.ts b/integration-tests/modules/helpers/create-authenticated-customer.ts index bbf1c40f2d..e9f139a820 100644 --- a/integration-tests/modules/helpers/create-authenticated-customer.ts +++ b/integration-tests/modules/helpers/create-authenticated-customer.ts @@ -1,43 +1,39 @@ -import { CreateCustomerDTO, MedusaContainer } from "@medusajs/types" -import { Modules } from "@medusajs/utils" - -import jwt from "jsonwebtoken" +import { CreateCustomerDTO } from "@medusajs/types" export const createAuthenticatedCustomer = async ( - appContainer: MedusaContainer, + api: any, + storeHeaders: Record, customerData: Partial = {} ) => { - const { http } = appContainer.resolve("configModule").projectConfig - const authService = appContainer.resolve(Modules.AUTH) - const customerModuleService = appContainer.resolve(Modules.CUSTOMER) - - const customer = await customerModuleService.createCustomers({ - first_name: "John", - last_name: "Doe", - email: "john@me.com", - ...customerData, + const email = customerData.email ?? "tony@start.com" + const signup = await api.post("/auth/customer/emailpass/register", { + email, + password: "secret_password", }) - const authIdentity = await authService.createAuthIdentities({ - provider_identities: [ - { - entity_id: "store_user", - provider: "emailpass", - }, - ], - app_metadata: { - customer_id: customer.id, - }, - }) - - const token = jwt.sign( + const { + data: { customer }, + } = await api.post( + "/store/customers", { - actor_id: customer.id, - actor_type: "customer", - auth_identity_id: authIdentity.id, + email, + first_name: "John", + last_name: "Doe", + metadata: {}, + ...customerData, }, - http.jwtSecret + { + headers: { + authorization: `Bearer ${signup.data.token}`, + ...storeHeaders.headers, + }, + } ) - return { customer, authIdentity, jwt: token } + const signin = await api.post("/auth/customer/emailpass", { + email, + password: "secret_password", + }) + + return { customer, jwt: signin.data.token } } diff --git a/packages/core/core-flows/src/cart/workflows/index.ts b/packages/core/core-flows/src/cart/workflows/index.ts index 8bd5203d9e..cf0d360885 100644 --- a/packages/core/core-flows/src/cart/workflows/index.ts +++ b/packages/core/core-flows/src/cart/workflows/index.ts @@ -7,6 +7,7 @@ export * from "./create-payment-collection-for-cart" export * from "./list-shipping-options-for-cart" export * from "./refresh-payment-collection" export * from "./update-cart" +export * from "./update-cart-customer" export * from "./update-cart-promotions" export * from "./update-line-item-in-cart" export * from "./update-tax-lines" diff --git a/packages/core/core-flows/src/cart/workflows/update-cart-customer.ts b/packages/core/core-flows/src/cart/workflows/update-cart-customer.ts new file mode 100644 index 0000000000..20a6449dec --- /dev/null +++ b/packages/core/core-flows/src/cart/workflows/update-cart-customer.ts @@ -0,0 +1,98 @@ +import { isDefined, MedusaError } from "@medusajs/framework/utils" +import { + createStep, + createWorkflow, + StepResponse, + transform, + when, + WorkflowData, +} from "@medusajs/framework/workflows-sdk" +import { CustomerDTO } from "@medusajs/types" +import { useQueryGraphStep } from "../../common" +import { updateCartsStep } from "../steps" + +/** + * This step validates if cart should be updated + */ +export const validateCartCustomerUpdateStep = createStep( + "validate-cart-customer-update", + async function ({ + cart, + customer, + }: { + cart: { + customer?: { id: string; has_account: boolean } + } + customer: CustomerDTO + }) { + // If cart customer is the same as the provided customer, succeed early + // Pass in a boolean to not perform a customer update + if (isDefined(cart.customer?.id) && cart.customer.id === customer.id) { + return new StepResponse(false) + } + + // If the cart customer already has an account, we can safely assume that its already + // been assigned to a different customer. This falls under cart take over, which isn't being + // handled with this workflow + if (cart.customer?.has_account) { + throw new MedusaError( + MedusaError.Types.NOT_ALLOWED, + `Cannot update cart customer when its assigned to a different customer` + ) + } + + return new StepResponse(true) + } +) + +export const updateCartCustomerWorkflowId = "update-cart-customer" +/** + * This workflow updates cart's customer. + */ +export const updateCartCustomerWorkflow = createWorkflow( + updateCartCustomerWorkflowId, + (input: WorkflowData<{ id: string; customer_id: string }>) => { + const cartQuery = useQueryGraphStep({ + entity: "cart", + filters: { id: input.id }, + fields: [ + "id", + "email", + "customer_id", + "customer.has_account", + "shipping_address.*", + "region.*", + "region.countries.*", + ], + options: { throwIfKeyNotFound: true }, + }).config({ name: "get-cart" }) + + const cart = transform({ cartQuery }, ({ cartQuery }) => cartQuery.data[0]) + + const customerQuery = useQueryGraphStep({ + entity: "customer", + filters: { id: input.customer_id }, + fields: ["id", "email"], + options: { throwIfKeyNotFound: true }, + }).config({ name: "get-customer" }) + + const customer = transform( + { customerQuery }, + ({ customerQuery }) => customerQuery.data[0] + ) + + const shouldUpdate = validateCartCustomerUpdateStep({ cart, customer }) + + when({ shouldUpdate }, ({ shouldUpdate }) => !!shouldUpdate).then(() => { + const cartInput = transform({ cart, customer }, ({ cart, customer }) => [ + { + id: cart.id, + customer_id: customer.id, + email: customer.email, + }, + ]) + + updateCartsStep(cartInput) + }) + } +) diff --git a/packages/medusa/src/api/store/carts/[id]/customer/route.ts b/packages/medusa/src/api/store/carts/[id]/customer/route.ts new file mode 100644 index 0000000000..2d2a6ae747 --- /dev/null +++ b/packages/medusa/src/api/store/carts/[id]/customer/route.ts @@ -0,0 +1,30 @@ +import { updateCartCustomerWorkflow } from "@medusajs/core-flows" +import { HttpTypes } from "@medusajs/framework/types" + +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "@medusajs/framework/http" +import { refetchCart } from "../../helpers" + +export const POST = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const workflow = updateCartCustomerWorkflow(req.scope) + + await workflow.run({ + input: { + id: req.params.id, + customer_id: req.auth_context?.actor_id, + }, + }) + + const cart = await refetchCart( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) + + res.status(200).json({ cart }) +} diff --git a/packages/medusa/src/api/store/carts/middlewares.ts b/packages/medusa/src/api/store/carts/middlewares.ts index eea117f6e2..9d2e651ddf 100644 --- a/packages/medusa/src/api/store/carts/middlewares.ts +++ b/packages/medusa/src/api/store/carts/middlewares.ts @@ -1,8 +1,10 @@ -import { MiddlewareRoute } from "@medusajs/framework/http" +import { + validateAndTransformBody, + validateAndTransformQuery, +} from "@medusajs/framework" +import { authenticate, MiddlewareRoute } from "@medusajs/framework/http" import { ensurePublishableKeyAndSalesChannelMatch } from "../../utils/middlewares/common/ensure-pub-key-sales-channel-match" import { maybeAttachPublishableKeyScopes } from "../../utils/middlewares/common/maybe-attach-pub-key-scopes" -import { validateAndTransformBody } from "@medusajs/framework" -import { validateAndTransformQuery } from "@medusajs/framework" import * as OrderQueryConfig from "../orders/query-config" import { StoreGetOrderParams } from "../orders/validators" import * as QueryConfig from "./query-config" @@ -15,6 +17,7 @@ import { StoreGetCartsCart, StoreRemoveCartPromotions, StoreUpdateCart, + StoreUpdateCartCustomer, StoreUpdateCartLineItem, } from "./validators" @@ -53,6 +56,18 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["POST"], + matcher: "/store/carts/:id/customer", + middlewares: [ + authenticate("customer", ["session", "bearer"]), + validateAndTransformBody(StoreUpdateCartCustomer), + validateAndTransformQuery( + StoreGetCartsCart, + QueryConfig.retrieveTransformQueryConfig + ), + ], + }, { method: ["POST"], matcher: "/store/carts/:id/line-items", diff --git a/packages/medusa/src/api/store/carts/validators.ts b/packages/medusa/src/api/store/carts/validators.ts index ee83af9a5a..f7ee20fc73 100644 --- a/packages/medusa/src/api/store/carts/validators.ts +++ b/packages/medusa/src/api/store/carts/validators.ts @@ -91,3 +91,8 @@ export type StoreCreateCartPaymentCollectionType = z.infer< typeof StoreCreateCartPaymentCollection > export const StoreCreateCartPaymentCollection = z.object({}).strict() + +export type StoreUpdateCartCustomerType = z.infer< + typeof StoreUpdateCartCustomer +> +export const StoreUpdateCartCustomer = z.object({}).strict()