feat(customer): Introduce customer group (#6137)

**What**
Methods for:
- Bulk create customers
- Bulk and single create of customer groups
- Assigning customer <> group relationships
- listing of customers and customer groups

++ Uses new repository loading mechanism
This commit is contained in:
Sebastian Rindom
2024-01-22 12:24:22 +01:00
committed by GitHub
parent fd78f5e242
commit a52586880c
18 changed files with 632 additions and 119 deletions
@@ -23,19 +23,290 @@ describe("Customer Module Service", () => {
})
describe("create", () => {
it("should create a customer", async () => {
const customerPromise = service.create({
it("should create a single customer", async () => {
const customerData = {
company_name: "Acme Corp",
first_name: "John",
last_name: "Doe",
})
email: "john.doe@acmecorp.com",
phone: "123456789",
created_by: "admin",
metadata: { membership: "gold" },
}
const customer = await service.create(customerData)
await expect(customerPromise).resolves.toEqual(
expect(customer).toEqual(
expect.objectContaining({
id: expect.any(String),
company_name: "Acme Corp",
first_name: "John",
last_name: "Doe",
email: "john.doe@acmecorp.com",
phone: "123456789",
created_by: "admin",
metadata: expect.objectContaining({ membership: "gold" }),
})
)
})
it("should create multiple customers", async () => {
const customersData = [
{
company_name: "Acme Corp",
first_name: "John",
last_name: "Doe",
email: "john.doe@acmecorp.com",
phone: "123456789",
created_by: "admin",
metadata: { membership: "gold" },
},
{
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com",
phone: "987654321",
metadata: { membership: "silver" },
},
]
const customer = await service.create(customersData)
expect(customer).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
company_name: "Acme Corp",
first_name: "John",
last_name: "Doe",
email: "john.doe@acmecorp.com",
phone: "123456789",
created_by: "admin",
metadata: expect.objectContaining({ membership: "gold" }),
}),
expect.objectContaining({
id: expect.any(String),
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com",
phone: "987654321",
metadata: expect.objectContaining({ membership: "silver" }),
}),
])
)
})
})
describe("createCustomerGroup", () => {
it("should create a single customer group", async () => {
const group = await service.createCustomerGroup({
name: "VIP Customers",
metadata: { priority: "high" },
created_by: "admin",
})
expect(group).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "VIP Customers",
metadata: expect.objectContaining({ priority: "high" }),
created_by: "admin",
})
)
})
it("should create multiple customer groups", async () => {
const groups = await service.createCustomerGroup([
{
name: "VIP Customers",
metadata: { priority: "high" },
created_by: "admin",
},
{
name: "Regular Customers",
metadata: { discount: "10%" },
created_by: "staff",
},
])
expect(groups).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
name: "VIP Customers",
metadata: expect.objectContaining({ priority: "high" }),
created_by: "admin",
}),
expect.objectContaining({
id: expect.any(String),
name: "Regular Customers",
metadata: expect.objectContaining({ discount: "10%" }),
created_by: "staff",
}),
])
)
})
})
describe("list", () => {
it("should list all customers when no filters are applied", async () => {
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 customers = await service.list()
expect(customers.length).toBeGreaterThanOrEqual(2)
expect(customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
first_name: "John",
last_name: "Doe",
email: "john.doe@example.com",
}),
expect.objectContaining({
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com",
}),
])
)
})
it("should list customers filtered by a specific email", async () => {
await service.create([
{
first_name: "John",
last_name: "Doe",
email: "unique.email@example.com",
},
{
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com",
},
])
const filter = { email: "unique.email@example.com" }
const customers = await service.list(filter)
expect(customers.length).toBe(1)
expect(customers[0]).toEqual(
expect.objectContaining({
first_name: "John",
last_name: "Doe",
email: "unique.email@example.com",
})
)
})
it("should list customers by a specific customer group", async () => {
const vipGroup = await service.createCustomerGroup({ name: "VIP" })
const [john] = 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",
},
])
await service.addCustomerToGroup({
customer_id: john.id,
customer_group_id: vipGroup.id,
})
const filter = { groups: vipGroup.id }
const customers = await service.list(filter)
expect(customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
first_name: "John",
last_name: "Doe",
email: "john.doe@example.com",
}),
])
)
expect(customers).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
first_name: "Jane",
last_name: "Smith",
email: "jane.smith@example.com",
}),
])
)
})
})
describe("addCustomerToGroup", () => {
it("should add a single customer to a customer group", async () => {
const [customer] = await service.create([
{ first_name: "John", last_name: "Doe", email: "john.doe@example.com" },
])
const [group] = await service.createCustomerGroup([{ name: "VIP" }])
const result = await service.addCustomerToGroup({
customer_id: customer.id,
customer_group_id: group.id,
})
expect(result).toEqual(
expect.objectContaining({ id: expect.any(String) })
)
// Additional validation (optional): retrieve the customer and check if the group is assigned
const updatedCustomer = await service.retrieve(customer.id, {
relations: ["groups"],
})
expect(updatedCustomer.groups).toContainEqual(
expect.objectContaining({ id: group.id })
)
})
it("should add multiple customers to customer groups", async () => {
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" },
])
const pairs = customers.map((customer, index) => ({
customer_id: customer.id,
customer_group_id: groups[index % groups.length].id,
}))
const results = await service.addCustomerToGroup(pairs)
expect(results).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: expect.any(String) }),
expect.objectContaining({ id: expect.any(String) }),
])
)
for (const customer of customers) {
const updatedCustomer = await service.retrieve(customer.id, {
relations: ["groups"],
})
expect(updatedCustomer.groups).toContainEqual(
expect.objectContaining({
id: groups[customers.indexOf(customer) % groups.length].id,
})
)
}
})
})
})
+8 -51
View File
@@ -1,52 +1,9 @@
import * as defaultRepositories from "@repositories"
import { MikroOrmBaseRepository, ModulesSdkUtils } from "@medusajs/utils"
import * as ModuleModels from "@models"
import * as ModuleServices from "@services"
import { LoaderOptions } from "@medusajs/modules-sdk"
import { ModulesSdkTypes } from "@medusajs/types"
import { loadCustomRepositories } from "@medusajs/utils"
import * as defaultServices from "@services"
import { asClass } from "awilix"
export default async ({
container,
options,
}: LoaderOptions<
| ModulesSdkTypes.ModuleServiceInitializeOptions
| ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions
>): Promise<void> => {
const customRepositories = (
options as ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions
)?.repositories
container.register({
customerService: asClass(defaultServices.CustomerService).singleton(),
addressService: asClass(defaultServices.AddressService).singleton(),
customerGroupService: asClass(
defaultServices.CustomerGroupService
).singleton(),
})
if (customRepositories) {
loadCustomRepositories({
defaultRepositories,
customRepositories,
container,
})
} else {
loadDefaultRepositories({ container })
}
}
function loadDefaultRepositories({ container }) {
container.register({
baseRepository: asClass(defaultRepositories.BaseRepository).singleton(),
customerRepository: asClass(
defaultRepositories.CustomerRepository
).singleton(),
addressRepository: asClass(
defaultRepositories.AddressRepository
).singleton(),
customerGroupRepository: asClass(
defaultRepositories.CustomerGroupRepository
).singleton(),
})
}
export default ModulesSdkUtils.moduleContainerLoaderFactory({
moduleModels: ModuleModels,
moduleServices: ModuleServices,
moduleRepositories: { BaseRepository: MikroOrmBaseRepository },
})
@@ -12,7 +12,7 @@ import {
import Customer from "./customer"
import CustomerGroup from "./customer-group"
type OptionalGroupProps = DAL.EntityDateColumns // TODO: To be revisited when more clear
type OptionalGroupProps = "customer_group" | "customer" | DAL.EntityDateColumns // TODO: To be revisited when more clear
@Entity({ tableName: "customer_group_customer" })
export default class CustomerGroupCustomer {
@@ -21,19 +21,27 @@ export default class CustomerGroupCustomer {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text" })
customer_id: string
@Property({ columnType: "text" })
customer_group_id: string
@ManyToOne({
entity: () => Customer,
fieldName: "customer__id",
fieldName: "customer_id",
index: "IDX_customer_group_customer_customer_id",
nullable: true,
})
customer: Customer
customer: Customer | null
@ManyToOne({
entity: () => CustomerGroup,
fieldName: "customer_group_id",
index: "IDX_customer_group_customer_group_id",
nullable: true,
})
customer_group: CustomerGroup
customer_group: CustomerGroup | null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@@ -53,6 +61,9 @@ export default class CustomerGroupCustomer {
})
updated_at: Date
@Property({ columnType: "text", nullable: true })
created_by: string | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "cusgc")
@@ -34,6 +34,9 @@ export default class CustomerGroup {
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@Property({ columnType: "text", nullable: true })
created_by: string | null = null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
+1 -1
View File
@@ -71,7 +71,7 @@ export default class Customer {
metadata: Record<string, unknown> | null = null
@ManyToMany({
inversedBy: (group) => group.customers,
mappedBy: "customers",
entity: () => CustomerGroup,
pivotEntity: () => CustomerGroupCustomer,
})
@@ -1,11 +0,0 @@
import { DALUtils } from "@medusajs/utils"
import { Address } from "@models"
import { CreateAddressDTO, UpdateAddressDTO } from "@types"
export class AddressRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
Address,
{
create: CreateAddressDTO
update: UpdateAddressDTO
}
>(Address) {}
@@ -1,11 +0,0 @@
import { DALUtils } from "@medusajs/utils"
import { CustomerGroup } from "@models"
import { CreateCustomerGroupDTO, UpdateCustomerGroupDTO } from "@types"
export class CustomerGroupRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
CustomerGroup,
{
create: CreateCustomerGroupDTO
update: UpdateCustomerGroupDTO
}
>(CustomerGroup) {}
@@ -1,11 +0,0 @@
import { DALUtils } from "@medusajs/utils"
import { Customer } from "@models"
import { CreateCustomerDTO, UpdateCustomerDTO } from "@medusajs/types"
export class CustomerRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
Customer,
{
create: CreateCustomerDTO
update: UpdateCustomerDTO
}
>(Customer) {}
@@ -1,4 +0,0 @@
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
export * from "./address"
export * from "./customer"
export * from "./customer-group"
@@ -0,0 +1,25 @@
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { CustomerGroupCustomer } from "@models"
type CreateCustomerGroupCustomerDTO = {
customer_id: string
customer_group_id: string
created_by?: string
}
type InjectedDependencies = {
customerGroupRepository: DAL.RepositoryService
}
export default class CustomerGroupCustomerService<
TEntity extends CustomerGroupCustomer = CustomerGroupCustomer
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{ create: CreateCustomerGroupCustomerDTO }
>(CustomerGroupCustomer)<TEntity> {
constructor(container: InjectedDependencies) {
// @ts-ignore
super(...arguments)
}
}
@@ -1,7 +1,7 @@
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { CustomerGroup } from "@models"
import { CreateCustomerGroupDTO, UpdateCustomerGroupDTO } from "@types"
import { CreateCustomerGroupDTO, UpdateCustomerGroupDTO } from "@medusajs/types"
type InjectedDependencies = {
customerGroupRepository: DAL.RepositoryService
@@ -8,7 +8,11 @@ import {
CustomerTypes,
} from "@medusajs/types"
import { InjectManager, MedusaContext } from "@medusajs/utils"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
} from "@medusajs/utils"
import { joinerConfig } from "../joiner-config"
import * as services from "../services"
@@ -17,6 +21,7 @@ type InjectedDependencies = {
customerService: services.CustomerService
addressService: services.AddressService
customerGroupService: services.CustomerGroupService
customerGroupCustomerService: services.CustomerGroupCustomerService
}
export default class CustomerModuleService implements ICustomerModuleService {
@@ -24,6 +29,7 @@ export default class CustomerModuleService implements ICustomerModuleService {
protected customerService_: services.CustomerService
protected addressService_: services.AddressService
protected customerGroupService_: services.CustomerGroupService
protected customerGroupCustomerService_: services.CustomerGroupCustomerService
constructor(
{
@@ -31,6 +37,7 @@ export default class CustomerModuleService implements ICustomerModuleService {
customerService,
addressService,
customerGroupService,
customerGroupCustomerService,
}: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
@@ -38,6 +45,7 @@ export default class CustomerModuleService implements ICustomerModuleService {
this.customerService_ = customerService
this.addressService_ = addressService
this.customerGroupService_ = customerGroupService
this.customerGroupCustomerService_ = customerGroupCustomerService
}
__joinerConfig(): ModuleJoinerConfig {
@@ -64,18 +72,189 @@ export default class CustomerModuleService implements ICustomerModuleService {
)
}
@InjectManager("baseRepository_")
async create(
data: CustomerTypes.CreateCustomerDTO,
sharedContext?: Context
): Promise<CustomerTypes.CustomerDTO>
async create(
data: CustomerTypes.CreateCustomerDTO[],
sharedContext?: Context
): Promise<CustomerTypes.CustomerDTO[]>
@InjectTransactionManager("baseRepository_")
async create(
dataOrArray:
| CustomerTypes.CreateCustomerDTO
| CustomerTypes.CreateCustomerDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<CustomerTypes.CustomerDTO> {
const [customer] = await this.customerService_.create([data], sharedContext)
) {
const data = Array.isArray(dataOrArray) ? dataOrArray : [dataOrArray]
const customer = await this.customerService_.create(data, sharedContext)
if (Array.isArray(dataOrArray)) {
return await this.baseRepository_.serialize<CustomerTypes.CustomerDTO[]>(
customer,
{
populate: true,
}
)
}
return await this.baseRepository_.serialize<CustomerTypes.CustomerDTO>(
customer,
customer[0],
{
populate: true,
}
)
}
@InjectManager("baseRepository_")
async list(
filters: CustomerTypes.FilterableCustomerProps = {},
config: FindConfig<CustomerTypes.CustomerDTO> = {},
@MedusaContext() sharedContext: Context = {}
) {
const customers = await this.customerService_.list(
filters,
config,
sharedContext
)
return await this.baseRepository_.serialize<CustomerTypes.CustomerDTO[]>(
customers,
{
populate: true,
}
)
}
@InjectManager("baseRepository_")
async listAndCount(
filters: CustomerTypes.FilterableCustomerProps = {},
config: FindConfig<CustomerTypes.CustomerDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[CustomerTypes.CustomerDTO[], number]> {
const [customers, count] = await this.customerService_.listAndCount(
filters,
config,
sharedContext
)
return [
await this.baseRepository_.serialize<CustomerTypes.CustomerDTO[]>(
customers,
{
populate: true,
}
),
count,
]
}
async createCustomerGroup(
dataOrArrayOfData: CustomerTypes.CreateCustomerGroupDTO,
sharedContext?: Context
): Promise<CustomerTypes.CustomerGroupDTO>
async createCustomerGroup(
dataOrArrayOfData: CustomerTypes.CreateCustomerGroupDTO[],
sharedContext?: Context
): Promise<CustomerTypes.CustomerGroupDTO[]>
@InjectTransactionManager("baseRepository_")
async createCustomerGroup(
dataOrArrayOfData:
| CustomerTypes.CreateCustomerGroupDTO
| CustomerTypes.CreateCustomerGroupDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const data = Array.isArray(dataOrArrayOfData)
? dataOrArrayOfData
: [dataOrArrayOfData]
const groups = await this.customerGroupService_.create(data, sharedContext)
if (Array.isArray(dataOrArrayOfData)) {
return await this.baseRepository_.serialize<
CustomerTypes.CustomerGroupDTO[]
>(groups, {
populate: true,
})
}
return await this.baseRepository_.serialize<CustomerTypes.CustomerGroupDTO>(
groups[0],
{ populate: true }
)
}
async addCustomerToGroup(
groupCustomerPair: CustomerTypes.GroupCustomerPair,
sharedContext?: Context
): Promise<{ id: string }>
async addCustomerToGroup(
groupCustomerPairs: CustomerTypes.GroupCustomerPair[],
sharedContext?: Context
): Promise<{ id: string }[]>
@InjectTransactionManager("baseRepository_")
async addCustomerToGroup(
data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[],
@MedusaContext() sharedContext: Context = {}
): Promise<{ id: string } | { id: string }[]> {
const groupCustomers = await this.customerGroupCustomerService_.create(
Array.isArray(data) ? data : [data],
sharedContext
)
if (Array.isArray(data)) {
return groupCustomers.map((gc) => ({ id: gc.id }))
}
return { id: groupCustomers[0].id }
}
@InjectManager("baseRepository_")
async listCustomerGroups(
filters: CustomerTypes.FilterableCustomerGroupProps = {},
config: FindConfig<CustomerTypes.CustomerGroupDTO> = {},
@MedusaContext() sharedContext: Context = {}
) {
const groups = await this.customerGroupService_.list(
filters,
config,
sharedContext
)
return await this.baseRepository_.serialize<
CustomerTypes.CustomerGroupDTO[]
>(groups, {
populate: true,
})
}
@InjectManager("baseRepository_")
async listAndCountCustomerGroups(
filters: CustomerTypes.FilterableCustomerGroupProps = {},
config: FindConfig<CustomerTypes.CustomerGroupDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[CustomerTypes.CustomerGroupDTO[], number]> {
const [groups, count] = await this.customerGroupService_.listAndCount(
filters,
config,
sharedContext
)
return [
await this.baseRepository_.serialize<CustomerTypes.CustomerGroupDTO[]>(
groups,
{
populate: true,
}
),
count,
]
}
}
+1
View File
@@ -2,3 +2,4 @@ export { default as AddressService } from "./address"
export { default as CustomerGroupService } from "./customer-group"
export { default as CustomerService } from "./customer"
export { default as CustomerModuleService } from "./customer-module"
export { default as CustomerGroupCustomerService } from "./customer-group-customer"
@@ -1,11 +0,0 @@
export type CreateCustomerGroupDTO = {
name: string
customer_ids?: string[]
metadata?: Record<string, unknown> | null
}
export type UpdateCustomerGroupDTO = {
name?: string
customer_ids?: string[]
metadata?: Record<string, unknown> | null
}
-2
View File
@@ -1,7 +1,5 @@
import { Logger } from "@medusajs/types"
export * from "./address"
export * from "./customer-group"
export type InitializeModuleInjectableDependencies = {
logger?: Logger
}
+44 -1
View File
@@ -1,5 +1,43 @@
import { BaseFilterable } from "../dal"
import { OperatorMap } from "../dal/utils"
import { AddressDTO } from "../address"
export interface CustomerGroupDTO {
id: string
name: string
customers?: Partial<CustomerDTO>[]
metadata?: Record<string, unknown>
created_by?: string | null
deleted_at?: Date | string | null
created_at?: Date | string
updated_at?: Date | string
}
export interface FilterableCustomerGroupProps
extends BaseFilterable<FilterableCustomerGroupProps> {
id?: string | string[]
name?: OperatorMap<string>
customers?: FilterableCustomerProps | string | string[]
created_by?: string | string[] | null
created_at?: OperatorMap<string>
updated_at?: OperatorMap<string>
}
export interface FilterableCustomerProps
extends BaseFilterable<FilterableCustomerProps> {
id?: string | string[]
email?: string | string[] | OperatorMap<string>
groups?: FilterableCustomerGroupProps | string | string[]
default_billing_address_id?: string | string[] | null
default_shipping_address_id?: string | string[] | null
company_name?: string | string[] | OperatorMap<string> | null
first_name?: string | string[] | OperatorMap<string> | null
last_name?: string | string[] | OperatorMap<string> | null
created_by?: string | string[] | null
created_at?: OperatorMap<string>
updated_at?: OperatorMap<string>
}
export interface CustomerDTO {
id: string
email: string
@@ -14,11 +52,16 @@ export interface CustomerDTO {
phone?: string | null
groups?: { id: string }[]
metadata?: Record<string, unknown>
deleted_at?: Date | string
deleted_at?: Date | string | null
created_at?: Date | string
updated_at?: Date | string
}
export type GroupCustomerPair = {
customer_id: string
customer_group_id: string
}
export type legacy_CustomerDTO = {
id: string
email: string
+18
View File
@@ -4,6 +4,7 @@ export interface CreateCustomerDTO {
last_name?: string
email?: string
phone?: string
created_by?: string
metadata?: Record<string, unknown>
}
@@ -15,3 +16,20 @@ export interface UpdateCustomerDTO {
phone?: string
metadata?: Record<string, unknown>
}
export interface CreateCustomerGroupDTO {
name: string
metadata?: Record<string, unknown> | null
created_by?: string
}
export interface CustomerGroupUpdatableFileds {
name?: string
metadata?: Record<string, unknown> | null
}
export interface UpdateCustomerGroupDTO {
id?: string
name?: string
metadata?: Record<string, unknown> | null
}
+57 -2
View File
@@ -1,8 +1,14 @@
import { FindConfig } from "../common"
import { IModuleService } from "../modules-sdk"
import { Context } from "../shared-context"
import { CustomerDTO } from "./common"
import { CreateCustomerDTO } from "./mutations"
import {
CustomerDTO,
CustomerGroupDTO,
FilterableCustomerProps,
FilterableCustomerGroupProps,
GroupCustomerPair,
} from "./common"
import { CreateCustomerDTO, CreateCustomerGroupDTO } from "./mutations"
export interface ICustomerModuleService extends IModuleService {
retrieve(
@@ -11,5 +17,54 @@ export interface ICustomerModuleService extends IModuleService {
sharedContext?: Context
): Promise<CustomerDTO>
create(
data: CreateCustomerDTO[],
sharedContext?: Context
): Promise<CustomerDTO[]>
create(data: CreateCustomerDTO, sharedContext?: Context): Promise<CustomerDTO>
createCustomerGroup(
data: CreateCustomerGroupDTO[],
sharedContext?: Context
): Promise<CustomerGroupDTO[]>
createCustomerGroup(
data: CreateCustomerGroupDTO,
sharedContext?: Context
): Promise<CustomerGroupDTO>
addCustomerToGroup(
groupCustomerPair: GroupCustomerPair,
sharedContext?: Context
): Promise<{ id: string }>
addCustomerToGroup(
groupCustomerPairs: GroupCustomerPair[],
sharedContext?: Context
): Promise<{ id: string }[]>
list(
filters?: FilterableCustomerProps,
config?: FindConfig<CustomerDTO>,
sharedContext?: Context
): Promise<CustomerDTO[]>
listAndCount(
filters?: FilterableCustomerProps,
config?: FindConfig<CustomerDTO>,
sharedContext?: Context
): Promise<[CustomerDTO[], number]>
listCustomerGroups(
filters?: FilterableCustomerGroupProps,
config?: FindConfig<CustomerGroupDTO>,
sharedContext?: Context
): Promise<CustomerGroupDTO[]>
listAndCountCustomerGroups(
filters?: FilterableCustomerGroupProps,
config?: FindConfig<CustomerGroupDTO>,
sharedContext?: Context
): Promise<[CustomerGroupDTO[], number]>
}