diff --git a/.changeset/odd-dolls-tie.md b/.changeset/odd-dolls-tie.md new file mode 100644 index 0000000000..fb361abacd --- /dev/null +++ b/.changeset/odd-dolls-tie.md @@ -0,0 +1,6 @@ +--- +"@medusajs/core-flows": patch +"@medusajs/medusa": patch +--- + +feat(core-flows,medusa): remove cart customer validation + rename workflow diff --git a/integration-tests/http/__tests__/cart/store/cart.spec.ts b/integration-tests/http/__tests__/cart/store/cart.spec.ts index 6b5b9f6c99..7828772789 100644 --- a/integration-tests/http/__tests__/cart/store/cart.spec.ts +++ b/integration-tests/http/__tests__/cart/store/cart.spec.ts @@ -1300,55 +1300,6 @@ medusaIntegrationTestRunner({ ) }) - 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`, diff --git a/packages/core/core-flows/src/cart/workflows/index.ts b/packages/core/core-flows/src/cart/workflows/index.ts index cf0d360885..50fd22ef29 100644 --- a/packages/core/core-flows/src/cart/workflows/index.ts +++ b/packages/core/core-flows/src/cart/workflows/index.ts @@ -6,8 +6,8 @@ export * from "./create-carts" export * from "./create-payment-collection-for-cart" export * from "./list-shipping-options-for-cart" export * from "./refresh-payment-collection" +export * from "./transfer-cart-customer" 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/transfer-cart-customer.ts b/packages/core/core-flows/src/cart/workflows/transfer-cart-customer.ts new file mode 100644 index 0000000000..05ccc1e68d --- /dev/null +++ b/packages/core/core-flows/src/cart/workflows/transfer-cart-customer.ts @@ -0,0 +1,71 @@ +import { + createWorkflow, + transform, + when, + WorkflowData, +} from "@medusajs/framework/workflows-sdk" +import { useQueryGraphStep } from "../../common" +import { updateCartsStep } from "../steps" + +export const transferCartCustomerWorkflowId = "transfer-cart-customer" +/** + * This workflow transfers cart's customer. + */ +export const transferCartCustomerWorkflow = createWorkflow( + transferCartCustomerWorkflowId, + (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] + ) + + // If its the same customer, we don't want the email to be overridden, so we skip the + // update entirely. When the customer is different, we also override the email. + // The customer will have an opportunity to edit email again through update cart endpoint. + const shouldTransfer = transform( + { cart, customer }, + ({ cart, customer }) => cart.customer?.id !== customer.id + ) + + when({ shouldTransfer }, ({ shouldTransfer }) => shouldTransfer).then( + () => { + const cartInput = transform( + { cart, customer }, + ({ cart, customer }) => [ + { + id: cart.id, + customer_id: customer.id, + email: customer.email, + }, + ] + ) + + updateCartsStep(cartInput) + } + ) + } +) 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 deleted file mode 100644 index 20a6449dec..0000000000 --- a/packages/core/core-flows/src/cart/workflows/update-cart-customer.ts +++ /dev/null @@ -1,98 +0,0 @@ -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 index 2d2a6ae747..144d818903 100644 --- a/packages/medusa/src/api/store/carts/[id]/customer/route.ts +++ b/packages/medusa/src/api/store/carts/[id]/customer/route.ts @@ -1,4 +1,4 @@ -import { updateCartCustomerWorkflow } from "@medusajs/core-flows" +import { transferCartCustomerWorkflow } from "@medusajs/core-flows" import { HttpTypes } from "@medusajs/framework/types" import { @@ -11,7 +11,7 @@ export const POST = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const workflow = updateCartCustomerWorkflow(req.scope) + const workflow = transferCartCustomerWorkflow(req.scope) await workflow.run({ input: {