diff --git a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts index cadd6c2b9a..dbc60d896f 100644 --- a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts +++ b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts @@ -409,4 +409,81 @@ describe("Customer Module Service", () => { expect(remainingCustomers.length).toBe(0) }) }) + + describe("removeCustomerFromGroup", () => { + it("should remove a single customer from a group", async () => { + // Creating a customer and a group + const [customer] = await service.create([ + { first_name: "John", last_name: "Doe", email: "john.doe@example.com" }, + ]) + const [group] = await service.createCustomerGroup([{ name: "VIP" }]) + + // Adding the customer to the group + await service.addCustomerToGroup({ + customer_id: customer.id, + customer_group_id: group.id, + }) + + const [customerInGroup] = await service.list( + { id: customer.id }, + { relations: ["groups"] } + ) + expect(customerInGroup.groups).toEqual([ + expect.objectContaining({ id: group.id }), + ]) + + // Removing the customer from the group + await service.removeCustomerFromGroup({ + customer_id: customer.id, + customer_group_id: group.id, + }) + + const [updatedCustomer] = await service.list( + { id: customer.id }, + { relations: ["groups"] } + ) + expect(updatedCustomer.groups).toEqual([]) + }) + + it("should remove multiple customers from groups", async () => { + // Creating multiple customers and groups + const customers = await service.create([ + { first_name: "John", last_name: "Doe", email: "john.doe@example.com" }, + { + first_name: "Jane", + last_name: "Smith", + email: "jane.smith@example.com", + }, + ]) + const groups = await service.createCustomerGroup([ + { name: "VIP" }, + { name: "Regular" }, + ]) + + // Adding customers to groups + const pairsToAdd = [ + { customer_id: customers[0].id, customer_group_id: groups[0].id }, + { customer_id: customers[1].id, customer_group_id: groups[1].id }, + ] + await service.addCustomerToGroup(pairsToAdd) + + // Removing customers from groups + const pairsToRemove = [ + { customer_id: customers[0].id, customer_group_id: groups[0].id }, + { customer_id: customers[1].id, customer_group_id: groups[1].id }, + ] + await service.removeCustomerFromGroup(pairsToRemove) + + // Verification for each customer + for (const pair of pairsToRemove) { + const [updatedCustomer] = await service.list( + { id: pair.customer_id }, + { relations: ["groups"] } + ) + expect(updatedCustomer.groups).not.toContainEqual( + expect.objectContaining({ id: pair.customer_group_id }) + ) + } + }) + }) }) diff --git a/packages/customer/src/services/customer-module.ts b/packages/customer/src/services/customer-module.ts index 0a1c5dc16c..ccaad8af8e 100644 --- a/packages/customer/src/services/customer-module.ts +++ b/packages/customer/src/services/customer-module.ts @@ -124,7 +124,7 @@ export default class CustomerModuleService implements ICustomerModuleService { @MedusaContext() sharedContext: Context = {} ) { let updateData: CustomerTypes.UpdateCustomerDTO[] = [] - if (typeof idsOrSelector === "string") { + if (isString(idsOrSelector)) { updateData = [ { id: idsOrSelector, @@ -264,6 +264,73 @@ export default class CustomerModuleService implements ICustomerModuleService { return Array.isArray(dataOrArrayOfData) ? serialized : serialized[0] } + async updateCustomerGroup( + groupId: string, + data: Partial, + sharedContext?: Context + ): Promise + async updateCustomerGroup( + groupIds: string[], + data: Partial, + sharedContext?: Context + ): Promise + async updateCustomerGroup( + selector: CustomerTypes.FilterableCustomerGroupProps, + data: Partial, + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async updateCustomerGroup( + groupIdOrSelector: + | string + | string[] + | CustomerTypes.FilterableCustomerGroupProps, + data: Partial, + @MedusaContext() sharedContext: Context = {} + ) { + let updateData: CustomerTypes.UpdateCustomerGroupDTO[] = [] + if (isString(groupIdOrSelector)) { + updateData = [ + { + id: groupIdOrSelector, + ...data, + }, + ] + } else if (Array.isArray(groupIdOrSelector)) { + updateData = groupIdOrSelector.map((id) => ({ + id, + ...data, + })) + } else { + const ids = await this.customerGroupService_.list( + groupIdOrSelector, + { select: ["id"] }, + sharedContext + ) + updateData = ids.map(({ id }) => ({ + id, + ...data, + })) + } + + const groups = await this.customerGroupService_.update( + updateData, + sharedContext + ) + + if (isString(groupIdOrSelector)) { + return await this.baseRepository_.serialize( + groups[0], + { populate: true } + ) + } + + return await this.baseRepository_.serialize< + CustomerTypes.CustomerGroupDTO[] + >(groups, { populate: true }) + } + async addCustomerToGroup( groupCustomerPair: CustomerTypes.GroupCustomerPair, sharedContext?: Context @@ -291,6 +358,30 @@ export default class CustomerModuleService implements ICustomerModuleService { return { id: groupCustomers[0].id } } + async removeCustomerFromGroup( + groupCustomerPair: CustomerTypes.GroupCustomerPair, + sharedContext?: Context + ): Promise + async removeCustomerFromGroup( + groupCustomerPairs: CustomerTypes.GroupCustomerPair[], + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async removeCustomerFromGroup( + data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + const pairs = Array.isArray(data) ? data : [data] + const groupCustomers = await this.customerGroupCustomerService_.list({ + $or: pairs, + }) + await this.customerGroupCustomerService_.delete( + groupCustomers.map((gc) => gc.id), + sharedContext + ) + } + @InjectManager("baseRepository_") async listCustomerGroups( filters: CustomerTypes.FilterableCustomerGroupProps = {}, diff --git a/packages/types/src/customer/service.ts b/packages/types/src/customer/service.ts index c13608f92d..f39ef3e8ba 100644 --- a/packages/types/src/customer/service.ts +++ b/packages/types/src/customer/service.ts @@ -57,6 +57,22 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise + updateCustomerGroup( + groupId: string, + data: Partial, + sharedContext?: Context + ): Promise + updateCustomerGroup( + groupIds: string[], + data: Partial, + sharedContext?: Context + ): Promise + updateCustomerGroup( + selector: FilterableCustomerGroupProps, + data: Partial, + sharedContext?: Context + ): Promise + addCustomerToGroup( groupCustomerPair: GroupCustomerPair, sharedContext?: Context @@ -67,6 +83,15 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise<{ id: string }[]> + removeCustomerFromGroup( + groupCustomerPair: { customer_id: string; customer_group_id: string }, + sharedContext?: Context + ): Promise + removeCustomerFromGroup( + groupCustomerPairs: { customer_id: string; customer_group_id: string }[], + sharedContext?: Context + ): Promise + list( filters?: FilterableCustomerProps, config?: FindConfig,