feat: /store api product types (#2552)
## What Allow users to fetch ProductTypes from the storefront API. ## Why This endpoint will allow developers to implement better faceted product search in Medusa without the need for search plugin. Developers will be able to use this to render refinement lists based on types, like this:  ## How Endpoint `GET /store/products/types` and `GET /store/product-types` (use [product types listing in admin](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/api/routes/admin/products/list-types.ts) as reference) Support added in @medusajs/medusa-js Support added in medusa-react ## Testing Similar automated tests as `GET /admin/products/types` and `GET /admin/product-types` --- Resolves CORE-699
This commit is contained in:
7
.changeset/early-birds-juggle.md
Normal file
7
.changeset/early-birds-juggle.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/medusa-js": patch
|
||||
"medusa-react": patch
|
||||
---
|
||||
|
||||
feat(medusa, medusa-js, medusa-react): /store api product types
|
||||
@@ -55,11 +55,7 @@ describe("/admin/product-types", () => {
|
||||
it("returns a list of product types", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const res = await api
|
||||
.get("/admin/product-types", adminReqConfig)
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
const res = await api.get("/admin/product-types", adminReqConfig)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
|
||||
@@ -74,11 +70,10 @@ describe("/admin/product-types", () => {
|
||||
it("returns a list of product types matching free text search param", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const res = await api
|
||||
.get("/admin/product-types?q=test-type-new", adminReqConfig)
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
const res = await api.get(
|
||||
"/admin/product-types?q=test-type-new",
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`/store/product-types GET /store/product-types returns a list of product types 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"created_at": Any<String>,
|
||||
"id": "test-type-new",
|
||||
"updated_at": Any<String>,
|
||||
"value": "test-type-new",
|
||||
},
|
||||
Object {
|
||||
"created_at": Any<String>,
|
||||
"id": "test-type",
|
||||
"updated_at": Any<String>,
|
||||
"value": "test-type",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`/store/product-types GET /store/product-types returns a list of product types matching free text search param 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"created_at": Any<String>,
|
||||
"id": "test-type-new",
|
||||
"updated_at": Any<String>,
|
||||
"value": "test-type-new",
|
||||
},
|
||||
]
|
||||
`;
|
||||
154
integration-tests/api/__tests__/store/product-type.js
Normal file
154
integration-tests/api/__tests__/store/product-type.js
Normal file
@@ -0,0 +1,154 @@
|
||||
const path = require("path")
|
||||
|
||||
const { IdMap } = require("medusa-test-utils")
|
||||
|
||||
const setupServer = require("../../../helpers/setup-server")
|
||||
const { useApi } = require("../../../helpers/use-api")
|
||||
const { initDb, useDb } = require("../../../helpers/use-db")
|
||||
|
||||
const productSeeder = require("../../helpers/product-seeder")
|
||||
const {
|
||||
DiscountRuleType,
|
||||
AllocationType,
|
||||
DiscountConditionType,
|
||||
DiscountConditionOperator,
|
||||
} = require("@medusajs/medusa")
|
||||
const { simpleDiscountFactory } = require("../../factories")
|
||||
|
||||
jest.setTimeout(50000)
|
||||
|
||||
describe("/store/product-types", () => {
|
||||
let medusaProcess
|
||||
let dbConnection
|
||||
|
||||
beforeAll(async () => {
|
||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||
dbConnection = await initDb({ cwd })
|
||||
medusaProcess = await setupServer({ cwd })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
const db = useDb()
|
||||
await db.shutdown()
|
||||
|
||||
medusaProcess.kill()
|
||||
})
|
||||
|
||||
describe("GET /store/product-types", () => {
|
||||
beforeEach(async () => {
|
||||
await productSeeder(dbConnection)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("returns a list of product types", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const res = await api.get("/store/product-types")
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
|
||||
const typeMatch = {
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
}
|
||||
|
||||
expect(res.data.product_types).toMatchSnapshot([typeMatch, typeMatch])
|
||||
})
|
||||
|
||||
it("returns a list of product types matching free text search param", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const res = await api.get("/store/product-types?q=test-type-new")
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
|
||||
const typeMatch = {
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
}
|
||||
|
||||
// The value of the type should match the search param
|
||||
expect(res.data.product_types.map((pt) => pt.value)).toEqual([
|
||||
"test-type-new",
|
||||
])
|
||||
|
||||
// Should only return one type as there is only one match to the search param
|
||||
expect(res.data.product_types).toMatchSnapshot([typeMatch])
|
||||
})
|
||||
|
||||
it("returns a list of product type filtered by discount condition id", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const resTypes = await api.get("/store/product-types")
|
||||
|
||||
const type1 = resTypes.data.product_types[0]
|
||||
const type2 = resTypes.data.product_types[1]
|
||||
|
||||
const buildDiscountData = (code, conditionId, types) => {
|
||||
return {
|
||||
code,
|
||||
rule: {
|
||||
type: DiscountRuleType.PERCENTAGE,
|
||||
value: 10,
|
||||
allocation: AllocationType.TOTAL,
|
||||
conditions: [
|
||||
{
|
||||
id: conditionId,
|
||||
type: DiscountConditionType.PRODUCT_TYPES,
|
||||
operator: DiscountConditionOperator.IN,
|
||||
product_types: types,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const discountConditionId = IdMap.getId("discount-condition-type-1")
|
||||
await simpleDiscountFactory(
|
||||
dbConnection,
|
||||
buildDiscountData("code-1", discountConditionId, [type1.id])
|
||||
)
|
||||
|
||||
const discountConditionId2 = IdMap.getId("discount-condition-type-2")
|
||||
await simpleDiscountFactory(
|
||||
dbConnection,
|
||||
buildDiscountData("code-2", discountConditionId2, [type2.id])
|
||||
)
|
||||
|
||||
let res = await api.get(
|
||||
`/store/product-types?discount_condition_id=${discountConditionId}`
|
||||
)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.product_types).toHaveLength(1)
|
||||
expect(res.data.product_types).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ id: type1.id })])
|
||||
)
|
||||
|
||||
res = await api.get(
|
||||
`/store/product-types?discount_condition_id=${discountConditionId2}`
|
||||
)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.product_types).toHaveLength(1)
|
||||
expect(res.data.product_types).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ id: type2.id })])
|
||||
)
|
||||
|
||||
res = await api.get(`/store/product-types`)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.product_types).toHaveLength(2)
|
||||
expect(res.data.product_types).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ id: type1.id }),
|
||||
expect.objectContaining({ id: type2.id }),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -10,6 +10,7 @@ import OrdersResource from "./resources/orders"
|
||||
import OrderEditsResource from "./resources/order-edits"
|
||||
import PaymentMethodsResource from "./resources/payment-methods"
|
||||
import ProductsResource from "./resources/products"
|
||||
import ProductTypesResource from "./resources/product-types"
|
||||
import RegionsResource from "./resources/regions"
|
||||
import ReturnReasonsResource from "./resources/return-reasons"
|
||||
import ReturnsResource from "./resources/returns"
|
||||
@@ -27,6 +28,7 @@ class Medusa {
|
||||
public orders: OrdersResource
|
||||
public orderEdits: OrderEditsResource
|
||||
public products: ProductsResource
|
||||
public productTypes: ProductTypesResource
|
||||
public regions: RegionsResource
|
||||
public returnReasons: ReturnReasonsResource
|
||||
public returns: ReturnsResource
|
||||
@@ -48,6 +50,7 @@ class Medusa {
|
||||
this.orders = new OrdersResource(this.client)
|
||||
this.orderEdits = new OrderEditsResource(this.client)
|
||||
this.products = new ProductsResource(this.client)
|
||||
this.productTypes = new ProductTypesResource(this.client)
|
||||
this.regions = new RegionsResource(this.client)
|
||||
this.returnReasons = new ReturnReasonsResource(this.client)
|
||||
this.returns = new ReturnsResource(this.client)
|
||||
|
||||
@@ -8,16 +8,17 @@ import BaseResource from "../base"
|
||||
|
||||
class AdminProductTypesResource extends BaseResource {
|
||||
list(
|
||||
query?: AdminGetProductTypesParams
|
||||
query?: AdminGetProductTypesParams,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminProductTypesListRes> {
|
||||
let path = `/admin/product-types`
|
||||
|
||||
if (query) {
|
||||
const queryString = qs.stringify(query)
|
||||
path = `/admin/product-types?${queryString}`
|
||||
path += `?${queryString}`
|
||||
}
|
||||
|
||||
return this.client.request("GET", path)
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@ class AdminProductsResource extends BaseResource {
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link AdminProductTypesResource.list} instead.
|
||||
*/
|
||||
listTypes(
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminProductsListTypesRes> {
|
||||
|
||||
31
packages/medusa-js/src/resources/product-types.ts
Normal file
31
packages/medusa-js/src/resources/product-types.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {
|
||||
StoreGetProductTypesParams,
|
||||
StoreProductTypesListRes,
|
||||
} from "@medusajs/medusa"
|
||||
import qs from "qs"
|
||||
import { ResponsePromise } from "../typings"
|
||||
import BaseResource from "./base"
|
||||
|
||||
class ProductTypesResource extends BaseResource {
|
||||
/**
|
||||
* @description Retrieves a list of product types
|
||||
* @param {StoreGetProductTypesParams} query is optional. Can contain a limit and offset for the returned list
|
||||
* @param customHeaders
|
||||
* @return {ResponsePromise<StoreProductTypesListRes>}
|
||||
*/
|
||||
list(
|
||||
query?: StoreGetProductTypesParams,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StoreProductTypesListRes> {
|
||||
let path = `/store/product-types`
|
||||
|
||||
if (query) {
|
||||
const queryString = qs.stringify(query)
|
||||
path += `?${queryString}`
|
||||
}
|
||||
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
export default ProductTypesResource
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./products/"
|
||||
export * from "./product-types/"
|
||||
export * from "./carts/"
|
||||
export * from "./shipping-options/"
|
||||
export * from "./regions/"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./queries"
|
||||
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
StoreGetProductTypesParams,
|
||||
StoreProductTypesListRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
import { useQuery } from "react-query"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { UseQueryOptionsWrapper } from "../../../types"
|
||||
import { queryKeysFactory } from "../../utils"
|
||||
|
||||
const PRODUCT_TYPES_QUERY_KEY = `product_types` as const
|
||||
|
||||
export const productTypeKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY)
|
||||
|
||||
type ProductTypesQueryKeys = typeof productTypeKeys
|
||||
|
||||
export const useProductTypes = (
|
||||
query?: StoreGetProductTypesParams,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<StoreProductTypesListRes>,
|
||||
Error,
|
||||
ReturnType<ProductTypesQueryKeys["list"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
productTypeKeys.list(query),
|
||||
() => client.productTypes.list(query),
|
||||
options
|
||||
)
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
@@ -56,6 +56,7 @@ export * from "./routes/store/gift-cards"
|
||||
export * from "./routes/store/order-edits"
|
||||
export * from "./routes/store/orders"
|
||||
export * from "./routes/store/products"
|
||||
export * from "./routes/store/product-types"
|
||||
export * from "./routes/store/regions"
|
||||
export * from "./routes/store/return-reasons"
|
||||
export * from "./routes/store/returns"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
DateComparisonOperator,
|
||||
FindPaginationParams,
|
||||
StringComparisonOperator,
|
||||
} from "../../../../types/common"
|
||||
import { IsNumber, IsOptional, IsString } from "class-validator"
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import ProductTypeService from "../../../../services/product-type"
|
||||
import { Type } from "class-transformer"
|
||||
|
||||
/**
|
||||
* @oas [get] /product-types
|
||||
@@ -15,7 +15,7 @@ import { Type } from "class-transformer"
|
||||
* description: "Retrieve a list of Product Types."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (query) limit=10 {integer} The number of types to return.
|
||||
* - (query) limit=20 {integer} The number of types to return.
|
||||
* - (query) offset=0 {integer} The number of items to skip before the results.
|
||||
* - (query) order {string} The field to sort items by.
|
||||
* - (query) discount_condition_id {string} The discount condition id on which to filter the product types.
|
||||
@@ -154,20 +154,8 @@ export default async (req, res) => {
|
||||
})
|
||||
}
|
||||
|
||||
export class AdminGetProductTypesPaginationParams {
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
limit? = 10
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
offset? = 0
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export class AdminGetProductTypesParams extends AdminGetProductTypesPaginationParams {
|
||||
export class AdminGetProductTypesParams extends FindPaginationParams {
|
||||
@IsType([String, [String], StringComparisonOperator])
|
||||
@IsOptional()
|
||||
id?: string | string[] | StringComparisonOperator
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ProductService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [get] /products/types
|
||||
* deprecated: true
|
||||
* operationId: "GetProductsTypes"
|
||||
* summary: "List Product Types"
|
||||
* description: "Retrieves a list of Product Types."
|
||||
|
||||
@@ -9,6 +9,7 @@ import giftCardRoutes from "./gift-cards"
|
||||
import orderRoutes from "./orders"
|
||||
import orderEditRoutes from "./order-edits"
|
||||
import productRoutes from "./products"
|
||||
import productTypesRoutes from "../admin/product-types"
|
||||
import regionRoutes from "./regions"
|
||||
import returnReasonRoutes from "./return-reasons"
|
||||
import returnRoutes from "./returns"
|
||||
@@ -35,6 +36,7 @@ export default (app, container, config) => {
|
||||
collectionRoutes(route)
|
||||
customerRoutes(route, container)
|
||||
productRoutes(route)
|
||||
productTypesRoutes(route)
|
||||
orderRoutes(route)
|
||||
orderEditRoutes(route)
|
||||
cartRoutes(route, container)
|
||||
|
||||
50
packages/medusa/src/api/routes/store/product-types/index.ts
Normal file
50
packages/medusa/src/api/routes/store/product-types/index.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Router } from "express"
|
||||
import { ProductType } from "../../../.."
|
||||
import { PaginatedResponse } from "../../../../types/common"
|
||||
import middlewares, { transformQuery } from "../../../middlewares"
|
||||
import "reflect-metadata"
|
||||
import { StoreGetProductTypesParams } from "./list-product-types"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use("/product-types", route)
|
||||
|
||||
route.get(
|
||||
"/",
|
||||
transformQuery(StoreGetProductTypesParams, {
|
||||
defaultFields: defaultStoreProductTypeFields,
|
||||
defaultRelations: defaultStoreProductTypeRelations,
|
||||
allowedFields: allowedStoreProductTypeFields,
|
||||
isList: true,
|
||||
}),
|
||||
middlewares.wrap(require("./list-product-types").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export const allowedStoreProductTypeFields = [
|
||||
"id",
|
||||
"value",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
export const defaultStoreProductTypeFields = [
|
||||
"id",
|
||||
"value",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
export const defaultStoreProductTypeRelations = []
|
||||
|
||||
export type StoreProductTypesListRes = PaginatedResponse & {
|
||||
product_types: ProductType[]
|
||||
}
|
||||
|
||||
export type StoreProductTypesRes = {
|
||||
product_type: ProductType
|
||||
}
|
||||
|
||||
export * from "./list-product-types"
|
||||
@@ -0,0 +1,186 @@
|
||||
import {
|
||||
DateComparisonOperator,
|
||||
FindPaginationParams,
|
||||
StringComparisonOperator,
|
||||
} from "../../../../types/common"
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import ProductTypeService from "../../../../services/product-type"
|
||||
|
||||
/**
|
||||
* @oas [get] /product-types
|
||||
* operationId: "GetProductTypes"
|
||||
* summary: "List Product Types"
|
||||
* description: "Retrieve a list of Product Types."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (query) limit=20 {integer} The number of types to return.
|
||||
* - (query) offset=0 {integer} The number of items to skip before the results.
|
||||
* - (query) order {string} The field to sort items by.
|
||||
* - (query) discount_condition_id {string} The discount condition id on which to filter the product types.
|
||||
* - in: query
|
||||
* name: value
|
||||
* style: form
|
||||
* explode: false
|
||||
* description: The type values to search for
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: id
|
||||
* style: form
|
||||
* explode: false
|
||||
* description: The type IDs to search for
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* - (query) q {string} A query string to search values for
|
||||
* - in: query
|
||||
* name: created_at
|
||||
* description: Date comparison for when resulting product types were created.
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* lt:
|
||||
* type: string
|
||||
* description: filter by dates less than this date
|
||||
* format: date
|
||||
* gt:
|
||||
* type: string
|
||||
* description: filter by dates greater than this date
|
||||
* format: date
|
||||
* lte:
|
||||
* type: string
|
||||
* description: filter by dates less than or equal to this date
|
||||
* format: date
|
||||
* gte:
|
||||
* type: string
|
||||
* description: filter by dates greater than or equal to this date
|
||||
* format: date
|
||||
* - in: query
|
||||
* name: updated_at
|
||||
* description: Date comparison for when resulting product types were updated.
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* lt:
|
||||
* type: string
|
||||
* description: filter by dates less than this date
|
||||
* format: date
|
||||
* gt:
|
||||
* type: string
|
||||
* description: filter by dates greater than this date
|
||||
* format: date
|
||||
* lte:
|
||||
* type: string
|
||||
* description: filter by dates less than or equal to this date
|
||||
* format: date
|
||||
* gte:
|
||||
* type: string
|
||||
* description: filter by dates greater than or equal to this date
|
||||
* format: date
|
||||
* x-codeSamples:
|
||||
* - lang: JavaScript
|
||||
* label: JS Client
|
||||
* source: |
|
||||
* import Medusa from "@medusajs/medusa-js"
|
||||
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
|
||||
* // must be previously logged in or use api token
|
||||
* medusa.store.productTypes.list()
|
||||
* .then(({ product_types }) => {
|
||||
* console.log(product_types.length);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request GET 'https://medusa-url.com/store/product-types' \
|
||||
* --header 'Authorization: Bearer {api_token}'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Product Type
|
||||
* responses:
|
||||
* "200":
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* product_types:
|
||||
* $ref: "#/components/schemas/product_type"
|
||||
* count:
|
||||
* type: integer
|
||||
* description: The total number of items available
|
||||
* offset:
|
||||
* type: integer
|
||||
* description: The number of items skipped before these items
|
||||
* limit:
|
||||
* type: integer
|
||||
* description: The number of items per page
|
||||
* "400":
|
||||
* $ref: "#/components/responses/400_error"
|
||||
* "401":
|
||||
* $ref: "#/components/responses/unauthorized"
|
||||
* "404":
|
||||
* $ref: "#/components/responses/not_found_error"
|
||||
* "409":
|
||||
* $ref: "#/components/responses/invalid_state_error"
|
||||
* "422":
|
||||
* $ref: "#/components/responses/invalid_request_error"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const typeService: ProductTypeService =
|
||||
req.scope.resolve("productTypeService")
|
||||
|
||||
const { listConfig, filterableFields } = req
|
||||
const { skip, take } = req.listConfig
|
||||
|
||||
const [types, count] = await typeService.listAndCount(
|
||||
filterableFields,
|
||||
listConfig
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
product_types: types,
|
||||
count,
|
||||
offset: skip,
|
||||
limit: take,
|
||||
})
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export class StoreGetProductTypesParams extends FindPaginationParams {
|
||||
@IsType([String, [String], StringComparisonOperator])
|
||||
@IsOptional()
|
||||
id?: string | string[] | StringComparisonOperator
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
q?: string
|
||||
|
||||
@IsType([String, [String], StringComparisonOperator])
|
||||
@IsOptional()
|
||||
value?: string | string[] | StringComparisonOperator
|
||||
|
||||
@IsType([DateComparisonOperator])
|
||||
@IsOptional()
|
||||
created_at?: DateComparisonOperator
|
||||
|
||||
@IsType([DateComparisonOperator])
|
||||
@IsOptional()
|
||||
updated_at?: DateComparisonOperator
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
order?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
discount_condition_id?: string
|
||||
}
|
||||
@@ -20,7 +20,7 @@ class ProductTypeService extends TransactionBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a product by id.
|
||||
* Gets a product type by id.
|
||||
* Throws in case of DB Error and if product was not found.
|
||||
* @param id - id of the product to get.
|
||||
* @param config - object that defines what should be included in the
|
||||
@@ -39,7 +39,7 @@ class ProductTypeService extends TransactionBaseService {
|
||||
if (!type) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Product with id: ${id} was not found`
|
||||
`Product type with id: ${id} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class ProductTypeService extends TransactionBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists product tags and adds count.
|
||||
* Lists product types and adds count.
|
||||
* @param selector - the query object for find
|
||||
* @param config - the config to be used for find
|
||||
* @return the result of the find operation
|
||||
|
||||
Reference in New Issue
Block a user