fix(medusa): GET /admin/shipping-options params (#6208)

This commit is contained in:
Kasper Fabricius Kristensen
2024-01-24 19:16:57 +01:00
committed by GitHub
parent 6404b9abd1
commit 134af77667
13 changed files with 433 additions and 109 deletions
@@ -1,25 +1,10 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option"
const defaultFields = [
"id",
"name",
"region_id",
"profile_id",
"provider_id",
"price_type",
"amount",
"is_return",
"admin_only",
"data",
"created_at",
"updated_at",
"deleted_at",
"metadata",
]
const defaultRelations = ["region", "profile", "requirements"]
import {
shippingOptionsDefaultFields,
shippingOptionsDefaultRelations,
} from "../index"
describe("GET /admin/shipping-options", () => {
describe("successful retrieval", () => {
@@ -44,8 +29,11 @@ describe("GET /admin/shipping-options", () => {
expect(ShippingOptionServiceMock.listAndCount).toHaveBeenCalledWith(
{},
{
select: defaultFields,
relations: defaultRelations,
order: { created_at: "DESC" },
select: shippingOptionsDefaultFields,
relations: shippingOptionsDefaultRelations,
skip: 0,
take: 50,
}
)
})
@@ -8,16 +8,19 @@ import {
IsString,
ValidateNested,
} from "class-validator"
import {
shippingOptionsDefaultFields,
shippingOptionsDefaultRelations,
} from "."
import { RequirementType, ShippingOptionPriceType } from "../../../../models"
import { defaultFields, defaultRelations } from "."
import { EntityManager } from "typeorm"
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
import { ShippingOptionService } from "../../../../services"
import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing"
import { ShippingOptionService } from "../../../../services"
import { CreateShippingOptionInput } from "../../../../types/shipping-options"
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
import { validator } from "../../../../utils/validator"
/**
* @oas [post] /admin/shipping-options
@@ -150,8 +153,8 @@ export default async (req, res) => {
})
const data = await optionService.retrieve(result.id, {
select: defaultFields,
relations: defaultRelations,
select: shippingOptionsDefaultFields,
relations: shippingOptionsDefaultRelations,
})
res.status(200).json({ shipping_option: data })
@@ -1,4 +1,7 @@
import { defaultFields, defaultRelations } from "."
import {
shippingOptionsDefaultFields,
shippingOptionsDefaultRelations,
} from "."
/**
* @oas [get] /admin/shipping-options/{id}
@@ -84,8 +87,8 @@ export default async (req, res) => {
const optionService = req.scope.resolve("shippingOptionService")
const data = await optionService.retrieve(option_id, {
select: defaultFields,
relations: defaultRelations,
select: shippingOptionsDefaultFields,
relations: shippingOptionsDefaultRelations,
})
res.status(200).json({ shipping_option: data })
@@ -1,9 +1,10 @@
import { FlagRouter } from "@medusajs/utils"
import { Router } from "express"
import { ShippingOption } from "../../../.."
import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing"
import { ShippingOption } from "../../../../models"
import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
import middlewares from "../../../middlewares"
import middlewares, { transformQuery } from "../../../middlewares"
import { AdminGetShippingOptionsParams } from "./list-shipping-options"
const route = Router()
@@ -11,10 +12,18 @@ export default (app, featureFlagRouter: FlagRouter) => {
app.use("/shipping-options", route)
if (featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key)) {
defaultFields.push("includes_tax")
shippingOptionsDefaultFields.push("includes_tax")
}
route.get("/", middlewares.wrap(require("./list-shipping-options").default))
route.get(
"/",
transformQuery(AdminGetShippingOptionsParams, {
defaultFields: shippingOptionsDefaultFields,
defaultRelations: shippingOptionsDefaultRelations,
isList: true,
}),
middlewares.wrap(require("./list-shipping-options").default)
)
route.post("/", middlewares.wrap(require("./create-shipping-option").default))
route.get(
@@ -33,7 +42,7 @@ export default (app, featureFlagRouter: FlagRouter) => {
return app
}
export const defaultFields: (keyof ShippingOption)[] = [
export const shippingOptionsDefaultFields: (keyof ShippingOption)[] = [
"id",
"name",
"region_id",
@@ -50,7 +59,11 @@ export const defaultFields: (keyof ShippingOption)[] = [
"metadata",
]
export const defaultRelations = ["region", "profile", "requirements"]
export const shippingOptionsDefaultRelations = [
"region",
"profile",
"requirements",
]
/**
* @schema AdminShippingOptionsListRes
@@ -1,33 +1,116 @@
import { IsBoolean, IsOptional, IsString } from "class-validator"
import { defaultFields, defaultRelations } from "."
import {
IsBoolean,
IsOptional,
IsString,
ValidateNested,
} from "class-validator"
import { PricingService } from "../../../../services"
import { Transform } from "class-transformer"
import { Transform, Type } from "class-transformer"
import { Request, Response } from "express"
import { PricingService, ShippingOptionService } from "../../../../services"
import {
DateComparisonOperator,
extendedFindParamsMixin,
} from "../../../../types/common"
import { IsType } from "../../../../utils"
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
import { validator } from "../../../../utils/validator"
/**
* @oas [get] /admin/shipping-options
* operationId: "GetShippingOptions"
* summary: "List Shipping Options"
* description: "Retrieve a list of Shipping Options. The shipping options can be filtered by fields such as `region_id` or `is_return`."
* description: "Retrieve a list of Shipping Options. The shipping options can be filtered by fields such as `region_id` or `is_return`. The shipping options can also be sorted or paginated."
* x-authenticated: true
* parameters:
* - in: query
* name: region_id
* schema:
* type: string
* description: Filter by a region ID.
* - in: query
* name: is_return
* description: Filter by whether the shipping option is used for returns or orders.
* schema:
* type: boolean
* - in: query
* name: admin_only
* schema:
* type: boolean
* description: Filter by whether the shipping option is used only by admins or not.
* - (query) name {string} Filter by name.
* - (query) region_id {string} Filter by the ID of the region the shipping options belong to.
* - (query) is_return {boolean} Filter by whether the shipping options are return shipping options.
* - (query) admin_only {boolean} Filter by whether the shipping options are available for admin users only.
* - (query) q {string} Term used to search shipping options' name.
* - (query) order {string} A shipping option field to sort-order the retrieved shipping options by.
* - in: query
* name: id
* style: form
* explode: false
* description: Filter by shipping option IDs.
* schema:
* oneOf:
* - type: string
* description: ID of the shipping option.
* - type: array
* items:
* type: string
* description: ID of a shipping option.
* - in: query
* name: created_at
* description: Filter by a creation date range.
* 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: Filter by an update date range.
* 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: deleted_at
* description: Filter by a deletion date range.
* 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
* - (query) offset=0 {integer} The number of users to skip when retrieving the shipping options.
* - (query) limit=20 {integer} Limit the number of shipping options returned.
* - (query) expand {string} Comma-separated relations that should be expanded in the returned shipping options.
* - (query) fields {string} Comma-separated fields that should be included in the returned shipping options.
* x-codegen:
* method: list
* queryParams: AdminGetShippingOptionsParams
@@ -103,37 +186,60 @@ import { validator } from "../../../../utils/validator"
* "500":
* $ref: "#/components/responses/500_error"
*/
export default async (req, res) => {
const validatedParams = await validator(
AdminGetShippingOptionsParams,
req.query
export default async (req: Request, res: Response) => {
const optionService: ShippingOptionService = req.scope.resolve(
"shippingOptionService"
)
const optionService = req.scope.resolve("shippingOptionService")
const pricingService: PricingService = req.scope.resolve("pricingService")
const [data, count] = await optionService.listAndCount(validatedParams, {
select: defaultFields,
relations: defaultRelations,
})
const listConfig = req.listConfig
const filterableFields = req.filterableFields
const [data, count] = await optionService.listAndCount(
filterableFields,
listConfig
)
const options = await pricingService.setShippingOptionPrices(data)
res.status(200).json({ shipping_options: options, count })
res.status(200).json({
shipping_options: options,
count,
offset: listConfig.skip,
limit: listConfig.take,
})
}
/**
* Parameters used to filter the retrieved shipping options.
*/
export class AdminGetShippingOptionsParams {
export class AdminGetShippingOptionsParams extends extendedFindParamsMixin({
limit: 50,
offset: 0,
}) {
/**
* Filter shipping options by the ID of the region they belong to.
* IDs to filter shipping options by.
*/
@IsOptional()
@IsType([String, [String]])
id?: string | string[]
/**
* Name to filter shipping options by.
*/
@IsOptional()
@IsString()
name?: string
/**
* Filter by a region ID.
*/
@IsOptional()
@IsString()
region_id?: string
/**
* Filter shipping options by whether they're return shipping options.
* Filter by whether the shipping option is used for returns or orders.
*/
@IsOptional()
@IsBoolean()
@@ -141,10 +247,62 @@ export class AdminGetShippingOptionsParams {
is_return?: boolean
/**
* Filter shipping options by whether they're available for admin users only.
* Filter by whether the shipping options are available for admin users only.
*/
@IsOptional()
@IsBoolean()
@Transform(({ value }) => optionalBooleanMapper.get(value))
admin_only?: boolean
/**
* Filter shipping options by a search query.
*/
@IsOptional()
@IsString()
q?: string
/**
* The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`.
*/
@IsOptional()
@IsString()
order?: string
/**
* Date filters to apply on shipping options' `created_at` field.
*/
@IsOptional()
@ValidateNested()
@Type(() => DateComparisonOperator)
created_at?: DateComparisonOperator
/**
* Date filters to apply on shipping options' `updated_at` field.
*/
@IsOptional()
@ValidateNested()
@Type(() => DateComparisonOperator)
updated_at?: DateComparisonOperator
/**
* Date filters to apply on shipping options' `deleted_at` field.
*/
@ValidateNested()
@IsOptional()
@Type(() => DateComparisonOperator)
deleted_at?: DateComparisonOperator
/**
* Comma-separated fields that should be included in the returned shipping options.
*/
@IsOptional()
@IsString()
fields?: string
/**
* Comma-separated relations that should be expanded in the returned shipping options.
*/
@IsOptional()
@IsString()
expand?: string
}
@@ -8,15 +8,18 @@ import {
IsString,
ValidateNested,
} from "class-validator"
import { defaultFields, defaultRelations } from "."
import {
shippingOptionsDefaultFields,
shippingOptionsDefaultRelations,
} from "."
import { Type } from "class-transformer"
import { EntityManager } from "typeorm"
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing"
import { ShippingOptionPriceType } from "../../../../models"
import { ShippingOptionService } from "../../../../services"
import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing"
import { Type } from "class-transformer"
import { UpdateShippingOptionInput } from "../../../../types/shipping-options"
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
import { validator } from "../../../../utils/validator"
/**
@@ -152,8 +155,8 @@ export default async (req, res) => {
})
const data = await optionService.retrieve(option_id, {
select: defaultFields,
relations: defaultRelations,
select: shippingOptionsDefaultFields,
relations: shippingOptionsDefaultRelations,
})
res.status(200).json({ shipping_option: data })
@@ -27,7 +27,7 @@ describe("GET /admin/users", () => {
expect.objectContaining({
order: { created_at: "DESC" },
skip: 0,
take: 20,
take: 50,
})
)
})
@@ -16,13 +16,25 @@ import { IsType } from "../../../../utils"
* description: "Retrieves a list of users. The users can be filtered by fields such as `q` or `email`. The users can also be sorted or paginated."
* x-authenticated: true
* parameters:
* - (query) id {string} Filter by a user ID.
* - (query) email {string} Filter by email.
* - (query) first_name {string} Filter by first name.
* - (query) last_name {string} Filter by last name.
* - (query) q {string} term used to search users' first name, last name, and email.
* - (query) q {string} Term used to search users' first name, last name, and email.
* - (query) order {string} A user field to sort-order the retrieved users by.
* - in: query
* name: id
* style: form
* explode: false
* description: Filter by user IDs.
* schema:
* oneOf:
* - type: string
* description: ID of the user.
* - type: array
* items:
* type: string
* description: ID of a user.
* - in: query
* name: created_at
* description: Filter by a creation date range.
* schema:
@@ -90,7 +102,6 @@ import { IsType } from "../../../../utils"
* format: date
* - (query) offset=0 {integer} The number of users to skip when retrieving the users.
* - (query) limit=20 {integer} Limit the number of users returned.
* - (query) expand {string} Comma-separated relations that should be expanded in the returned users.
* - (query) fields {string} Comma-separated fields that should be included in the returned users.
* x-codegen:
* method: list
@@ -181,7 +192,10 @@ export default async (req: Request, res: Response) => {
/**
* Parameters used to filter and configure the pagination of the retrieved users.
*/
export class AdminGetUsersParams extends extendedFindParamsMixin() {
export class AdminGetUsersParams extends extendedFindParamsMixin({
limit: 50,
offset: 0,
}) {
/**
* IDs to filter users by.
*/
@@ -254,4 +268,11 @@ export class AdminGetUsersParams extends extendedFindParamsMixin() {
@IsOptional()
@IsEnum(UserRole, { each: true })
role?: UserRole
/**
* Comma-separated fields that should be included in the returned users.
*/
@IsOptional()
@IsString()
fields?: string
}