fix(core-flows): keep same customer on cart update (#9977)

* fix(core-flows): keep same customer on cart update

* update guest customer email

* create guest customer for new emails

* rm log
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2024-11-10 14:11:40 +01:00
1 parent 6e775a2e04
commit 1bae311a29
4 files changed
+262 -33

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/core-flows": patch
---
Keep customer when updating cart
@@ -1882,6 +1882,192 @@ medusaIntegrationTestRunner({
}) })
}) })
it("should create another guest customer and update the cart email when an different email is provided", async () => {
const cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
email: "tony@stark-industries.com",
shipping_address: {
address_1: "test address 1",
address_2: "test address 2",
city: "ny",
country_code: "us",
province: "ny",
postal_code: "94016",
},
sales_channel_id: salesChannel.id,
},
storeHeaders
)
).data.cart
const originalCartCustomer = cart.customer
// update the cart without providing an email
await api.post(
`/store/carts/${cart.id}`,
{
metadata: {
test: "test updated",
},
},
storeHeaders
)
let currentCart = await api.get(
`/store/carts/${cart.id}`,
storeHeaders
)
let currentCartCustomer = currentCart.data.cart.customer
let customerData = (
await api.get(
`/admin/customers/${currentCart.data.cart.customer_id}`,
adminHeaders
)
).data.customer
expect(currentCartCustomer).toEqual(originalCartCustomer)
expect(customerData.email).toEqual(currentCart.data.cart.email)
expect(currentCart.data.cart.email).toEqual(
"tony@stark-industries.com"
)
expect(currentCart.data.cart.metadata).toEqual({
test: "test updated",
})
// update the cart providing an email
await api.post(
`/store/carts/${cart.id}`,
{
email: "foo@bar.com",
metadata: {
test: "test updated 2, new customer",
},
},
storeHeaders
)
currentCart = await api.get(`/store/carts/${cart.id}`, storeHeaders)
customerData = (
await api.get(
`/admin/customers/${currentCart.data.cart.customer_id}`,
adminHeaders
)
).data.customer
currentCartCustomer = currentCart.data.cart.customer
expect(currentCartCustomer).not.toEqual(originalCartCustomer)
expect(currentCart.data.cart.customer_id).not.toEqual(
originalCartCustomer.id
)
expect(customerData.email).toEqual(currentCart.data.cart.email)
expect(currentCart.data.cart.email).toEqual("foo@bar.com")
expect(currentCart.data.cart.metadata).toEqual({
test: "test updated 2, new customer",
})
})
it("should keep the same customer when updating the customer cart and update Cart's email if provided", async () => {
// create a customer
const mainEmail = "jhon.doe@acme.com"
await customerModule.createCustomers({
email: mainEmail,
has_account: true,
})
const cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
email: mainEmail,
shipping_address: {
address_1: "test address 1",
address_2: "test address 2",
city: "ny",
country_code: "us",
province: "ny",
postal_code: "94016",
},
sales_channel_id: salesChannel.id,
},
storeHeaders
)
).data.cart
const originalCartCustomer = cart.customer
// update the cart without providing an email
await api.post(
`/store/carts/${cart.id}`,
{
metadata: {
test: "test updated",
},
},
storeHeaders
)
let currentCart = await api.get(
`/store/carts/${cart.id}`,
storeHeaders
)
let currentCartCustomer = currentCart.data.cart.customer
let customerData = (
await api.get(
`/admin/customers/${currentCart.data.cart.customer_id}`,
adminHeaders
)
).data.customer
expect(currentCartCustomer).toEqual(originalCartCustomer)
expect(customerData.email).toEqual(currentCart.data.cart.email)
expect(currentCart.data.cart.email).toEqual(mainEmail)
expect(currentCart.data.cart.metadata).toEqual({
test: "test updated",
})
// update the cart providing an email
await api.post(
`/store/carts/${cart.id}`,
{
email: "foo@bar.com",
metadata: {
test: "test updated 2, new customer",
},
},
storeHeaders
)
currentCart = await api.get(`/store/carts/${cart.id}`, storeHeaders)
customerData = (
await api.get(
`/admin/customers/${currentCart.data.cart.customer_id}`,
adminHeaders
)
).data.customer
currentCartCustomer = currentCart.data.cart.customer
expect(currentCartCustomer).toEqual(originalCartCustomer)
expect(currentCart.data.cart.customer_id).toEqual(
originalCartCustomer.id
)
expect(customerData.email).not.toEqual(currentCart.data.cart.email)
expect(customerData.email).toEqual(mainEmail)
expect(currentCart.data.cart.email).toEqual("foo@bar.com")
expect(currentCart.data.cart.metadata).toEqual({
test: "test updated 2, new customer",
})
})
it("should return order when cart is already completed", async () => { it("should return order when cart is already completed", async () => {
const cart = ( const cart = (
await api.post( await api.post(
@@ -1,6 +1,6 @@
import { CustomerDTO, ICustomerModuleService } from "@medusajs/framework/types" import { CustomerDTO, ICustomerModuleService } from "@medusajs/framework/types"
import { Modules, validateEmail } from "@medusajs/framework/utils" import { isDefined, Modules, validateEmail } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk" import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
export interface FindOrCreateCustomerStepInput { export interface FindOrCreateCustomerStepInput {
customerId?: string | null customerId?: string | null
@@ -21,20 +21,20 @@ export const findOrCreateCustomerStepId = "find-or-create-customer"
/** /**
* This step either finds a customer matching the specified ID, or finds / create a customer * This step either finds a customer matching the specified ID, or finds / create a customer
* matching the specified email. If both ID and email are provided, ID takes precedence. * matching the specified email. If both ID and email are provided, ID takes precedence.
* If the customer is a guest, the email is updated to the provided email.
*/ */
export const findOrCreateCustomerStep = createStep( export const findOrCreateCustomerStep = createStep(
findOrCreateCustomerStepId, findOrCreateCustomerStepId,
async (data: FindOrCreateCustomerStepInput, { container }) => { async (data: FindOrCreateCustomerStepInput, { container }) => {
if ( if (!isDefined(data.customerId) && !isDefined(data.email)) {
typeof data.customerId === undefined &&
typeof data.email === undefined
) {
return new StepResponse( return new StepResponse(
{ {
customer: undefined, customer: undefined,
email: undefined, email: undefined,
}, },
{ customerWasCreated: false } {
customerWasCreated: false,
}
) )
} }
@@ -44,37 +44,50 @@ export const findOrCreateCustomerStep = createStep(
customer: null, customer: null,
email: null, email: null,
} }
let originalCustomer: CustomerDTO | null = null
let customerWasCreated = false let customerWasCreated = false
if (data.customerId) { if (data.customerId) {
const customer = await service.retrieveCustomer(data.customerId) originalCustomer = await service.retrieveCustomer(data.customerId)
customerData.customer = customer customerData.customer = originalCustomer
customerData.email = customer.email customerData.email = originalCustomer.email
return new StepResponse(customerData, {
customerWasCreated,
})
} }
if (data.email) { if (data.email) {
const validatedEmail = validateEmail(data.email) const validatedEmail = (data.email && validateEmail(data.email)) as string
let [customer] = await service.listCustomers({ let [customer] = originalCustomer
email: validatedEmail, ? [originalCustomer]
has_account: false, : await service.listCustomers({
}) email: validatedEmail,
})
if (!customer) { // if NOT a guest customer, return it
if (customer?.has_account) {
customerData.customer = customer
customerData.email = customer.email
return new StepResponse(customerData, {
customerWasCreated,
})
}
if (
!customer ||
(isDefined(data.email) && customer.email !== validatedEmail)
) {
customer = await service.createCustomers({ email: validatedEmail }) customer = await service.createCustomers({ email: validatedEmail })
customerWasCreated = true customerWasCreated = true
} }
originalCustomer = customer
customerData.customer = customer customerData.customer = customer
customerData.email = customer.email customerData.email = customer.email
} }
return new StepResponse(customerData, { return new StepResponse(customerData, {
customer: customerData.customer, customer: originalCustomer,
customerWasCreated, customerWasCreated,
}) })
}, },
@@ -34,18 +34,32 @@ export const updateCartWorkflow = createWorkflow(
const cartToUpdate = useRemoteQueryStep({ const cartToUpdate = useRemoteQueryStep({
entry_point: "cart", entry_point: "cart",
variables: { id: input.id }, variables: { id: input.id },
fields: ["id", "shipping_address.*", "region.*", "region.countries.*"], fields: [
"id",
"email",
"customer_id",
"shipping_address.*",
"region.*",
"region.countries.*",
],
list: false, list: false,
throw_if_key_not_found: true, throw_if_key_not_found: true,
}).config({ name: "get-cart" }) }).config({ name: "get-cart" })
const [salesChannel, customerData] = parallelize( const customerDataInput = transform({ input, cartToUpdate }, (data) => {
return {
customer_id: data.cartToUpdate.customer_id,
email: data.input.email ?? data.cartToUpdate.email,
}
})
const [salesChannel, customer] = parallelize(
findSalesChannelStep({ findSalesChannelStep({
salesChannelId: input.sales_channel_id, salesChannelId: input.sales_channel_id,
}), }),
findOrCreateCustomerStep({ findOrCreateCustomerStep({
customerId: input.customer_id, customerId: customerDataInput.customer_id,
email: input.email, email: customerDataInput.email,
}) })
) )
@@ -66,7 +80,13 @@ export const updateCartWorkflow = createWorkflow(
}) })
const cartInput = transform( const cartInput = transform(
{ input, region, customerData, salesChannel, cartToUpdate }, {
input,
region,
customer,
salesChannel,
cartToUpdate,
},
(data) => { (data) => {
const { const {
promo_codes, promo_codes,
@@ -116,13 +136,16 @@ export const updateCartWorkflow = createWorkflow(
} }
} }
if ( if (isDefined(updateCartData.email) && data.customer?.customer) {
isDefined(updateCartData.customer_id) || const currentCustomer = data.customer.customer!
isDefined(updateCartData.email) data_.customer_id = currentCustomer.id
) {
data_.customer_id = data.customerData.customer?.id || null // registered customers can update the cart email
data_.email = if (currentCustomer.has_account) {
data.input?.email ?? (data.customerData.customer?.email || null) data_.email = updateCartData.email
} else {
data_.email = data.customer.email
}
} }
if (isDefined(updateCartData.sales_channel_id)) { if (isDefined(updateCartData.sales_channel_id)) {
@@ -133,6 +156,7 @@ export const updateCartWorkflow = createWorkflow(
} }
) )
/*
when({ cartInput }, ({ cartInput }) => { when({ cartInput }, ({ cartInput }) => {
return isDefined(cartInput.customer_id) || isDefined(cartInput.email) return isDefined(cartInput.customer_id) || isDefined(cartInput.email)
}).then(() => { }).then(() => {
@@ -141,6 +165,7 @@ export const updateCartWorkflow = createWorkflow(
data: { id: input.id }, data: { id: input.id },
}).config({ name: "emit-customer-updated" }) }).config({ name: "emit-customer-updated" })
}) })
*/
when({ input, cartToUpdate }, ({ input, cartToUpdate }) => { when({ input, cartToUpdate }, ({ input, cartToUpdate }) => {
return ( return (