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
2024-11-10 14:11:40 +01:00
committed by GitHub
parent 6e775a2e04
commit 1bae311a29
4 changed files with 262 additions and 33 deletions
+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 () => {
const cart = (
await api.post(
@@ -1,6 +1,6 @@
import { CustomerDTO, ICustomerModuleService } from "@medusajs/framework/types"
import { Modules, validateEmail } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
import { isDefined, Modules, validateEmail } from "@medusajs/framework/utils"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
export interface FindOrCreateCustomerStepInput {
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
* 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(
findOrCreateCustomerStepId,
async (data: FindOrCreateCustomerStepInput, { container }) => {
if (
typeof data.customerId === undefined &&
typeof data.email === undefined
) {
if (!isDefined(data.customerId) && !isDefined(data.email)) {
return new StepResponse(
{
customer: undefined,
email: undefined,
},
{ customerWasCreated: false }
{
customerWasCreated: false,
}
)
}
@@ -44,37 +44,50 @@ export const findOrCreateCustomerStep = createStep(
customer: null,
email: null,
}
let originalCustomer: CustomerDTO | null = null
let customerWasCreated = false
if (data.customerId) {
const customer = await service.retrieveCustomer(data.customerId)
customerData.customer = customer
customerData.email = customer.email
return new StepResponse(customerData, {
customerWasCreated,
})
originalCustomer = await service.retrieveCustomer(data.customerId)
customerData.customer = originalCustomer
customerData.email = originalCustomer.email
}
if (data.email) {
const validatedEmail = validateEmail(data.email)
const validatedEmail = (data.email && validateEmail(data.email)) as string
let [customer] = await service.listCustomers({
email: validatedEmail,
has_account: false,
})
let [customer] = originalCustomer
? [originalCustomer]
: 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 })
customerWasCreated = true
}
originalCustomer = customer
customerData.customer = customer
customerData.email = customer.email
}
return new StepResponse(customerData, {
customer: customerData.customer,
customer: originalCustomer,
customerWasCreated,
})
},
@@ -34,18 +34,32 @@ export const updateCartWorkflow = createWorkflow(
const cartToUpdate = useRemoteQueryStep({
entry_point: "cart",
variables: { id: input.id },
fields: ["id", "shipping_address.*", "region.*", "region.countries.*"],
fields: [
"id",
"email",
"customer_id",
"shipping_address.*",
"region.*",
"region.countries.*",
],
list: false,
throw_if_key_not_found: true,
}).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({
salesChannelId: input.sales_channel_id,
}),
findOrCreateCustomerStep({
customerId: input.customer_id,
email: input.email,
customerId: customerDataInput.customer_id,
email: customerDataInput.email,
})
)
@@ -66,7 +80,13 @@ export const updateCartWorkflow = createWorkflow(
})
const cartInput = transform(
{ input, region, customerData, salesChannel, cartToUpdate },
{
input,
region,
customer,
salesChannel,
cartToUpdate,
},
(data) => {
const {
promo_codes,
@@ -116,13 +136,16 @@ export const updateCartWorkflow = createWorkflow(
}
}
if (
isDefined(updateCartData.customer_id) ||
isDefined(updateCartData.email)
) {
data_.customer_id = data.customerData.customer?.id || null
data_.email =
data.input?.email ?? (data.customerData.customer?.email || null)
if (isDefined(updateCartData.email) && data.customer?.customer) {
const currentCustomer = data.customer.customer!
data_.customer_id = currentCustomer.id
// registered customers can update the cart email
if (currentCustomer.has_account) {
data_.email = updateCartData.email
} else {
data_.email = data.customer.email
}
}
if (isDefined(updateCartData.sales_channel_id)) {
@@ -133,6 +156,7 @@ export const updateCartWorkflow = createWorkflow(
}
)
/*
when({ cartInput }, ({ cartInput }) => {
return isDefined(cartInput.customer_id) || isDefined(cartInput.email)
}).then(() => {
@@ -141,6 +165,7 @@ export const updateCartWorkflow = createWorkflow(
data: { id: input.id },
}).config({ name: "emit-customer-updated" })
})
*/
when({ input, cartToUpdate }, ({ input, cartToUpdate }) => {
return (