feat(medusa, stock-location, types): Add q and order params to list-stock-locations (#6197)

**What**
- add `q` and `order` params to list-stock-location endpoint

closes #6189
This commit is contained in:
Philip Korsholm
2024-01-29 09:14:39 +00:00
committed by GitHub
parent 3db2f95e65
commit d1c18a3090
9 changed files with 263 additions and 33 deletions
+7
View File
@@ -0,0 +1,7 @@
---
"@medusajs/stock-location": patch
"@medusajs/medusa": patch
"@medusajs/types": patch
---
feat(stock-location, medusa, types): add `q` and `order` query parameters to stock locations list endpoint
@@ -0,0 +1,181 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { useApi } from "../../../environment-helpers/use-api"
import { AxiosInstance } from "axios"
import adminSeeder from "../../../helpers/admin-seeder"
const path = require("path")
const {
startBootstrapApp,
} = require("../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
const { getContainer } = require("../../../environment-helpers/use-container")
const { useExpressServer } = require("../../../environment-helpers/use-api")
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
jest.setTimeout(50000)
describe("List stock locations", () => {
let shutdownServer
let appContainer
let dbConnection
let addressId
let scId
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
shutdownServer = await startBootstrapApp({ cwd })
appContainer = getContainer()
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
const stockLocationModule = appContainer.resolve(
ModuleRegistrationName.STOCK_LOCATION
)
const salesChannelService = appContainer.resolve("salesChannelService")
const salesChannelLocationService = appContainer.resolve(
"salesChannelLocationService"
)
const { id: sc_id } = await salesChannelService.create({ name: "test" })
scId = sc_id
const [{ address_id }, { id }] = await Promise.all([
stockLocationModule.create({
name: "Copenhagen",
address: {
address_1: "test street 1",
country_code: "DK",
},
}),
stockLocationModule.create({
name: "Berlin",
}),
stockLocationModule.create({
name: "Paris",
}),
])
await salesChannelLocationService.associateLocation(sc_id, id)
addressId = address_id
})
describe("GET /stock-location", () => {
it("should list all stock locations", async () => {
const api = useApi()! as AxiosInstance
const result = await api.get("/admin/stock-locations", adminHeaders)
expect(result.status).toEqual(200)
expect(result.data.stock_locations).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: "Copenhagen",
}),
expect.objectContaining({
name: "Berlin",
}),
expect.objectContaining({
name: "Paris",
}),
])
)
})
it("should list stock locations filtered by q parameter", async () => {
const api = useApi()! as AxiosInstance
const result = await api.get(
"/admin/stock-locations?q=open",
adminHeaders
)
expect(result.status).toEqual(200)
expect(result.data.count).toEqual(1)
expect(result.data.stock_locations).toEqual([
expect.objectContaining({
name: "Copenhagen",
}),
])
})
it("should list stock locations filtered by addresses", async () => {
const api = useApi()! as AxiosInstance
const result = await api.get(
`/admin/stock-locations?address_id=${addressId}`,
adminHeaders
)
expect(result.status).toEqual(200)
expect(result.data.count).toEqual(1)
expect(result.data.stock_locations).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: "Copenhagen",
}),
])
)
})
it("should list stock locations filtered by sales channel Id", async () => {
const api = useApi()! as AxiosInstance
const result = await api.get(
`/admin/stock-locations?sales_channel_id=${scId}`,
adminHeaders
)
expect(result.status).toEqual(200)
expect(result.data.count).toEqual(1)
expect(result.data.stock_locations).toEqual([
expect.objectContaining({
name: "Berlin",
}),
])
})
it("should list stock locations in requested order", async () => {
const api = useApi()! as AxiosInstance
const nameOrderLocations = [
expect.objectContaining({
name: "Berlin",
}),
expect.objectContaining({
name: "Copenhagen",
}),
expect.objectContaining({
name: "Paris",
}),
]
let result = await api.get(
"/admin/stock-locations?order=name",
adminHeaders
)
expect(result.status).toEqual(200)
expect(result.data.stock_locations).toEqual(nameOrderLocations)
result = await api.get("/admin/stock-locations?order=-name", adminHeaders)
expect(result.status).toEqual(200)
expect(result.data.stock_locations).toEqual(nameOrderLocations.reverse())
})
})
})
@@ -2,15 +2,17 @@ const path = require("path")
const {
startBootstrapApp,
} = require("../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
} = require("../../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../environment-helpers/use-db")
const {
useApi,
useExpressServer,
} = require("../../../environment-helpers/use-api")
} = require("../../../../environment-helpers/use-api")
const adminSeeder = require("../../../helpers/admin-seeder")
const { getContainer } = require("../../../environment-helpers/use-container")
const adminSeeder = require("../../../../helpers/admin-seeder")
const {
getContainer,
} = require("../../../../environment-helpers/use-container")
jest.setTimeout(30000)
@@ -20,7 +22,7 @@ describe("Sales channels", () => {
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
shutdownServer = await startBootstrapApp({ cwd })
appContainer = getContainer()
@@ -2,15 +2,17 @@ const path = require("path")
const {
startBootstrapApp,
} = require("../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
} = require("../../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../environment-helpers/use-db")
const {
useApi,
useExpressServer,
} = require("../../../environment-helpers/use-api")
} = require("../../../../environment-helpers/use-api")
const adminSeeder = require("../../../helpers/admin-seeder")
const { getContainer } = require("../../../environment-helpers/use-container")
const adminSeeder = require("../../../../helpers/admin-seeder")
const {
getContainer,
} = require("../../../../environment-helpers/use-container")
jest.setTimeout(30000)
@@ -20,7 +22,7 @@ describe("Sales channels", () => {
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
shutdownServer = await startBootstrapApp({ cwd })
appContainer = getContainer()
@@ -2,15 +2,17 @@ const path = require("path")
const {
startBootstrapApp,
} = require("../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
} = require("../../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../environment-helpers/use-db")
const {
useApi,
useExpressServer,
} = require("../../../environment-helpers/use-api")
} = require("../../../../environment-helpers/use-api")
const adminSeeder = require("../../../helpers/admin-seeder")
const { getContainer } = require("../../../environment-helpers/use-container")
const adminSeeder = require("../../../../helpers/admin-seeder")
const {
getContainer,
} = require("../../../../environment-helpers/use-container")
jest.setTimeout(30000)
@@ -22,7 +24,7 @@ describe("Sales channels", () => {
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
shutdownServer = await startBootstrapApp({ cwd })
appContainer = getContainer()
@@ -2,20 +2,22 @@ const path = require("path")
const {
startBootstrapApp,
} = require("../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
const { getContainer } = require("../../../environment-helpers/use-container")
const { useExpressServer } = require("../../../environment-helpers/use-api")
} = require("../../../../environment-helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../environment-helpers/use-db")
const {
getContainer,
} = require("../../../../environment-helpers/use-container")
const { useExpressServer } = require("../../../../environment-helpers/use-api")
jest.setTimeout(30000)
describe("Inventory Module", () => {
describe("Stock Location Module", () => {
let appContainer
let dbConnection
let shutdownServer
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
shutdownServer = await startBootstrapApp({ cwd })
appContainer = getContainer()
@@ -1,5 +1,5 @@
import { IStockLocationService } from "@medusajs/types"
import { IsOptional } from "class-validator"
import { IsOptional, IsString } from "class-validator"
import { Request, Response } from "express"
import {
SalesChannelLocationService,
@@ -231,6 +231,13 @@ export class AdminGetStockLocationsParams extends extendedFindParamsMixin({
limit: 20,
offset: 0,
}) {
/**
* Search term to search stock location names.
*/
@IsString()
@IsOptional()
q?: string
/**
* IDs to filter stock locations by.
*/
@@ -258,4 +265,11 @@ export class AdminGetStockLocationsParams extends extendedFindParamsMixin({
@IsOptional()
@IsType([String, [String]])
sales_channel_id?: string | 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 `-`.
*/
@IsString()
@IsOptional()
order?: string
}
@@ -12,12 +12,12 @@ import {
} from "@medusajs/types"
import {
InjectEntityManager,
isDefined,
MedusaContext,
MedusaError,
isDefined,
setMetadata,
} from "@medusajs/utils"
import { EntityManager } from "typeorm"
import { EntityManager, FindOptionsWhere, ILike } from "typeorm"
import { joinerConfig } from "../joiner-config"
import { StockLocation, StockLocationAddress } from "../models"
import { buildQuery } from "../utils/build-query"
@@ -66,11 +66,8 @@ export default class StockLocationService {
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 },
context: SharedContext = {}
): Promise<StockLocation[]> {
const manager = context.transactionManager ?? this.manager_
const locationRepo = manager.getRepository(StockLocation)
const query = buildQuery(selector, config)
return await locationRepo.find(query)
const [locations] = await this.listAndCount(selector, config, context)
return locations
}
/**
@@ -87,8 +84,27 @@ export default class StockLocationService {
): Promise<[StockLocation[], number]> {
const manager = context.transactionManager ?? this.manager_
const locationRepo = manager.getRepository(StockLocation)
let q
if (selector.q) {
q = selector.q
delete selector.q
}
const query = buildQuery(selector, config)
if (q) {
const where = query.where as FindOptionsWhere<StockLocation>
delete where.name
query.where = [
{
...where,
name: ILike(`%${q}%`),
},
]
}
return await locationRepo.findAndCount(query)
}
+5 -1
View File
@@ -153,10 +153,14 @@ export type StockLocationExpandedDTO = StockLocationDTO & {
/**
* @interface
*
*
* The filters to apply on the retrieved stock locations.
*/
export type FilterableStockLocationProps = {
/**
* Search parameter for stock location names
*/
q?: string
/**
* The IDs to filter stock locations by.
*/