Skip to content

Commit 0e1ccf4

Browse files
GBreg19Giorgi Bregvadze
andauthored
fix(medusa): allow admin draft orders without an email or customer_id (#16133)
* fix(medusa): allow admin draft orders without an email or customer_id POST /admin/draft-orders required either email or customer_id via a validator refine(), but createOrderWorkflow and the Order data model already tolerate neither being set. This blocked use cases with no captured customer identity, e.g. POS/walk-in retail orders. Raised in #15820. * fix(medusa): don't leak an unrelated customer's email on anonymous draft orders The customer-lookup fallback in POST /admin/draft-orders queried with filters: { id: undefined } when customer_id was omitted, which matched an arbitrary customer instead of none, leaking their email onto the draft order. Only run the lookup when customer_id is provided. Caught by the new test added in this PR. --------- Co-authored-by: Giorgi Bregvadze <gbreg19@duck.com>
1 parent 9fa4bd9 commit 0e1ccf4

4 files changed

Lines changed: 26 additions & 16 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@medusajs/medusa": patch
3+
---
4+
5+
fix(medusa): allow admin draft orders without an email or customer_id
6+
7+
`POST /admin/draft-orders` previously rejected requests missing both `email` and `customer_id`, even though `createOrderWorkflow` and the order data model already support neither being set. This blocked use cases with no captured customer identity (e.g. POS/walk-in orders). The admin validator no longer requires either field.
8+
9+
Also fixes a related bug the relaxed validator exposed: the route's customer-lookup fallback queried `customer` with `filters: { id: undefined }` when `customer_id` was omitted, which matched an arbitrary customer instead of none, leaking an unrelated customer's email onto the draft order. The lookup now only runs when `customer_id` is actually provided.

integration-tests/http/__tests__/draft-order/admin/draft-order.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,21 @@ medusaIntegrationTestRunner({
208208
expect(response.data.draft_order.email).toBe("test2@test.com")
209209
expect(response.data.draft_order.region_id).toBe(region.id)
210210
})
211+
212+
it("should create a draft order without an email or customer_id", async () => {
213+
const response = await api.post(
214+
"/admin/draft-orders",
215+
{
216+
region_id: region.id,
217+
},
218+
adminHeaders
219+
)
220+
221+
expect(response.status).toBe(200)
222+
expect(response.data.draft_order.email).toBeFalsy()
223+
expect(response.data.draft_order.customer_id).toBeFalsy()
224+
expect(response.data.draft_order.region_id).toBe(region.id)
225+
})
211226
})
212227

213228
describe("GET /draft-orders/:id", () => {

packages/medusa/src/api/admin/draft-orders/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const POST = async (
8787
/**
8888
* If the email is not provided, we fetch the customer and use the email from there.
8989
*/
90-
if (!workflowInput.email) {
90+
if (!workflowInput.email && input.customer_id) {
9191
const queryObject = remoteQueryObjectFromString({
9292
entryPoint: "customer",
9393
variables: {

packages/medusa/src/api/admin/draft-orders/validators.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,7 @@ const CreateDraftOrder = z
8888
})
8989
.strict()
9090

91-
export const AdminCreateDraftOrder = WithAdditionalData(
92-
CreateDraftOrder,
93-
(schema) => {
94-
return schema.refine(
95-
(data) => {
96-
if (!data.email && !data.customer_id) {
97-
return false
98-
}
99-
100-
return true
101-
},
102-
{ message: "Either email or customer_id must be provided" }
103-
)
104-
}
105-
)
91+
export const AdminCreateDraftOrder = WithAdditionalData(CreateDraftOrder)
10692

10793
export type AdminUpdateDraftOrderType = z.infer<typeof AdminUpdateDraftOrder>
10894
export const AdminUpdateDraftOrder = z.object({

0 commit comments

Comments
 (0)