From ca0e0631afb0dd261d372358f6ffe67f92cf7eed Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Tue, 30 Jan 2024 20:37:53 +0100 Subject: [PATCH] feat(customer): add customer group management apis (#6233) **What** ``` POST /admin/customer-groups POST /admin/customer-groups/:id GET /admin/customer-groups/:id DELETE /admin/customer-groups/:id ``` - Workflows --- .../admin/create-customer-group.ts | 65 ++++++++++++++++++ .../admin/delete-customer-group.ts | 65 ++++++++++++++++++ .../admin/list-customer-groups.spec.ts | 2 +- .../admin/retrieve-customer-group.ts | 65 ++++++++++++++++++ .../admin/update-customer-group.ts | 68 +++++++++++++++++++ .../core-flows/src/customer-group/index.ts | 2 + .../steps/create-customer-groups.ts | 33 +++++++++ .../steps/delete-customer-groups.ts | 30 ++++++++ .../src/customer-group/steps/index.ts | 3 + .../steps/update-customer-groups.ts | 58 ++++++++++++++++ .../workflows/create-customer-groups.ts | 13 ++++ .../workflows/delete-customer-groups.ts | 12 ++++ .../src/customer-group/workflows/index.ts | 3 + .../workflows/update-customer-groups.ts | 20 ++++++ packages/core-flows/src/index.ts | 1 + .../customer/src/services/customer-module.ts | 22 +++--- .../admin/customer-groups/[id]/route.ts | 63 +++++++++++++++++ .../src/api-v2/admin/customer-groups/route.ts | 26 ++++++- packages/types/src/customer/mutations.ts | 2 +- packages/types/src/customer/service.ts | 7 +- 20 files changed, 540 insertions(+), 20 deletions(-) create mode 100644 integration-tests/plugins/__tests__/customer-group/admin/create-customer-group.ts create mode 100644 integration-tests/plugins/__tests__/customer-group/admin/delete-customer-group.ts rename integration-tests/plugins/__tests__/{customer => customer-group}/admin/list-customer-groups.spec.ts (97%) create mode 100644 integration-tests/plugins/__tests__/customer-group/admin/retrieve-customer-group.ts create mode 100644 integration-tests/plugins/__tests__/customer-group/admin/update-customer-group.ts create mode 100644 packages/core-flows/src/customer-group/index.ts create mode 100644 packages/core-flows/src/customer-group/steps/create-customer-groups.ts create mode 100644 packages/core-flows/src/customer-group/steps/delete-customer-groups.ts create mode 100644 packages/core-flows/src/customer-group/steps/index.ts create mode 100644 packages/core-flows/src/customer-group/steps/update-customer-groups.ts create mode 100644 packages/core-flows/src/customer-group/workflows/create-customer-groups.ts create mode 100644 packages/core-flows/src/customer-group/workflows/delete-customer-groups.ts create mode 100644 packages/core-flows/src/customer-group/workflows/index.ts create mode 100644 packages/core-flows/src/customer-group/workflows/update-customer-groups.ts create mode 100644 packages/medusa/src/api-v2/admin/customer-groups/[id]/route.ts diff --git a/integration-tests/plugins/__tests__/customer-group/admin/create-customer-group.ts b/integration-tests/plugins/__tests__/customer-group/admin/create-customer-group.ts new file mode 100644 index 0000000000..b987f255c8 --- /dev/null +++ b/integration-tests/plugins/__tests__/customer-group/admin/create-customer-group.ts @@ -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("POST /admin/customer-groups", () => { + 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 group", async () => { + const api = useApi() as any + const response = await api.post( + `/admin/customer-groups`, + { + name: "VIP", + }, + adminHeaders + ) + + expect(response.status).toEqual(200) + expect(response.data.customer_group).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "VIP", + created_by: "admin_user", + }) + ) + }) +}) diff --git a/integration-tests/plugins/__tests__/customer-group/admin/delete-customer-group.ts b/integration-tests/plugins/__tests__/customer-group/admin/delete-customer-group.ts new file mode 100644 index 0000000000..88189e4402 --- /dev/null +++ b/integration-tests/plugins/__tests__/customer-group/admin/delete-customer-group.ts @@ -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/customer-groups/: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 group", async () => { + const group = await customerModuleService.createCustomerGroup({ + name: "VIP", + }) + + const api = useApi() as any + const response = await api.delete( + `/admin/customer-groups/${group.id}`, + adminHeaders + ) + + expect(response.status).toEqual(200) + + const deletedCustomer = await customerModuleService.retrieveCustomerGroup( + group.id, + { withDeleted: true } + ) + expect(deletedCustomer.deleted_at).toBeTruthy() + }) +}) diff --git a/integration-tests/plugins/__tests__/customer/admin/list-customer-groups.spec.ts b/integration-tests/plugins/__tests__/customer-group/admin/list-customer-groups.spec.ts similarity index 97% rename from integration-tests/plugins/__tests__/customer/admin/list-customer-groups.spec.ts rename to integration-tests/plugins/__tests__/customer-group/admin/list-customer-groups.spec.ts index 538caa7cbf..732f26da34 100644 --- a/integration-tests/plugins/__tests__/customer/admin/list-customer-groups.spec.ts +++ b/integration-tests/plugins/__tests__/customer-group/admin/list-customer-groups.spec.ts @@ -53,7 +53,7 @@ describe("GET /admin/customer-groups", () => { expect(response.status).toEqual(200) expect(response.data.count).toEqual(1) - expect(response.data.groups).toEqual([ + expect(response.data.customer_groups).toEqual([ expect.objectContaining({ id: expect.any(String), name: "Test", diff --git a/integration-tests/plugins/__tests__/customer-group/admin/retrieve-customer-group.ts b/integration-tests/plugins/__tests__/customer-group/admin/retrieve-customer-group.ts new file mode 100644 index 0000000000..f2ad1a6634 --- /dev/null +++ b/integration-tests/plugins/__tests__/customer-group/admin/retrieve-customer-group.ts @@ -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("GET /admin/customer-groups/: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 retrieve customer group", async () => { + const group = await customerModuleService.createCustomerGroup({ + name: "Test", + }) + + const api = useApi() as any + const response = await api.get( + `/admin/customer-groups/${group.id}`, + adminHeaders + ) + + expect(response.status).toEqual(200) + expect(response.data.customer_group).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "Test", + }) + ) + }) +}) diff --git a/integration-tests/plugins/__tests__/customer-group/admin/update-customer-group.ts b/integration-tests/plugins/__tests__/customer-group/admin/update-customer-group.ts new file mode 100644 index 0000000000..25d94f0b0b --- /dev/null +++ b/integration-tests/plugins/__tests__/customer-group/admin/update-customer-group.ts @@ -0,0 +1,68 @@ +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/customer-groups/: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 group", async () => { + const customer = await customerModuleService.createCustomerGroup({ + name: "VIP", + }) + + const api = useApi() as any + const response = await api.post( + `/admin/customer-groups/${customer.id}`, + { + name: "regular", + }, + adminHeaders + ) + + expect(response.status).toEqual(200) + expect(response.data.customer_group).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "regular", + }) + ) + }) +}) diff --git a/packages/core-flows/src/customer-group/index.ts b/packages/core-flows/src/customer-group/index.ts new file mode 100644 index 0000000000..e84516860c --- /dev/null +++ b/packages/core-flows/src/customer-group/index.ts @@ -0,0 +1,2 @@ +export * from "./workflows" +export * from "./steps" diff --git a/packages/core-flows/src/customer-group/steps/create-customer-groups.ts b/packages/core-flows/src/customer-group/steps/create-customer-groups.ts new file mode 100644 index 0000000000..26a8af5732 --- /dev/null +++ b/packages/core-flows/src/customer-group/steps/create-customer-groups.ts @@ -0,0 +1,33 @@ +import { CreateCustomerGroupDTO, ICustomerModuleService } from "@medusajs/types" +import { StepResponse, createStep } from "@medusajs/workflows-sdk" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" + +export const createCustomerGroupsStepId = "create-customer-groups" +export const createCustomerGroupsStep = createStep( + createCustomerGroupsStepId, + async (data: CreateCustomerGroupDTO[], { container }) => { + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + const createdCustomerGroups = await service.createCustomerGroup(data) + + return new StepResponse( + createdCustomerGroups, + createdCustomerGroups.map( + (createdCustomerGroups) => createdCustomerGroups.id + ) + ) + }, + async (createdCustomerGroupIds, { container }) => { + if (!createdCustomerGroupIds?.length) { + return + } + + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + await service.delete(createdCustomerGroupIds) + } +) diff --git a/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts b/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts new file mode 100644 index 0000000000..b2b074842c --- /dev/null +++ b/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts @@ -0,0 +1,30 @@ +import { ICustomerModuleService } from "@medusajs/types" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" + +type DeleteCustomerGroupStepInput = string[] + +export const deleteCustomerGroupStepId = "delete-customer-groups" +export const deleteCustomerGroupStep = createStep( + deleteCustomerGroupStepId, + async (ids: DeleteCustomerGroupStepInput, { container }) => { + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + await service.softDeleteCustomerGroup(ids) + + return new StepResponse(void 0, ids) + }, + async (prevCustomerGroups, { container }) => { + if (!prevCustomerGroups) { + return + } + + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + await service.restoreCustomerGroup(prevCustomerGroups) + } +) diff --git a/packages/core-flows/src/customer-group/steps/index.ts b/packages/core-flows/src/customer-group/steps/index.ts new file mode 100644 index 0000000000..2d99ae94fa --- /dev/null +++ b/packages/core-flows/src/customer-group/steps/index.ts @@ -0,0 +1,3 @@ +export * from "./update-customer-groups" +export * from "./delete-customer-groups" +export * from "./create-customer-groups" diff --git a/packages/core-flows/src/customer-group/steps/update-customer-groups.ts b/packages/core-flows/src/customer-group/steps/update-customer-groups.ts new file mode 100644 index 0000000000..553f1d5ae6 --- /dev/null +++ b/packages/core-flows/src/customer-group/steps/update-customer-groups.ts @@ -0,0 +1,58 @@ +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { + FilterableCustomerGroupProps, + ICustomerModuleService, + CustomerGroupUpdatableFields, +} from "@medusajs/types" +import { + getSelectsAndRelationsFromObjectArray, + promiseAll, +} from "@medusajs/utils" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" + +type UpdateCustomerGroupStepInput = { + selector: FilterableCustomerGroupProps + update: CustomerGroupUpdatableFields +} + +export const updateCustomerGroupStepId = "update-customer-groups" +export const updateCustomerGroupsStep = createStep( + updateCustomerGroupStepId, + async (data: UpdateCustomerGroupStepInput, { container }) => { + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + const { selects, relations } = getSelectsAndRelationsFromObjectArray([ + data.update, + ]) + const prevCustomerGroups = await service.listCustomerGroups(data.selector, { + select: selects, + relations, + }) + + const customers = await service.updateCustomerGroup( + data.selector, + data.update + ) + + return new StepResponse(customers, prevCustomerGroups) + }, + async (prevCustomerGroups, { container }) => { + if (!prevCustomerGroups) { + return + } + + const service = container.resolve( + ModuleRegistrationName.CUSTOMER + ) + + await promiseAll( + prevCustomerGroups.map((c) => + service.updateCustomerGroup(c.id, { + name: c.name, + }) + ) + ) + } +) diff --git a/packages/core-flows/src/customer-group/workflows/create-customer-groups.ts b/packages/core-flows/src/customer-group/workflows/create-customer-groups.ts new file mode 100644 index 0000000000..7ee861087e --- /dev/null +++ b/packages/core-flows/src/customer-group/workflows/create-customer-groups.ts @@ -0,0 +1,13 @@ +import { CustomerGroupDTO, CreateCustomerGroupDTO } from "@medusajs/types" +import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { createCustomerGroupsStep } from "../steps" + +type WorkflowInput = { customersData: CreateCustomerGroupDTO[] } + +export const createCustomerGroupsWorkflowId = "create-customer-groups" +export const createCustomerGroupsWorkflow = createWorkflow( + createCustomerGroupsWorkflowId, + (input: WorkflowData): WorkflowData => { + return createCustomerGroupsStep(input.customersData) + } +) diff --git a/packages/core-flows/src/customer-group/workflows/delete-customer-groups.ts b/packages/core-flows/src/customer-group/workflows/delete-customer-groups.ts new file mode 100644 index 0000000000..b2923eb7c4 --- /dev/null +++ b/packages/core-flows/src/customer-group/workflows/delete-customer-groups.ts @@ -0,0 +1,12 @@ +import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { deleteCustomerGroupStep } from "../steps" + +type WorkflowInput = { ids: string[] } + +export const deleteCustomerGroupsWorkflowId = "delete-customer-groups" +export const deleteCustomerGroupsWorkflow = createWorkflow( + deleteCustomerGroupsWorkflowId, + (input: WorkflowData): WorkflowData => { + return deleteCustomerGroupStep(input.ids) + } +) diff --git a/packages/core-flows/src/customer-group/workflows/index.ts b/packages/core-flows/src/customer-group/workflows/index.ts new file mode 100644 index 0000000000..2d99ae94fa --- /dev/null +++ b/packages/core-flows/src/customer-group/workflows/index.ts @@ -0,0 +1,3 @@ +export * from "./update-customer-groups" +export * from "./delete-customer-groups" +export * from "./create-customer-groups" diff --git a/packages/core-flows/src/customer-group/workflows/update-customer-groups.ts b/packages/core-flows/src/customer-group/workflows/update-customer-groups.ts new file mode 100644 index 0000000000..f807f644d2 --- /dev/null +++ b/packages/core-flows/src/customer-group/workflows/update-customer-groups.ts @@ -0,0 +1,20 @@ +import { + CustomerGroupDTO, + FilterableCustomerGroupProps, + CustomerGroupUpdatableFields, +} from "@medusajs/types" +import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { updateCustomerGroupsStep } from "../steps" + +type WorkflowInput = { + selector: FilterableCustomerGroupProps + update: CustomerGroupUpdatableFields +} + +export const updateCustomerGroupsWorkflowId = "update-customer-groups" +export const updateCustomerGroupsWorkflow = createWorkflow( + updateCustomerGroupsWorkflowId, + (input: WorkflowData): WorkflowData => { + return updateCustomerGroupsStep(input) + } +) diff --git a/packages/core-flows/src/index.ts b/packages/core-flows/src/index.ts index 0d26e847b6..c31f9fabe4 100644 --- a/packages/core-flows/src/index.ts +++ b/packages/core-flows/src/index.ts @@ -3,3 +3,4 @@ export * from "./definitions" export * as Handlers from "./handlers" export * from "./promotion" export * from "./customer" +export * from "./customer-group" diff --git a/packages/customer/src/services/customer-module.ts b/packages/customer/src/services/customer-module.ts index a2352f1d67..ee50bf7ee8 100644 --- a/packages/customer/src/services/customer-module.ts +++ b/packages/customer/src/services/customer-module.ts @@ -19,11 +19,7 @@ import { isString, isObject, } from "@medusajs/utils" -import { - entityNameToLinkableKeysMap, - LinkableKeys, - joinerConfig, -} from "../joiner-config" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import * as services from "../services" type InjectedDependencies = { @@ -111,24 +107,24 @@ export default class CustomerModuleService implements ICustomerModuleService { update( customerId: string, - data: CustomerUpdatableFields, + data: CustomerTypes.CustomerUpdatableFields, sharedContext?: Context ): Promise update( customerIds: string[], - data: CustomerUpdatableFields, + data: CustomerTypes.CustomerUpdatableFields, sharedContext?: Context ): Promise update( selector: CustomerTypes.FilterableCustomerProps, - data: CustomerUpdatableFields, + data: CustomerTypes.CustomerUpdatableFields, sharedContext?: Context ): Promise @InjectTransactionManager("baseRepository_") async update( idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps, - data: CustomerUpdatableFields, + data: CustomerTypes.CustomerUpdatableFields, @MedusaContext() sharedContext: Context = {} ) { let updateData: CustomerTypes.UpdateCustomerDTO[] = [] @@ -291,17 +287,17 @@ export default class CustomerModuleService implements ICustomerModuleService { async updateCustomerGroup( groupId: string, - data: Partial, + data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise async updateCustomerGroup( groupIds: string[], - data: Partial, + data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise async updateCustomerGroup( selector: CustomerTypes.FilterableCustomerGroupProps, - data: Partial, + data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise @@ -311,7 +307,7 @@ export default class CustomerModuleService implements ICustomerModuleService { | string | string[] | CustomerTypes.FilterableCustomerGroupProps, - data: Partial, + data: CustomerTypes.CustomerGroupUpdatableFields, @MedusaContext() sharedContext: Context = {} ) { let updateData: CustomerTypes.UpdateCustomerGroupDTO[] = [] diff --git a/packages/medusa/src/api-v2/admin/customer-groups/[id]/route.ts b/packages/medusa/src/api-v2/admin/customer-groups/[id]/route.ts new file mode 100644 index 0000000000..15fbe1cb34 --- /dev/null +++ b/packages/medusa/src/api-v2/admin/customer-groups/[id]/route.ts @@ -0,0 +1,63 @@ +import { + updateCustomerGroupsWorkflow, + deleteCustomerGroupsWorkflow, +} from "@medusajs/core-flows" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { + CustomerGroupUpdatableFields, + ICustomerModuleService, +} from "@medusajs/types" +import { MedusaRequest, MedusaResponse } from "../../../../types/routing" + +export const GET = async (req: MedusaRequest, res: MedusaResponse) => { + const customerModuleService = req.scope.resolve( + ModuleRegistrationName.CUSTOMER + ) + + const group = await customerModuleService.retrieveCustomerGroup( + req.params.id, + { + select: req.retrieveConfig.select, + relations: req.retrieveConfig.relations, + } + ) + + res.status(200).json({ customer_group: group }) +} + +export const POST = async (req: MedusaRequest, res: MedusaResponse) => { + const updateGroups = updateCustomerGroupsWorkflow(req.scope) + const { result, errors } = await updateGroups.run({ + input: { + selector: { id: req.params.id }, + update: req.validatedBody as CustomerGroupUpdatableFields, + }, + throwOnError: false, + }) + + if (Array.isArray(errors) && errors[0]) { + throw errors[0].error + } + + res.status(200).json({ customer_group: result[0] }) +} + +export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => { + const id = req.params.id + const deleteCustomerGroups = deleteCustomerGroupsWorkflow(req.scope) + + const { errors } = await deleteCustomerGroups.run({ + input: { ids: [id] }, + throwOnError: false, + }) + + if (Array.isArray(errors) && errors[0]) { + throw errors[0].error + } + + res.status(200).json({ + id, + object: "customer_group", + deleted: true, + }) +} diff --git a/packages/medusa/src/api-v2/admin/customer-groups/route.ts b/packages/medusa/src/api-v2/admin/customer-groups/route.ts index 03cbdd4728..eea7d452f6 100644 --- a/packages/medusa/src/api-v2/admin/customer-groups/route.ts +++ b/packages/medusa/src/api-v2/admin/customer-groups/route.ts @@ -1,5 +1,6 @@ +import { createCustomerGroupsWorkflow } from "@medusajs/core-flows" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { ICustomerModuleService } from "@medusajs/types" +import { CreateCustomerGroupDTO, ICustomerModuleService } from "@medusajs/types" import { MedusaRequest, MedusaResponse } from "../../../types/routing" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { @@ -17,8 +18,29 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => { res.json({ count, - groups, + customer_groups: groups, offset, limit, }) } + +export const POST = async (req: MedusaRequest, res: MedusaResponse) => { + const createGroups = createCustomerGroupsWorkflow(req.scope) + const customersData = [ + { + ...(req.validatedBody as CreateCustomerGroupDTO), + created_by: req.user!.id, + }, + ] + + const { result, errors } = await createGroups.run({ + input: { customersData }, + throwOnError: false, + }) + + if (Array.isArray(errors) && errors[0]) { + throw errors[0].error + } + + res.status(200).json({ customer_group: result[0] }) +} diff --git a/packages/types/src/customer/mutations.ts b/packages/types/src/customer/mutations.ts index 1e1d42334e..d84874119f 100644 --- a/packages/types/src/customer/mutations.ts +++ b/packages/types/src/customer/mutations.ts @@ -71,7 +71,7 @@ export interface CreateCustomerGroupDTO { created_by?: string } -export interface CustomerGroupUpdatableFileds { +export interface CustomerGroupUpdatableFields { name?: string metadata?: Record | null } diff --git a/packages/types/src/customer/service.ts b/packages/types/src/customer/service.ts index 56383da8a4..f6f3979744 100644 --- a/packages/types/src/customer/service.ts +++ b/packages/types/src/customer/service.ts @@ -17,6 +17,7 @@ import { CreateCustomerAddressDTO, CreateCustomerDTO, CreateCustomerGroupDTO, + CustomerGroupUpdatableFields, CustomerUpdatableFields, UpdateCustomerAddressDTO, } from "./mutations" @@ -75,17 +76,17 @@ export interface ICustomerModuleService extends IModuleService { updateCustomerGroup( groupId: string, - data: Partial, + data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise updateCustomerGroup( groupIds: string[], - data: Partial, + data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise updateCustomerGroup( selector: FilterableCustomerGroupProps, - data: Partial, + data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise