fix(core-flows): conditionally create customer on order email update if unset (#14264)
* Find or create customer on order email update when order email is unset * Tests * Add changeset
This commit is contained in:
1 parent
a464e9d907
commit
8055a79c52
4 files changed
+260
-25
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(core-flows): conditionally create customer on order email update if unset
|
||||||
@@ -6,7 +6,11 @@ import {
|
|||||||
AdminStockLocation,
|
AdminStockLocation,
|
||||||
MedusaContainer,
|
MedusaContainer,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { ContainerRegistrationKeys, Modules, ProductStatus } from "@medusajs/utils"
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
Modules,
|
||||||
|
ProductStatus,
|
||||||
|
} from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
adminHeaders,
|
adminHeaders,
|
||||||
generatePublishableKey,
|
generatePublishableKey,
|
||||||
|
|||||||
@@ -165,7 +165,10 @@ medusaIntegrationTestRunner({
|
|||||||
order = seeder.order
|
order = seeder.order
|
||||||
|
|
||||||
order = (
|
order = (
|
||||||
await api.get(`/admin/orders/${order.id}?fields=+email`, adminHeaders)
|
await api.get(
|
||||||
|
`/admin/orders/${order.id}?fields=+email,+customer_id`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
).data.order
|
).data.order
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -477,6 +480,215 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
expect(orderChangesResult.length).toEqual(0)
|
expect(orderChangesResult.length).toEqual(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("conditional customer creation", () => {
|
||||||
|
it("should create or find a customer when order email is unset and input email is provided", async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
const orderService = container.resolve(ModuleRegistrationName.ORDER)
|
||||||
|
const customerService = container.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const orderWithoutEmail = await orderService.createOrders({
|
||||||
|
region_id: seeder.region.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "Test Item",
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
shipping_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
billing_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(orderWithoutEmail.email).toBeNull()
|
||||||
|
|
||||||
|
const newEmail = "newcustomer@example.com"
|
||||||
|
|
||||||
|
const customersBefore = await customerService.listCustomers()
|
||||||
|
const customerCountBefore = customersBefore.length
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/orders/${orderWithoutEmail.id}?fields=+email,+customer_id`,
|
||||||
|
{
|
||||||
|
email: newEmail,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.order.email).toBe(newEmail)
|
||||||
|
expect(response.data.order.customer_id).toBeDefined()
|
||||||
|
|
||||||
|
const customersAfter = await customerService.listCustomers()
|
||||||
|
expect(customersAfter.length).toBe(customerCountBefore + 1)
|
||||||
|
|
||||||
|
const customer = await customerService.retrieveCustomer(
|
||||||
|
response.data.order.customer_id
|
||||||
|
)
|
||||||
|
expect(customer.email).toBe(newEmail)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should NOT create or find a customer when order email is already set and input email is provided", async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
const customerService = container.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const existingEmail = order.email
|
||||||
|
|
||||||
|
expect(existingEmail).toBeDefined()
|
||||||
|
|
||||||
|
const originalCustomerId = order.customer_id
|
||||||
|
const newEmail = "updated@example.com"
|
||||||
|
|
||||||
|
const customersBefore = await customerService.listCustomers()
|
||||||
|
const customerCountBefore = customersBefore.length
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/orders/${order.id}?fields=+email,+customer_id`,
|
||||||
|
{
|
||||||
|
email: newEmail,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.order.email).toBe(newEmail)
|
||||||
|
expect(response.data.order.customer_id).toBe(originalCustomerId)
|
||||||
|
|
||||||
|
const customersAfter = await customerService.listCustomers()
|
||||||
|
expect(customersAfter.length).toBe(customerCountBefore)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should NOT create or find a customer when order email is unset and input email is not provided", async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
const orderService = container.resolve(ModuleRegistrationName.ORDER)
|
||||||
|
const customerService = container.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const orderWithoutEmail = await orderService.createOrders({
|
||||||
|
region_id: seeder.region.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
email: undefined,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "Test Item",
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
shipping_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
billing_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const customersBefore = await customerService.listCustomers()
|
||||||
|
const customerCountBefore = customersBefore.length
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/orders/${orderWithoutEmail.id}?fields=+customer_id`,
|
||||||
|
{
|
||||||
|
metadata: {
|
||||||
|
test: "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.order.customer_id).toBeNull()
|
||||||
|
|
||||||
|
const customersAfter = await customerService.listCustomers()
|
||||||
|
expect(customersAfter.length).toBe(customerCountBefore)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should find existing customer when order email is unset and input email matches existing customer", async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
const orderService = container.resolve(ModuleRegistrationName.ORDER)
|
||||||
|
const customerService = container.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const existingEmail = "existingcustomer@example.com"
|
||||||
|
|
||||||
|
const existingCustomer = await customerService.createCustomers({
|
||||||
|
email: existingEmail,
|
||||||
|
})
|
||||||
|
|
||||||
|
const orderWithoutEmail = await orderService.createOrders({
|
||||||
|
region_id: seeder.region.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: "Test Item",
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
shipping_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
billing_address: {
|
||||||
|
first_name: "Test",
|
||||||
|
last_name: "Test",
|
||||||
|
address_1: "Test",
|
||||||
|
city: "Test",
|
||||||
|
country_code: "US",
|
||||||
|
postal_code: "12345",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const customersBefore = await customerService.listCustomers()
|
||||||
|
const customerCountBefore = customersBefore.length
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/orders/${orderWithoutEmail.id}?fields=+email,+customer_id`,
|
||||||
|
{
|
||||||
|
email: existingEmail,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.order.email).toBe(existingEmail)
|
||||||
|
expect(response.data.order.customer_id).toBe(existingCustomer.id)
|
||||||
|
|
||||||
|
const customersAfter = await customerService.listCustomers()
|
||||||
|
expect(customersAfter.length).toBe(customerCountBefore)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /orders/:id/cancel", () => {
|
describe("POST /orders/:id/cancel", () => {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
updateOrdersStep,
|
updateOrdersStep,
|
||||||
} from "../steps"
|
} from "../steps"
|
||||||
import { throwIfOrderIsCancelled } from "../utils/order-validation"
|
import { throwIfOrderIsCancelled } from "../utils/order-validation"
|
||||||
|
import { findOrCreateCustomerStep } from "../../cart"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to validate the order update.
|
* The data to validate the order update.
|
||||||
@@ -151,31 +152,44 @@ export const updateOrderWorkflow = createWorkflow(
|
|||||||
|
|
||||||
updateOrderValidationStep({ order, input })
|
updateOrderValidationStep({ order, input })
|
||||||
|
|
||||||
const updateInput = transform({ input, order }, ({ input, order }) => {
|
const customerData = when({ input, order }, ({ input, order }) => {
|
||||||
const update: UpdateOrderDTO = {}
|
return !order.email && !!input.email
|
||||||
|
}).then(() => {
|
||||||
if (input.shipping_address) {
|
return findOrCreateCustomerStep({ email: input.email })
|
||||||
const address = {
|
|
||||||
// we want to create a new address
|
|
||||||
...order.shipping_address,
|
|
||||||
...input.shipping_address,
|
|
||||||
}
|
|
||||||
delete address.id
|
|
||||||
update.shipping_address = address
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.billing_address) {
|
|
||||||
const address = {
|
|
||||||
...order.billing_address,
|
|
||||||
...input.billing_address,
|
|
||||||
}
|
|
||||||
delete address.id
|
|
||||||
update.billing_address = address
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...input, ...update }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const updateInput = transform(
|
||||||
|
{ input, order, customerData },
|
||||||
|
({ input, order, customerData }) => {
|
||||||
|
const update: UpdateOrderDTO = {}
|
||||||
|
|
||||||
|
if (input.shipping_address) {
|
||||||
|
const address = {
|
||||||
|
// we want to create a new address
|
||||||
|
...order.shipping_address,
|
||||||
|
...input.shipping_address,
|
||||||
|
}
|
||||||
|
delete address.id
|
||||||
|
update.shipping_address = address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.billing_address) {
|
||||||
|
const address = {
|
||||||
|
...order.billing_address,
|
||||||
|
...input.billing_address,
|
||||||
|
}
|
||||||
|
delete address.id
|
||||||
|
update.billing_address = address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!customerData?.customer) {
|
||||||
|
update.customer_id = customerData.customer.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...input, ...update }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const updatedOrders = updateOrdersStep({
|
const updatedOrders = updateOrdersStep({
|
||||||
selector: { id: input.id },
|
selector: { id: input.id },
|
||||||
update: updateInput,
|
update: updateInput,
|
||||||
|
|||||||
Reference in new issue
Block a user