feat: List products middleware (#6769)
This commit is contained in:
@@ -2,6 +2,10 @@ import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import * as QueryConfig from "./query-config"
|
||||
import {
|
||||
maybeApplyPriceListsFilter,
|
||||
maybeApplySalesChannelsFilter,
|
||||
} from "./utils"
|
||||
import {
|
||||
AdminGetProductsOptionsParams,
|
||||
AdminGetProductsParams,
|
||||
@@ -31,6 +35,8 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
AdminGetProductsParams,
|
||||
QueryConfig.listProductQueryConfig
|
||||
),
|
||||
maybeApplySalesChannelsFilter(),
|
||||
maybeApplyPriceListsFilter(),
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -86,6 +86,7 @@ export const defaultAdminProductFields = [
|
||||
"*variants",
|
||||
"*variants.prices",
|
||||
"*variants.options",
|
||||
"*sales_channels",
|
||||
]
|
||||
|
||||
export const retrieveProductQueryConfig = {
|
||||
|
||||
@@ -2,74 +2,26 @@ import { createProductsWorkflow } from "@medusajs/core-flows"
|
||||
import { CreateProductDTO } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
isString,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaContainer } from "medusa-core-utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../types/routing"
|
||||
import { listPriceLists } from "../price-lists/queries"
|
||||
import { refetchProduct, remapKeysForProduct, remapProduct } from "./helpers"
|
||||
import { AdminGetProductsParams } from "./validators"
|
||||
|
||||
const applyVariantFiltersForPriceList = async (
|
||||
scope: MedusaContainer,
|
||||
filterableFields: AdminGetProductsParams
|
||||
) => {
|
||||
const filterByPriceListIds = filterableFields.price_list_id
|
||||
const priceListVariantIds: string[] = []
|
||||
|
||||
// When filtering by price_list_id, we need use the remote query to get
|
||||
// the variant IDs through the price list price sets.
|
||||
if (Array.isArray(filterByPriceListIds)) {
|
||||
const [priceLists] = await listPriceLists({
|
||||
container: scope,
|
||||
remoteQueryFields: ["price_set_money_amounts.price_set.variant.id"],
|
||||
apiFields: ["prices.variant_id"],
|
||||
variables: { filters: { id: filterByPriceListIds }, skip: 0, take: null },
|
||||
})
|
||||
|
||||
priceListVariantIds.push(
|
||||
...((priceLists
|
||||
.map((priceList) => priceList.prices?.map((price) => price.variant_id))
|
||||
.flat(2)
|
||||
.filter(isString) || []) as string[])
|
||||
)
|
||||
|
||||
delete filterableFields.price_list_id
|
||||
}
|
||||
|
||||
if (priceListVariantIds.length) {
|
||||
const existingVariantFilters = filterableFields.variants || {}
|
||||
|
||||
filterableFields.variants = {
|
||||
...existingVariantFilters,
|
||||
id: priceListVariantIds,
|
||||
}
|
||||
}
|
||||
|
||||
return filterableFields
|
||||
}
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<AdminGetProductsParams>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
let filterableFields: AdminGetProductsParams = { ...req.filterableFields }
|
||||
|
||||
filterableFields = await applyVariantFiltersForPriceList(
|
||||
req.scope,
|
||||
filterableFields
|
||||
)
|
||||
|
||||
const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "product",
|
||||
variables: {
|
||||
filters: filterableFields,
|
||||
filters: req.filterableFields,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: selectFields,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./maybe-apply-price-lists-filter"
|
||||
export * from "./maybe-apply-sales-channels-filter"
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { NextFunction } from "express"
|
||||
import { MedusaRequest } from "../../../../types/routing"
|
||||
import { AdminGetProductsParams } from "../validators"
|
||||
|
||||
export function maybeApplyPriceListsFilter() {
|
||||
return async (req: MedusaRequest, _, next: NextFunction) => {
|
||||
const filterableFields: AdminGetProductsParams = req.filterableFields
|
||||
|
||||
if (!filterableFields.price_list_id) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const priceListIds = filterableFields.price_list_id
|
||||
delete filterableFields.price_list_id
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "price_list",
|
||||
fields: ["price_set_money_amounts.price_set.variant.id"],
|
||||
variables: {
|
||||
id: priceListIds,
|
||||
},
|
||||
})
|
||||
|
||||
const remoteQuery = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const variantIds: string[] = []
|
||||
const priceLists = await remoteQuery(queryObject)
|
||||
|
||||
priceLists.forEach((priceList) => {
|
||||
priceList.price_set_money_amounts?.forEach((psma) => {
|
||||
const variantId = psma.price_set?.variant?.id
|
||||
if (variantId) {
|
||||
variantIds.push(variantId)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
filterableFields.variants = {
|
||||
...(filterableFields.variants ?? {}),
|
||||
id: variantIds,
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { NextFunction } from "express"
|
||||
import { MedusaRequest } from "../../../../types/routing"
|
||||
import { AdminGetProductsParams } from "../validators"
|
||||
|
||||
export function maybeApplySalesChannelsFilter() {
|
||||
return async (req: MedusaRequest, _, next: NextFunction) => {
|
||||
const filterableFields: AdminGetProductsParams = req.filterableFields
|
||||
|
||||
if (!filterableFields.sales_channel_id) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const salesChannelIds = filterableFields.sales_channel_id
|
||||
delete filterableFields.sales_channel_id
|
||||
|
||||
const remoteQuery = req.scope.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "product_sales_channel",
|
||||
fields: ["product_id"],
|
||||
variables: { sales_channel_id: salesChannelIds },
|
||||
})
|
||||
|
||||
const productsInSalesChannels = await remoteQuery(queryObject)
|
||||
|
||||
filterableFields.id = productsInSalesChannels.map((p) => p.product_id)
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,13 @@ export class AdminGetProductsParams extends extendedFindParamsMixin({
|
||||
@IsArray()
|
||||
price_list_id?: string[]
|
||||
|
||||
/**
|
||||
* Filter products by associated sales channel IDs.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
sales_channel_id?: string[]
|
||||
|
||||
/**
|
||||
* Filter products by their associated product collection's ID.
|
||||
*/
|
||||
@@ -107,12 +114,6 @@ export class AdminGetProductsParams extends extendedFindParamsMixin({
|
||||
@IsObject()
|
||||
variants?: Record<any, any>
|
||||
|
||||
// /**
|
||||
// * Filter products by their associated sales channels' ID.
|
||||
// */
|
||||
// @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()])
|
||||
// sales_channel_id?: string[]
|
||||
|
||||
// /**
|
||||
// * Filter products by their associated discount condition's ID.
|
||||
// */
|
||||
|
||||
@@ -42,7 +42,7 @@ export const POST = async (
|
||||
) => {
|
||||
const salesChannelsData = [req.validatedBody]
|
||||
|
||||
const { errors } = await createSalesChannelsWorkflow(req.scope).run({
|
||||
const { errors, result } = await createSalesChannelsWorkflow(req.scope).run({
|
||||
input: { salesChannelsData },
|
||||
throwOnError: false,
|
||||
})
|
||||
@@ -51,11 +51,13 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const salesChannel = result[0]
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "sales_channels",
|
||||
variables: { id: req.params.id },
|
||||
variables: { id: salesChannel.id },
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user