feat(medusa): Allow to filter collections by discount condition id (#2411)
This commit is contained in:
1 parent
308b99cc5d
commit
c717442451
11 files changed
+210
-51
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa): Allow to filter collections by discount condition id
|
||||||
@@ -5,8 +5,23 @@ const { initDb, useDb } = require("../../../helpers/use-db")
|
|||||||
|
|
||||||
const productSeeder = require("../../helpers/product-seeder")
|
const productSeeder = require("../../helpers/product-seeder")
|
||||||
const adminSeeder = require("../../helpers/admin-seeder")
|
const adminSeeder = require("../../helpers/admin-seeder")
|
||||||
|
const {
|
||||||
|
DiscountRuleType,
|
||||||
|
AllocationType,
|
||||||
|
DiscountConditionType,
|
||||||
|
DiscountConditionOperator,
|
||||||
|
} = require("@medusajs/medusa")
|
||||||
|
const { IdMap } = require("medusa-test-utils")
|
||||||
|
const { simpleDiscountFactory } = require("../../factories")
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
const adminReqConfig = {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
describe("/admin/collections", () => {
|
describe("/admin/collections", () => {
|
||||||
let medusaProcess
|
let medusaProcess
|
||||||
let dbConnection
|
let dbConnection
|
||||||
@@ -334,5 +349,82 @@ describe("/admin/collections", () => {
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns a list of collections filtered by discount condition id", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const resCollections = await api.get("/admin/collections", adminReqConfig)
|
||||||
|
|
||||||
|
const collection1 = resCollections.data.collections[0]
|
||||||
|
const collection2 = resCollections.data.collections[1]
|
||||||
|
|
||||||
|
const buildDiscountData = (code, conditionId, collections) => {
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
rule: {
|
||||||
|
type: DiscountRuleType.PERCENTAGE,
|
||||||
|
value: 10,
|
||||||
|
allocation: AllocationType.TOTAL,
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
id: conditionId,
|
||||||
|
type: DiscountConditionType.PRODUCT_COLLECTIONS,
|
||||||
|
operator: DiscountConditionOperator.IN,
|
||||||
|
product_collections: collections,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const discountConditionId = IdMap.getId("discount-condition-type-1")
|
||||||
|
await simpleDiscountFactory(
|
||||||
|
dbConnection,
|
||||||
|
buildDiscountData("code-1", discountConditionId, [collection1.id])
|
||||||
|
)
|
||||||
|
|
||||||
|
const discountConditionId2 = IdMap.getId("discount-condition-type-2")
|
||||||
|
await simpleDiscountFactory(
|
||||||
|
dbConnection,
|
||||||
|
buildDiscountData("code-2", discountConditionId2, [collection2.id])
|
||||||
|
)
|
||||||
|
|
||||||
|
let res = await api.get(
|
||||||
|
`/admin/collections?discount_condition_id=${discountConditionId}`,
|
||||||
|
adminReqConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.collections).toHaveLength(1)
|
||||||
|
expect(res.data.collections).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: collection1.id }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await api.get(
|
||||||
|
`/admin/collections?discount_condition_id=${discountConditionId2}`,
|
||||||
|
adminReqConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.collections).toHaveLength(1)
|
||||||
|
expect(res.data.collections).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: collection2.id }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
res = await api.get(`/admin/collections`, adminReqConfig)
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.collections).toHaveLength(3)
|
||||||
|
expect(res.data.collections).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({ id: collection1.id }),
|
||||||
|
expect.objectContaining({ id: collection2.id }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -6,10 +6,10 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"handle": "test-collection",
|
"handle": "test-collection2",
|
||||||
"id": "test-collection",
|
"id": "test-collection2",
|
||||||
"metadata": null,
|
"metadata": null,
|
||||||
"title": "Test collection",
|
"title": "Test collection 2",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@@ -24,10 +24,10 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"handle": "test-collection2",
|
"handle": "test-collection",
|
||||||
"id": "test-collection2",
|
"id": "test-collection",
|
||||||
"metadata": null,
|
"metadata": null,
|
||||||
"title": "Test collection 2",
|
"title": "Test collection",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe("/store/collections", () => {
|
|||||||
expect(response.data).toMatchSnapshot({
|
expect(response.data).toMatchSnapshot({
|
||||||
collections: [
|
collections: [
|
||||||
{
|
{
|
||||||
id: "test-collection",
|
id: "test-collection2",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
@@ -76,7 +76,7 @@ describe("/store/collections", () => {
|
|||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "test-collection2",
|
id: "test-collection",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IsNumber, IsOptional, IsString, ValidateNested } from "class-validator"
|
import { IsNumber, IsOptional, IsString, ValidateNested } from "class-validator"
|
||||||
import { Request, Response } from "express"
|
import { Request, Response } from "express"
|
||||||
import _, { identity } from "lodash"
|
|
||||||
|
|
||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
import ProductCollectionService from "../../../../services/product-collection"
|
import ProductCollectionService from "../../../../services/product-collection"
|
||||||
@@ -18,6 +17,7 @@ import { Type } from "class-transformer"
|
|||||||
* - (query) title {string} The title of collections to return.
|
* - (query) title {string} The title of collections to return.
|
||||||
* - (query) handle {string} The handle of collections to return.
|
* - (query) handle {string} The handle of collections to return.
|
||||||
* - (query) q {string} a search term to search titles and handles.
|
* - (query) q {string} a search term to search titles and handles.
|
||||||
|
* - (query) discount_condition_id {string} The discount condition id on which to filter the product collections.
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: created_at
|
* name: created_at
|
||||||
* description: Date comparison for when resulting collections were created.
|
* description: Date comparison for when resulting collections were created.
|
||||||
@@ -143,22 +143,19 @@ export default async (req: Request, res: Response) => {
|
|||||||
"productCollectionService"
|
"productCollectionService"
|
||||||
)
|
)
|
||||||
|
|
||||||
const {
|
const { filterableFields, listConfig } = req
|
||||||
validatedQuery: { limit, offset },
|
const { skip, take } = listConfig
|
||||||
filterableFields,
|
|
||||||
listConfig,
|
|
||||||
} = req
|
|
||||||
|
|
||||||
const [collections, count] = await productCollectionService.listAndCount(
|
const [collections, count] = await productCollectionService.listAndCount(
|
||||||
_.pickBy(filterableFields, identity),
|
filterableFields,
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
collections,
|
collections,
|
||||||
count,
|
count,
|
||||||
offset,
|
offset: skip,
|
||||||
limit,
|
limit: take,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,4 +199,8 @@ export class AdminGetCollectionsParams extends AdminGetCollectionsPaginationPara
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
q?: string
|
q?: string
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
discount_condition_id?: string
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@ import {
|
|||||||
StringComparisonOperator,
|
StringComparisonOperator,
|
||||||
} from "../../../../types/common"
|
} from "../../../../types/common"
|
||||||
import { IsNumber, IsOptional, IsString } from "class-validator"
|
import { IsNumber, IsOptional, IsString } from "class-validator"
|
||||||
import { identity, pickBy } from "lodash"
|
|
||||||
|
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import ProductTypeService from "../../../../services/product-type"
|
import ProductTypeService from "../../../../services/product-type"
|
||||||
@@ -143,7 +142,7 @@ export default async (req, res) => {
|
|||||||
const { skip, take } = req.listConfig
|
const { skip, take } = req.listConfig
|
||||||
|
|
||||||
const [types, count] = await typeService.listAndCount(
|
const [types, count] = await typeService.listAndCount(
|
||||||
pickBy(filterableFields, identity),
|
filterableFields,
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ describe("GET /store/collections", () => {
|
|||||||
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
|
order: {
|
||||||
|
created_at: "DESC",
|
||||||
|
},
|
||||||
|
relations: [],
|
||||||
|
select: undefined,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 5,
|
take: 5,
|
||||||
}
|
}
|
||||||
@@ -60,6 +65,11 @@ describe("GET /store/collections", () => {
|
|||||||
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
|
order: {
|
||||||
|
created_at: "DESC",
|
||||||
|
},
|
||||||
|
relations: [],
|
||||||
|
select: undefined,
|
||||||
skip: 10,
|
skip: 10,
|
||||||
take: 10,
|
take: 10,
|
||||||
}
|
}
|
||||||
@@ -84,6 +94,11 @@ describe("GET /store/collections", () => {
|
|||||||
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
|
order: {
|
||||||
|
created_at: "DESC",
|
||||||
|
},
|
||||||
|
relations: [],
|
||||||
|
select: undefined,
|
||||||
skip: 10,
|
skip: 10,
|
||||||
take: 20,
|
take: 20,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { PaginatedResponse } from "./../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import { ProductCollection } from "../../../../"
|
import { ProductCollection } from "../../../../"
|
||||||
import middlewares from "../../../middlewares"
|
import middlewares, { transformQuery } from "../../../middlewares"
|
||||||
|
import { StoreGetCollectionsParams } from "./list-collections"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
|
|
||||||
export default (app) => {
|
export default (app) => {
|
||||||
app.use("/collections", route)
|
app.use("/collections", route)
|
||||||
|
|
||||||
route.get("/", middlewares.wrap(require("./list-collections").default))
|
route.get(
|
||||||
|
"/",
|
||||||
|
transformQuery(StoreGetCollectionsParams, {
|
||||||
|
allowedFields,
|
||||||
|
isList: true,
|
||||||
|
}),
|
||||||
|
middlewares.wrap(require("./list-collections").default)
|
||||||
|
)
|
||||||
route.get("/:id", middlewares.wrap(require("./get-collection").default))
|
route.get("/:id", middlewares.wrap(require("./get-collection").default))
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultStoreCollectionFields = ["id", "title", "handle"]
|
|
||||||
export const defaultStoreCollectionRelations = ["products"]
|
export const defaultStoreCollectionRelations = ["products"]
|
||||||
|
export const allowedFields = [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"handle",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
...defaultStoreCollectionRelations,
|
||||||
|
]
|
||||||
|
|
||||||
export type StoreCollectionsListRes = PaginatedResponse & {
|
export type StoreCollectionsListRes = PaginatedResponse & {
|
||||||
collections: ProductCollection[]
|
collections: ProductCollection[]
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { IsInt, IsOptional, ValidateNested } from "class-validator"
|
|||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
import ProductCollectionService from "../../../../services/product-collection"
|
import ProductCollectionService from "../../../../services/product-collection"
|
||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
import { validator } from "../../../../utils/validator"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /collections
|
* @oas [get] /collections
|
||||||
@@ -105,24 +104,19 @@ import { validator } from "../../../../utils/validator"
|
|||||||
* $ref: "#/components/responses/500_error"
|
* $ref: "#/components/responses/500_error"
|
||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const validated = await validator(StoreGetCollectionsParams, req.query)
|
|
||||||
const { limit, offset, ...filterableFields } = validated
|
|
||||||
|
|
||||||
const productCollectionService: ProductCollectionService = req.scope.resolve(
|
const productCollectionService: ProductCollectionService = req.scope.resolve(
|
||||||
"productCollectionService"
|
"productCollectionService"
|
||||||
)
|
)
|
||||||
|
|
||||||
const listConfig = {
|
const { listConfig, filterableFields } = req
|
||||||
skip: offset,
|
const { skip, take } = req.listConfig
|
||||||
take: limit,
|
|
||||||
}
|
|
||||||
|
|
||||||
const [collections, count] = await productCollectionService.listAndCount(
|
const [collections, count] = await productCollectionService.listAndCount(
|
||||||
filterableFields,
|
filterableFields,
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
res.status(200).json({ collections, count, limit, offset })
|
res.status(200).json({ collections, count, limit: take, offset: skip })
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StoreGetCollectionsParams {
|
export class StoreGetCollectionsParams {
|
||||||
|
|||||||
@@ -1,6 +1,36 @@
|
|||||||
import { EntityRepository, Repository } from "typeorm"
|
import { EntityRepository, Repository } from "typeorm"
|
||||||
import { ProductCollection } from "../models/product-collection"
|
import { ProductCollection } from "../models"
|
||||||
|
import { ExtendedFindConfig } from "../types/common"
|
||||||
|
|
||||||
@EntityRepository(ProductCollection)
|
@EntityRepository(ProductCollection)
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
export class ProductCollectionRepository extends Repository<ProductCollection> {}
|
export class ProductCollectionRepository extends Repository<ProductCollection> {
|
||||||
|
async findAndCountByDiscountConditionId(
|
||||||
|
conditionId: string,
|
||||||
|
query: ExtendedFindConfig<ProductCollection, Partial<ProductCollection>>
|
||||||
|
): Promise<[ProductCollection[], number]> {
|
||||||
|
const qb = this.createQueryBuilder("pc")
|
||||||
|
|
||||||
|
if (query?.select) {
|
||||||
|
qb.select(query.select.map((select) => `pc.${select}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.skip) {
|
||||||
|
qb.skip(query.skip)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.take) {
|
||||||
|
qb.take(query.take)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await qb
|
||||||
|
.where(query.where)
|
||||||
|
.innerJoin(
|
||||||
|
"discount_condition_product_collection",
|
||||||
|
"dc_pc",
|
||||||
|
`dc_pc.product_collection_id = pc.id AND dc_pc.condition_id = :dcId`,
|
||||||
|
{ dcId: conditionId }
|
||||||
|
)
|
||||||
|
.getManyAndCount()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,12 @@ import { TransactionBaseService } from "../interfaces"
|
|||||||
import { ProductCollection } from "../models"
|
import { ProductCollection } from "../models"
|
||||||
import { ProductRepository } from "../repositories/product"
|
import { ProductRepository } from "../repositories/product"
|
||||||
import { ProductCollectionRepository } from "../repositories/product-collection"
|
import { ProductCollectionRepository } from "../repositories/product-collection"
|
||||||
import { ExtendedFindConfig, FindConfig, QuerySelector } from "../types/common"
|
import { FindConfig } from "../types/common"
|
||||||
import {
|
import {
|
||||||
CreateProductCollection,
|
CreateProductCollection,
|
||||||
UpdateProductCollection,
|
UpdateProductCollection,
|
||||||
} from "../types/product-collection"
|
} from "../types/product-collection"
|
||||||
import { buildQuery, setMetadata } from "../utils"
|
import { buildQuery, isString, setMetadata } from "../utils"
|
||||||
import { formatException } from "../utils/exception-formatter"
|
import { formatException } from "../utils/exception-formatter"
|
||||||
import EventBusService from "./event-bus"
|
import EventBusService from "./event-bus"
|
||||||
|
|
||||||
@@ -219,15 +219,14 @@ class ProductCollectionService extends TransactionBaseService {
|
|||||||
* @return the result of the find operation
|
* @return the result of the find operation
|
||||||
*/
|
*/
|
||||||
async list(
|
async list(
|
||||||
selector = {},
|
selector: Partial<ProductCollection> & {
|
||||||
|
q?: string
|
||||||
|
discount_condition_id?: string
|
||||||
|
} = {},
|
||||||
config = { skip: 0, take: 20 }
|
config = { skip: 0, take: 20 }
|
||||||
): Promise<ProductCollection[]> {
|
): Promise<ProductCollection[]> {
|
||||||
const productCollectionRepo = this.manager_.getCustomRepository(
|
const [collections] = await this.listAndCount(selector, config)
|
||||||
this.productCollectionRepository_
|
return collections
|
||||||
)
|
|
||||||
|
|
||||||
const query = buildQuery(selector, config)
|
|
||||||
return await productCollectionRepo.find(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,7 +236,10 @@ class ProductCollectionService extends TransactionBaseService {
|
|||||||
* @return the result of the find operation
|
* @return the result of the find operation
|
||||||
*/
|
*/
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: QuerySelector<ProductCollection> = {},
|
selector: Partial<ProductCollection> & {
|
||||||
|
q?: string
|
||||||
|
discount_condition_id?: string
|
||||||
|
} = {},
|
||||||
config: FindConfig<ProductCollection> = { skip: 0, take: 20 }
|
config: FindConfig<ProductCollection> = { skip: 0, take: 20 }
|
||||||
): Promise<[ProductCollection[], number]> {
|
): Promise<[ProductCollection[], number]> {
|
||||||
const productCollectionRepo = this.manager_.getCustomRepository(
|
const productCollectionRepo = this.manager_.getCustomRepository(
|
||||||
@@ -245,17 +247,12 @@ class ProductCollectionService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let q
|
let q
|
||||||
if ("q" in selector) {
|
if (isString(selector.q)) {
|
||||||
q = selector.q
|
q = selector.q
|
||||||
delete selector.q
|
delete selector.q
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = buildQuery(
|
const query = buildQuery(selector, config)
|
||||||
selector,
|
|
||||||
config
|
|
||||||
) as ExtendedFindConfig<ProductCollection> & {
|
|
||||||
where: (qb: any) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
const where = query.where
|
const where = query.where
|
||||||
@@ -278,6 +275,15 @@ class ProductCollectionService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query.where.discount_condition_id) {
|
||||||
|
const discountConditionId = query.where.discount_condition_id as string
|
||||||
|
delete query.where.discount_condition_id
|
||||||
|
return await productCollectionRepo.findAndCountByDiscountConditionId(
|
||||||
|
discountConditionId,
|
||||||
|
query
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return await productCollectionRepo.findAndCount(query)
|
return await productCollectionRepo.findAndCount(query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user