feat: update customer groups (#1075)
* update customer service prep * expand on the update customer groups test case * add the test case for customer group update * docs for `groups` prop on update customer endpoint * refactor, update comments * expend on integration tests, add customer mock with a group * refactor to use `customerGroupService.list` method * update units * remove `updateCustomerGroups` * fix rebase conflict * fix customer seed data, add JoinTable on groups * group retrieval using the expand param * fix: use `buildQuery_` * fix: validation for `groups`, enable `expand`param on update customer endpoint * fix: remove fileds form the `FilterableCustomerGroupProps` * fix: spearate body/query validation Co-authored-by: fPolic <frane@medusajs.com>
This commit is contained in:
@@ -62,6 +62,7 @@ Object {
|
|||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"email": "test1@email.com",
|
"email": "test1@email.com",
|
||||||
"first_name": null,
|
"first_name": null,
|
||||||
|
"groups": Array [],
|
||||||
"has_account": false,
|
"has_account": false,
|
||||||
"id": "test-customer-1",
|
"id": "test-customer-1",
|
||||||
"last_name": null,
|
"last_name": null,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ describe("/admin/customers", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.count).toEqual(4)
|
expect(response.data.count).toEqual(5)
|
||||||
expect(response.data.customers).toEqual(
|
expect(response.data.customers).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -228,6 +228,106 @@ describe("/admin/customers", () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("Correctly updates customer groups", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
let response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/customers/test-customer-3?expand=groups",
|
||||||
|
{
|
||||||
|
groups: [{ id: "test-group-4" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer.groups).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: "test-group-4", name: "test-group-4" }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// Try adding a non existing group
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/customers/test-customer-3?expand=groups",
|
||||||
|
{
|
||||||
|
groups: [{ id: "test-group-4" }, { id: "fake-group-0" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer.groups.length).toEqual(1)
|
||||||
|
expect(response.data.customer.groups).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: "test-group-4", name: "test-group-4" }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete all groups
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/customers/test-customer-3?expand=groups",
|
||||||
|
{
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer.groups.length).toEqual(0)
|
||||||
|
|
||||||
|
// Adding a group to a customer with already existing groups.
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/customers/test-customer-5?expand=groups",
|
||||||
|
{
|
||||||
|
groups: [{ id: "test-group-5" }, { id: "test-group-4" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.customer.groups.length).toEqual(2)
|
||||||
|
expect(response.data.customer.groups).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: "test-group-4", name: "test-group-4" }),
|
||||||
|
expect.objectContaining({ id: "test-group-5", name: "test-group-5" }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /admin/customers/:id", () => {
|
describe("GET /admin/customers/:id", () => {
|
||||||
@@ -278,7 +378,7 @@ describe("/admin/customers", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/customers/test-customer-1?expand=billing_address", {
|
.get("/admin/customers/test-customer-1?expand=billing_address,groups", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer test_token",
|
Authorization: "Bearer test_token",
|
||||||
},
|
},
|
||||||
@@ -295,6 +395,7 @@ describe("/admin/customers", () => {
|
|||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
|
groups: [],
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,8 +36,24 @@ module.exports = async (connection, data = {}) => {
|
|||||||
has_account: true,
|
has_account: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await manager.insert(Customer, {
|
||||||
|
id: "test-customer-5",
|
||||||
|
email: "test5@email.com",
|
||||||
|
groups: [{ id: "test-group-5", name: "test-group-5" }],
|
||||||
|
})
|
||||||
|
|
||||||
await manager.insert(CustomerGroup, {
|
await manager.insert(CustomerGroup, {
|
||||||
id: "customer-group-1",
|
id: "customer-group-1",
|
||||||
name: "vip-customers",
|
name: "vip-customers",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await manager.insert(CustomerGroup, {
|
||||||
|
id: "test-group-4",
|
||||||
|
name: "test-group-4",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.insert(CustomerGroup, {
|
||||||
|
id: "test-group-5",
|
||||||
|
name: "test-group-5",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
import { IsEmail, IsObject, IsOptional, IsString } from "class-validator"
|
import {
|
||||||
|
IsArray,
|
||||||
|
IsEmail,
|
||||||
|
IsObject,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
|
} from "class-validator"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import CustomerService from "../../../../services/customer"
|
import CustomerService from "../../../../services/customer"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
import { defaultAdminCustomersRelations } from "."
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import { FindParams } from "../../../../types/common"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [post] /customers/{id}
|
* @oas [post] /customers/{id}
|
||||||
@@ -31,6 +41,16 @@ import { validator } from "../../../../utils/validator"
|
|||||||
* password:
|
* password:
|
||||||
* type: string
|
* type: string
|
||||||
* description: The Customer's password.
|
* description: The Customer's password.
|
||||||
|
* groups:
|
||||||
|
* type: array
|
||||||
|
* description: A list of customer groups to which the customer belongs.
|
||||||
|
* items:
|
||||||
|
* required:
|
||||||
|
* - id
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* description: The id of a customer group
|
||||||
|
* type: string
|
||||||
* metadata:
|
* metadata:
|
||||||
* type: object
|
* type: object
|
||||||
* description: Metadata for the customer.
|
* description: Metadata for the customer.
|
||||||
@@ -49,27 +69,43 @@ import { validator } from "../../../../utils/validator"
|
|||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
|
|
||||||
const validated = await validator(AdminPostCustomersCustomerReq, req.body)
|
const validatedBody = await validator(AdminPostCustomersCustomerReq, req.body)
|
||||||
|
const validatedQuery = await validator(FindParams, req.query)
|
||||||
|
|
||||||
const customerService: CustomerService = req.scope.resolve("customerService")
|
const customerService: CustomerService = req.scope.resolve("customerService")
|
||||||
|
|
||||||
let customer = await customerService.retrieve(id)
|
let customer = await customerService.retrieve(id)
|
||||||
|
|
||||||
if (validated.email && customer.has_account) {
|
if (validatedBody.email && customer.has_account) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"Email cannot be changed when the user has registered their account"
|
"Email cannot be changed when the user has registered their account"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await customerService.update(id, validated)
|
await customerService.update(id, validatedBody)
|
||||||
|
|
||||||
|
let expandFields: string[] = []
|
||||||
|
if (validatedQuery.expand) {
|
||||||
|
expandFields = validatedQuery.expand.split(",")
|
||||||
|
}
|
||||||
|
|
||||||
|
const findConfig = {
|
||||||
|
relations: expandFields.length
|
||||||
|
? expandFields
|
||||||
|
: defaultAdminCustomersRelations,
|
||||||
|
}
|
||||||
|
|
||||||
|
customer = await customerService.retrieve(id, findConfig)
|
||||||
|
|
||||||
customer = await customerService.retrieve(id, {
|
|
||||||
relations: ["orders"],
|
|
||||||
})
|
|
||||||
res.status(200).json({ customer })
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Group {
|
||||||
|
@IsString()
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
export class AdminPostCustomersCustomerReq {
|
export class AdminPostCustomersCustomerReq {
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@@ -94,4 +130,10 @@ export class AdminPostCustomersCustomerReq {
|
|||||||
@IsObject()
|
@IsObject()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
metadata?: object
|
metadata?: object
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
@Type(() => Group)
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
groups?: Group[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ export class Customer {
|
|||||||
@JoinColumn({ name: "billing_address_id" })
|
@JoinColumn({ name: "billing_address_id" })
|
||||||
billing_address: Address
|
billing_address: Address
|
||||||
|
|
||||||
@OneToMany(() => Address, (address) => address.customer)
|
@OneToMany(
|
||||||
|
() => Address,
|
||||||
|
(address) => address.customer
|
||||||
|
)
|
||||||
shipping_addresses: Address[]
|
shipping_addresses: Address[]
|
||||||
|
|
||||||
@Column({ nullable: true, select: false })
|
@Column({ nullable: true, select: false })
|
||||||
@@ -55,9 +58,23 @@ export class Customer {
|
|||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
has_account: boolean
|
has_account: boolean
|
||||||
|
|
||||||
@OneToMany(() => Order, (order) => order.customer)
|
@OneToMany(
|
||||||
|
() => Order,
|
||||||
|
(order) => order.customer
|
||||||
|
)
|
||||||
orders: Order[]
|
orders: Order[]
|
||||||
|
|
||||||
|
@JoinTable({
|
||||||
|
name: "customer_group_customers",
|
||||||
|
inverseJoinColumn: {
|
||||||
|
name: "customer_group_id",
|
||||||
|
referencedColumnName: "id",
|
||||||
|
},
|
||||||
|
joinColumn: {
|
||||||
|
name: "customer_id",
|
||||||
|
referencedColumnName: "id",
|
||||||
|
},
|
||||||
|
})
|
||||||
@ManyToMany(() => CustomerGroup, { cascade: true })
|
@ManyToMany(() => CustomerGroup, { cascade: true })
|
||||||
groups: CustomerGroup[]
|
groups: CustomerGroup[]
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ const eventBusService = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customerGroupService = {
|
||||||
|
withTransaction: function() {
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
list: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
}
|
||||||
|
|
||||||
describe("CustomerService", () => {
|
describe("CustomerService", () => {
|
||||||
describe("retrieve", () => {
|
describe("retrieve", () => {
|
||||||
const customerRepository = MockRepository({
|
const customerRepository = MockRepository({
|
||||||
@@ -86,7 +93,7 @@ describe("CustomerService", () => {
|
|||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
const customerRepository = MockRepository({
|
const customerRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
if (query.where.email === "tony@stark.com") {
|
if (query.where.email === "tony@stark.com") {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
id: IdMap.getId("exists"),
|
id: IdMap.getId("exists"),
|
||||||
@@ -162,14 +169,14 @@ describe("CustomerService", () => {
|
|||||||
|
|
||||||
describe("update", () => {
|
describe("update", () => {
|
||||||
const customerRepository = MockRepository({
|
const customerRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
return Promise.resolve({ id: IdMap.getId("ironman") })
|
return Promise.resolve({ id: IdMap.getId("ironman") })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const addressRepository = MockRepository({
|
const addressRepository = MockRepository({
|
||||||
create: data => data,
|
create: (data) => data,
|
||||||
save: data => Promise.resolve(data),
|
save: (data) => Promise.resolve(data),
|
||||||
})
|
})
|
||||||
|
|
||||||
const customerService = new CustomerService({
|
const customerService = new CustomerService({
|
||||||
@@ -246,9 +253,50 @@ describe("CustomerService", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("update customer groups", () => {
|
||||||
|
const customerRepository = MockRepository({
|
||||||
|
findOne: (query) => {
|
||||||
|
return Promise.resolve({ id: IdMap.getId("ironman") })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const addressRepository = MockRepository({
|
||||||
|
create: (data) => data,
|
||||||
|
save: (data) => Promise.resolve(data),
|
||||||
|
})
|
||||||
|
|
||||||
|
const customerGroupRepository = MockRepository({
|
||||||
|
findByIds: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
})
|
||||||
|
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
manager: MockManager,
|
||||||
|
addressRepository,
|
||||||
|
customerRepository,
|
||||||
|
customerGroupRepository,
|
||||||
|
customerGroupService,
|
||||||
|
eventBusService,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls `customerGroupService.list` if `groups` prop is received as a param", async () => {
|
||||||
|
await customerService.update(IdMap.getId("ironman"), {
|
||||||
|
groups: [{ id: "group-id" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(customerGroupService.list).toBeCalledTimes(1)
|
||||||
|
expect(customerGroupService.list).toBeCalledWith({ id: ["group-id"] })
|
||||||
|
|
||||||
|
expect(customerRepository.save).toBeCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("updateAddress", () => {
|
describe("updateAddress", () => {
|
||||||
const addressRepository = MockRepository({
|
const addressRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
id: IdMap.getId("hollywood-boulevard"),
|
id: IdMap.getId("hollywood-boulevard"),
|
||||||
address_1: "Hollywood Boulevard 2",
|
address_1: "Hollywood Boulevard 2",
|
||||||
@@ -312,7 +360,7 @@ describe("CustomerService", () => {
|
|||||||
|
|
||||||
describe("removeAddress", () => {
|
describe("removeAddress", () => {
|
||||||
const addressRepository = MockRepository({
|
const addressRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
id: IdMap.getId("hollywood-boulevard"),
|
id: IdMap.getId("hollywood-boulevard"),
|
||||||
address_1: "Hollywood Boulevard 2",
|
address_1: "Hollywood Boulevard 2",
|
||||||
@@ -345,7 +393,7 @@ describe("CustomerService", () => {
|
|||||||
|
|
||||||
describe("delete", () => {
|
describe("delete", () => {
|
||||||
const customerRepository = MockRepository({
|
const customerRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
return Promise.resolve({ id: IdMap.getId("ironman") })
|
return Promise.resolve({ id: IdMap.getId("ironman") })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { BaseService } from "medusa-interfaces"
|
|||||||
import { DeepPartial, EntityManager } from "typeorm"
|
import { DeepPartial, EntityManager } from "typeorm"
|
||||||
import { CustomerGroup } from ".."
|
import { CustomerGroup } from ".."
|
||||||
import { CustomerGroupRepository } from "../repositories/customer-group"
|
import { CustomerGroupRepository } from "../repositories/customer-group"
|
||||||
|
import { FindConfig } from "../types/common"
|
||||||
|
import { FilterableCustomerGroupProps } from "../types/customer-groups"
|
||||||
|
|
||||||
type CustomerGroupConstructorProps = {
|
type CustomerGroupConstructorProps = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
@@ -64,6 +66,25 @@ class CustomerGroupService extends BaseService {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List customer groups.
|
||||||
|
*
|
||||||
|
* @param {Object} selector - the query object for find
|
||||||
|
* @param {Object} config - the config to be used for find
|
||||||
|
* @return {Promise} the result of the find operation
|
||||||
|
*/
|
||||||
|
async list(
|
||||||
|
selector: FilterableCustomerGroupProps = {},
|
||||||
|
config: FindConfig<CustomerGroup>
|
||||||
|
): Promise<CustomerGroup[]> {
|
||||||
|
const cgRepo: CustomerGroupRepository = this.manager_.getCustomRepository(
|
||||||
|
this.customerGroupRepository_
|
||||||
|
)
|
||||||
|
|
||||||
|
const query = this.buildQuery_(selector, config)
|
||||||
|
return await cgRepo.find(query)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CustomerGroupService
|
export default CustomerGroupService
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class CustomerService extends BaseService {
|
|||||||
customerRepository,
|
customerRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
addressRepository,
|
addressRepository,
|
||||||
|
customerGroupService,
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ class CustomerService extends BaseService {
|
|||||||
|
|
||||||
/** @private @const {AddressRepository} */
|
/** @private @const {AddressRepository} */
|
||||||
this.addressRepository_ = addressRepository
|
this.addressRepository_ = addressRepository
|
||||||
|
|
||||||
|
this.customerGroupService_ = customerGroupService
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager) {
|
withTransaction(transactionManager) {
|
||||||
@@ -60,7 +63,9 @@ class CustomerService extends BaseService {
|
|||||||
* @return {string} the validated email
|
* @return {string} the validated email
|
||||||
*/
|
*/
|
||||||
validateEmail_(email) {
|
validateEmail_(email) {
|
||||||
const schema = Validator.string().email().required()
|
const schema = Validator.string()
|
||||||
|
.email()
|
||||||
|
.required()
|
||||||
const { value, error } = schema.validate(email)
|
const { value, error } = schema.validate(email)
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -391,6 +396,7 @@ class CustomerService extends BaseService {
|
|||||||
metadata,
|
metadata,
|
||||||
billing_address,
|
billing_address,
|
||||||
billing_address_id,
|
billing_address_id,
|
||||||
|
groups,
|
||||||
...rest
|
...rest
|
||||||
} = update
|
} = update
|
||||||
|
|
||||||
@@ -417,6 +423,11 @@ class CustomerService extends BaseService {
|
|||||||
customer.password_hash = await this.hashPassword_(password)
|
customer.password_hash = await this.hashPassword_(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (groups) {
|
||||||
|
const id = groups.map((g) => g.id)
|
||||||
|
customer.groups = await this.customerGroupService_.list({ id })
|
||||||
|
}
|
||||||
|
|
||||||
const updated = await customerRepository.save(customer)
|
const updated = await customerRepository.save(customer)
|
||||||
|
|
||||||
await this.eventBus_
|
await this.eventBus_
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { ValidateNested } from "class-validator"
|
||||||
|
import { IsType } from "../utils/validators/is-type"
|
||||||
|
|
||||||
|
import { StringComparisonOperator } from "./common"
|
||||||
|
|
||||||
|
export class FilterableCustomerGroupProps {
|
||||||
|
@ValidateNested()
|
||||||
|
@IsType([String, [String], StringComparisonOperator])
|
||||||
|
id?: string | string[] | StringComparisonOperator
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user