feat(customer): admin CRUD endpoints (#6232)
**What** - GET /customers/:id - POST /customers/:id - DELETE /customers/:id - POST /customers Including workflows for each.
This commit is contained in:
1 parent
328eb85a8b
commit
18ff739a94
21 files changed
+503
-25
No files matched your search
@@ -0,0 +1,67 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { ICustomerModuleService } from "@medusajs/types"
|
||||||
|
import path from "path"
|
||||||
|
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
||||||
|
import { useApi } from "../../../../environment-helpers/use-api"
|
||||||
|
import { getContainer } from "../../../../environment-helpers/use-container"
|
||||||
|
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||||
|
import adminSeeder from "../../../../helpers/admin-seeder"
|
||||||
|
|
||||||
|
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||||
|
const adminHeaders = {
|
||||||
|
headers: { "x-medusa-access-token": "test_token" },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("POST /admin/customers", () => {
|
||||||
|
let dbConnection
|
||||||
|
let appContainer
|
||||||
|
let shutdownServer
|
||||||
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd, env } as any)
|
||||||
|
shutdownServer = await startBootstrapApp({ cwd, env })
|
||||||
|
appContainer = getContainer()
|
||||||
|
customerModuleService = appContainer.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
await shutdownServer()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a customer", async () => {
|
||||||
|
const api = useApi() as any
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/customers`,
|
||||||
|
{
|
||||||
|
first_name: "John",
|
||||||
|
last_name: "Doe",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
first_name: "John",
|
||||||
|
last_name: "Doe",
|
||||||
|
created_by: "admin_user",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { ICustomerModuleService } from "@medusajs/types"
|
||||||
|
import path from "path"
|
||||||
|
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
||||||
|
import { useApi } from "../../../../environment-helpers/use-api"
|
||||||
|
import { getContainer } from "../../../../environment-helpers/use-container"
|
||||||
|
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||||
|
import adminSeeder from "../../../../helpers/admin-seeder"
|
||||||
|
|
||||||
|
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||||
|
const adminHeaders = {
|
||||||
|
headers: { "x-medusa-access-token": "test_token" },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("DELETE /admin/customers/:id", () => {
|
||||||
|
let dbConnection
|
||||||
|
let appContainer
|
||||||
|
let shutdownServer
|
||||||
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd, env } as any)
|
||||||
|
shutdownServer = await startBootstrapApp({ cwd, env })
|
||||||
|
appContainer = getContainer()
|
||||||
|
customerModuleService = appContainer.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
await shutdownServer()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should delete a customer", async () => {
|
||||||
|
const customer = await customerModuleService.create({
|
||||||
|
first_name: "John",
|
||||||
|
last_name: "Doe",
|
||||||
|
})
|
||||||
|
|
||||||
|
const api = useApi() as any
|
||||||
|
const response = await api.delete(
|
||||||
|
`/admin/customers/${customer.id}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
|
const deletedCustomer = await customerModuleService.retrieve(customer.id, {
|
||||||
|
withDeleted: true,
|
||||||
|
})
|
||||||
|
expect(deletedCustomer.deleted_at).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { ICustomerModuleService } from "@medusajs/types"
|
||||||
|
import path from "path"
|
||||||
|
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
||||||
|
import { useApi } from "../../../../environment-helpers/use-api"
|
||||||
|
import { getContainer } from "../../../../environment-helpers/use-container"
|
||||||
|
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||||
|
import adminSeeder from "../../../../helpers/admin-seeder"
|
||||||
|
|
||||||
|
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||||
|
const adminHeaders = {
|
||||||
|
headers: { "x-medusa-access-token": "test_token" },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("POST /admin/customers/:id", () => {
|
||||||
|
let dbConnection
|
||||||
|
let appContainer
|
||||||
|
let shutdownServer
|
||||||
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd, env } as any)
|
||||||
|
shutdownServer = await startBootstrapApp({ cwd, env })
|
||||||
|
appContainer = getContainer()
|
||||||
|
customerModuleService = appContainer.resolve(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
await shutdownServer()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update a customer", async () => {
|
||||||
|
const customer = await customerModuleService.create({
|
||||||
|
first_name: "John",
|
||||||
|
last_name: "Doe",
|
||||||
|
})
|
||||||
|
|
||||||
|
const api = useApi() as any
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/customers/${customer.id}`,
|
||||||
|
{
|
||||||
|
first_name: "Jane",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
first_name: "Jane",
|
||||||
|
last_name: "Doe",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./steps"
|
||||||
|
export * from "./workflows"
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
import { CreateCustomerDTO, ICustomerModuleService } from "@medusajs/types"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
|
||||||
|
export const createCustomersStepId = "create-customers"
|
||||||
|
export const createCustomersStep = createStep(
|
||||||
|
createCustomersStepId,
|
||||||
|
async (data: CreateCustomerDTO[], { container }) => {
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const createdCustomers = await service.create(data)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
createdCustomers,
|
||||||
|
createdCustomers.map((createdCustomers) => createdCustomers.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdCustomerIds, { container }) => {
|
||||||
|
if (!createdCustomerIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.delete(createdCustomerIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { ICustomerModuleService } from "@medusajs/types"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
|
||||||
|
type DeleteCustomerStepInput = string[]
|
||||||
|
|
||||||
|
export const deleteCustomerStepId = "delete-customer"
|
||||||
|
export const deleteCustomerStep = createStep(
|
||||||
|
deleteCustomerStepId,
|
||||||
|
async (ids: DeleteCustomerStepInput, { container }) => {
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.softDelete(ids)
|
||||||
|
|
||||||
|
return new StepResponse(void 0, ids)
|
||||||
|
},
|
||||||
|
async (prevCustomerIds, { container }) => {
|
||||||
|
if (!prevCustomerIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.restore(prevCustomerIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./create-customers"
|
||||||
|
export * from "./update-customers"
|
||||||
|
export * from "./delete-customers"
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
FilterableCustomerProps,
|
||||||
|
ICustomerModuleService,
|
||||||
|
CustomerUpdatableFields,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
getSelectsAndRelationsFromObjectArray,
|
||||||
|
promiseAll,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
type UpdateCustomersStepInput = {
|
||||||
|
selector: FilterableCustomerProps
|
||||||
|
update: CustomerUpdatableFields
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateCustomersStepId = "update-customer"
|
||||||
|
export const updateCustomersStep = createStep(
|
||||||
|
updateCustomersStepId,
|
||||||
|
async (data: UpdateCustomersStepInput, { container }) => {
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
data.update,
|
||||||
|
])
|
||||||
|
const prevCustomers = await service.list(data.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const customers = await service.update(data.selector, data.update)
|
||||||
|
|
||||||
|
return new StepResponse(customers, prevCustomers)
|
||||||
|
},
|
||||||
|
async (prevCustomers, { container }) => {
|
||||||
|
if (!prevCustomers?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
await promiseAll(
|
||||||
|
prevCustomers.map((c) =>
|
||||||
|
service.update(c.id, {
|
||||||
|
first_name: c.first_name,
|
||||||
|
last_name: c.last_name,
|
||||||
|
email: c.email,
|
||||||
|
phone: c.phone,
|
||||||
|
metadata: c.metadata,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { CustomerDTO, CreateCustomerDTO } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { createCustomersStep } from "../steps"
|
||||||
|
|
||||||
|
type WorkflowInput = { customersData: CreateCustomerDTO[] }
|
||||||
|
|
||||||
|
export const createCustomersWorkflowId = "create-customers"
|
||||||
|
export const createCustomersWorkflow = createWorkflow(
|
||||||
|
createCustomersWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<CustomerDTO[]> => {
|
||||||
|
return createCustomersStep(input.customersData)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { deleteCustomerStep } from "../steps"
|
||||||
|
|
||||||
|
type WorkflowInput = { ids: string[] }
|
||||||
|
|
||||||
|
export const deleteCustomersWorkflowId = "delete-customers"
|
||||||
|
export const deleteCustomersWorkflow = createWorkflow(
|
||||||
|
deleteCustomersWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||||
|
return deleteCustomerStep(input.ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./create-customers"
|
||||||
|
export * from "./update-customers"
|
||||||
|
export * from "./delete-customers"
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
CustomerDTO,
|
||||||
|
CustomerUpdatableFields,
|
||||||
|
FilterableCustomerProps,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateCustomersStep } from "../steps"
|
||||||
|
|
||||||
|
type UpdateCustomersStepInput = {
|
||||||
|
selector: FilterableCustomerProps
|
||||||
|
update: CustomerUpdatableFields
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorkflowInput = UpdateCustomersStepInput
|
||||||
|
|
||||||
|
export const updateCustomersWorkflowId = "update-customers"
|
||||||
|
export const updateCustomersWorkflow = createWorkflow(
|
||||||
|
updateCustomersWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<CustomerDTO[]> => {
|
||||||
|
return updateCustomersStep(input)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -2,3 +2,4 @@ export * from "./definition"
|
|||||||
export * from "./definitions"
|
export * from "./definitions"
|
||||||
export * as Handlers from "./handlers"
|
export * as Handlers from "./handlers"
|
||||||
export * from "./promotion"
|
export * from "./promotion"
|
||||||
|
export * from "./customer"
|
||||||
@@ -6,6 +6,7 @@ export class Migration20240124154000 extends Migration {
|
|||||||
this.addSql(
|
this.addSql(
|
||||||
'create table if not exists "customer" ("id" text not null, "company_name" text null, "first_name" text null, "last_name" text null, "email" text null, "phone" text null, "has_account" boolean not null default false, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "created_by" text null, constraint "customer_pkey" primary key ("id"));'
|
'create table if not exists "customer" ("id" text not null, "company_name" text null, "first_name" text null, "last_name" text null, "email" text null, "phone" text null, "has_account" boolean not null default false, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "created_by" text null, constraint "customer_pkey" primary key ("id"));'
|
||||||
)
|
)
|
||||||
|
this.addSql('alter table "customer" alter column "email" drop not null;')
|
||||||
this.addSql(
|
this.addSql(
|
||||||
'alter table "customer" add column if not exists "company_name" text null;'
|
'alter table "customer" add column if not exists "company_name" text null;'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
CustomerTypes,
|
CustomerTypes,
|
||||||
SoftDeleteReturn,
|
SoftDeleteReturn,
|
||||||
RestoreReturn,
|
RestoreReturn,
|
||||||
|
CustomerUpdatableFields,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -110,24 +111,24 @@ export default class CustomerModuleService implements ICustomerModuleService {
|
|||||||
|
|
||||||
update(
|
update(
|
||||||
customerId: string,
|
customerId: string,
|
||||||
data: Partial<CustomerTypes.CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerTypes.CustomerDTO>
|
): Promise<CustomerTypes.CustomerDTO>
|
||||||
update(
|
update(
|
||||||
customerIds: string[],
|
customerIds: string[],
|
||||||
data: Partial<CustomerTypes.CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerTypes.CustomerDTO[]>
|
): Promise<CustomerTypes.CustomerDTO[]>
|
||||||
update(
|
update(
|
||||||
selector: CustomerTypes.FilterableCustomerProps,
|
selector: CustomerTypes.FilterableCustomerProps,
|
||||||
data: Partial<CustomerTypes.CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerTypes.CustomerDTO[]>
|
): Promise<CustomerTypes.CustomerDTO[]>
|
||||||
|
|
||||||
@InjectTransactionManager("baseRepository_")
|
@InjectTransactionManager("baseRepository_")
|
||||||
async update(
|
async update(
|
||||||
idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps,
|
idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps,
|
||||||
data: Partial<CustomerTypes.CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
) {
|
) {
|
||||||
let updateData: CustomerTypes.UpdateCustomerDTO[] = []
|
let updateData: CustomerTypes.UpdateCustomerDTO[] = []
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
updateCustomersWorkflow,
|
||||||
|
deleteCustomersWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
CustomerUpdatableFields,
|
||||||
|
ICustomerModuleService,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
|
||||||
|
|
||||||
|
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const customerModuleService = req.scope.resolve<ICustomerModuleService>(
|
||||||
|
ModuleRegistrationName.CUSTOMER
|
||||||
|
)
|
||||||
|
|
||||||
|
const customer = await customerModuleService.retrieve(req.params.id, {
|
||||||
|
select: req.retrieveConfig.select,
|
||||||
|
relations: req.retrieveConfig.relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ customer })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const updateCustomers = updateCustomersWorkflow(req.scope)
|
||||||
|
const { result, errors } = await updateCustomers.run({
|
||||||
|
input: {
|
||||||
|
selector: { id: req.params.id },
|
||||||
|
update: req.validatedBody as CustomerUpdatableFields,
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ customer: result[0] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const id = req.params.id
|
||||||
|
const deleteCustomers = deleteCustomersWorkflow(req.scope)
|
||||||
|
|
||||||
|
const { errors } = await deleteCustomers.run({
|
||||||
|
input: { ids: [id] },
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
id,
|
||||||
|
object: "customer",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,23 +1,14 @@
|
|||||||
import { MedusaV2Flag } from "@medusajs/utils"
|
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||||
|
|
||||||
import {
|
|
||||||
isFeatureFlagEnabled,
|
|
||||||
transformBody,
|
|
||||||
transformQuery,
|
|
||||||
} from "../../../api/middlewares"
|
|
||||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
import * as QueryConfig from "./query-config"
|
import * as QueryConfig from "./query-config"
|
||||||
import {
|
import {
|
||||||
AdminGetCustomersParams,
|
AdminGetCustomersParams,
|
||||||
AdminGetCustomersCustomerParams,
|
AdminGetCustomersCustomerParams,
|
||||||
|
AdminPostCustomersReq,
|
||||||
AdminPostCustomersCustomerReq,
|
AdminPostCustomersCustomerReq,
|
||||||
} from "./validators"
|
} from "./validators"
|
||||||
|
|
||||||
export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
{
|
|
||||||
matcher: "/admin/customers*",
|
|
||||||
middlewares: [isFeatureFlagEnabled(MedusaV2Flag.key)],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/customers",
|
matcher: "/admin/customers",
|
||||||
@@ -28,6 +19,11 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/customers",
|
||||||
|
middlewares: [transformBody(AdminPostCustomersReq)],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/customers/:id",
|
matcher: "/admin/customers/:id",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { createCustomersWorkflow } from "@medusajs/core-flows"
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
import { ICustomerModuleService } from "@medusajs/types"
|
import { CreateCustomerDTO, ICustomerModuleService } from "@medusajs/types"
|
||||||
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
|
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
|
||||||
|
|
||||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
@@ -39,3 +40,24 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
|||||||
limit,
|
limit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const createCustomers = createCustomersWorkflow(req.scope)
|
||||||
|
const customersData = [
|
||||||
|
{
|
||||||
|
...(req.validatedBody as CreateCustomerDTO),
|
||||||
|
created_by: req.user!.id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const { result, errors } = await createCustomers.run({
|
||||||
|
input: { customersData },
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ customer: result[0] })
|
||||||
|
}
|
||||||
@@ -121,6 +121,11 @@ export class AdminPostCustomersReq {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
email?: string
|
email?: string
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
phone?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AdminPostCustomersCustomerReq {
|
export class AdminPostCustomersCustomerReq {
|
||||||
@@ -143,4 +148,9 @@ export class AdminPostCustomersCustomerReq {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
email?: string
|
email?: string
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
phone?: string
|
||||||
}
|
}
|
||||||
@@ -48,12 +48,21 @@ export interface CreateCustomerDTO {
|
|||||||
|
|
||||||
export interface UpdateCustomerDTO {
|
export interface UpdateCustomerDTO {
|
||||||
id: string
|
id: string
|
||||||
company_name?: string
|
company_name?: string | null
|
||||||
first_name?: string
|
first_name?: string | null
|
||||||
last_name?: string
|
last_name?: string | null
|
||||||
email?: string
|
email?: string | null
|
||||||
phone?: string
|
phone?: string | null
|
||||||
metadata?: Record<string, unknown>
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomerUpdatableFields {
|
||||||
|
company_name?: string | null
|
||||||
|
first_name?: string | null
|
||||||
|
last_name?: string | null
|
||||||
|
email?: string | null
|
||||||
|
phone?: string | null
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateCustomerGroupDTO {
|
export interface CreateCustomerGroupDTO {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
CreateCustomerAddressDTO,
|
CreateCustomerAddressDTO,
|
||||||
CreateCustomerDTO,
|
CreateCustomerDTO,
|
||||||
CreateCustomerGroupDTO,
|
CreateCustomerGroupDTO,
|
||||||
|
CustomerUpdatableFields,
|
||||||
UpdateCustomerAddressDTO,
|
UpdateCustomerAddressDTO,
|
||||||
} from "./mutations"
|
} from "./mutations"
|
||||||
|
|
||||||
@@ -35,17 +36,17 @@ export interface ICustomerModuleService extends IModuleService {
|
|||||||
|
|
||||||
update(
|
update(
|
||||||
customerId: string,
|
customerId: string,
|
||||||
data: Partial<CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerDTO>
|
): Promise<CustomerDTO>
|
||||||
update(
|
update(
|
||||||
customerIds: string[],
|
customerIds: string[],
|
||||||
data: Partial<CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerDTO[]>
|
): Promise<CustomerDTO[]>
|
||||||
update(
|
update(
|
||||||
selector: FilterableCustomerProps,
|
selector: FilterableCustomerProps,
|
||||||
data: Partial<CreateCustomerDTO>,
|
data: CustomerUpdatableFields,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<CustomerDTO[]>
|
): Promise<CustomerDTO[]>
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user