From ff84f749d59dae52e8f9ce19c36802aacafe9497 Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Wed, 27 Mar 2024 18:59:38 +0100 Subject: [PATCH] feat(medusa): add list location levels endpoint in api v2 (#6741) --- .../modules/__tests__/inventory/index.spec.ts | 74 +++++++++++++++++++ .../[id]/location-levels/route.ts | 24 ++++++ .../admin/inventory-items/middlewares.ts | 16 ++++ .../admin/inventory-items/validators.ts | 8 ++ 4 files changed, 122 insertions(+) diff --git a/integration-tests/modules/__tests__/inventory/index.spec.ts b/integration-tests/modules/__tests__/inventory/index.spec.ts index 0f1e150a2e..c7128b68cd 100644 --- a/integration-tests/modules/__tests__/inventory/index.spec.ts +++ b/integration-tests/modules/__tests__/inventory/index.spec.ts @@ -206,6 +206,80 @@ medusaIntegrationTestRunner({ ) }) + describe("List inventory levels", () => { + let inventoryItemId + let stockLocation1Id + let stockLocation2Id + + beforeEach(async () => { + const inventoryItem = await api.post( + `/admin/inventory-items`, + { sku: "test-sku" }, + adminHeaders + ) + inventoryItemId = inventoryItem.data.inventory_item.id + + const locationService = appContainer.resolve( + ModuleRegistrationName.STOCK_LOCATION + ) + const stockLocation1 = await locationService.create({ + name: "loc-1", + }) + stockLocation1Id = stockLocation1.id + + const stockLocation2 = await locationService.create({ + name: "loc-2", + }) + stockLocation2Id = stockLocation2.id + + await api.post( + `/admin/inventory-items/${inventoryItemId}/location-levels`, + { + location_id: stockLocation1Id, + stocked_quantity: 10, + }, + adminHeaders + ) + await api.post( + `/admin/inventory-items/${inventoryItemId}/location-levels`, + { + location_id: stockLocation2Id, + stocked_quantity: 15, + }, + adminHeaders + ) + }) + + it("should list the inventory levels", async () => { + const response = await api.get( + `/admin/inventory-items/${inventoryItemId}/location-levels`, + adminHeaders + ) + + expect(response.data).toEqual( + expect.objectContaining({ + count: 2, + offset: 0, + limit: 50, + }) + ) + + expect(response.data.inventory_levels).toHaveLength(2) + expect(response.data.inventory_levels).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + location_id: stockLocation1Id, + stocked_quantity: 10, + }), + expect.objectContaining({ + location_id: stockLocation2Id, + stocked_quantity: 15, + }), + ]) + ) + }) + }) + describe("Update inventory item", () => { let inventoryItemId beforeEach(async () => { diff --git a/packages/medusa/src/api-v2/admin/inventory-items/[id]/location-levels/route.ts b/packages/medusa/src/api-v2/admin/inventory-items/[id]/location-levels/route.ts index 0bd3293efb..386fc5aaa9 100644 --- a/packages/medusa/src/api-v2/admin/inventory-items/[id]/location-levels/route.ts +++ b/packages/medusa/src/api-v2/admin/inventory-items/[id]/location-levels/route.ts @@ -46,3 +46,27 @@ export const POST = async ( res.status(200).json({ inventory_item }) } + +export const GET = async (req: MedusaRequest, res: MedusaResponse) => { + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const query = remoteQueryObjectFromString({ + entryPoint: "inventory_levels", + variables: { + filters: req.filterableFields, + order: req.listConfig.order, + skip: req.listConfig.skip, + take: req.listConfig.take, + }, + fields: req.remoteQueryConfig.fields, + }) + + const { rows: inventory_levels, metadata } = await remoteQuery(query) + + res.status(200).json({ + inventory_levels, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, + }) +} diff --git a/packages/medusa/src/api-v2/admin/inventory-items/middlewares.ts b/packages/medusa/src/api-v2/admin/inventory-items/middlewares.ts index 9b6aa5ad3f..2067c97cdf 100644 --- a/packages/medusa/src/api-v2/admin/inventory-items/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/inventory-items/middlewares.ts @@ -1,6 +1,7 @@ import * as QueryConfig from "./query-config" import { + AdminGetInventoryItemsItemLocationLevelsParams, AdminGetInventoryItemsItemParams, AdminGetInventoryItemsParams, AdminPostInventoryItemsInventoryItemParams, @@ -52,6 +53,21 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["GET"], + matcher: "/admin/inventory-items/:id/location-levels", + middlewares: [ + transformQuery( + AdminGetInventoryItemsItemLocationLevelsParams, + QueryConfig.listLocationLevelsTransformQueryConfig + ), + ], + }, + { + method: ["POST"], + matcher: "/admin/inventory-items/:id/location-levels", + middlewares: [transformBody(AdminPostInventoryItemsItemLocationLevelsReq)], + }, { method: ["POST"], matcher: "/admin/inventory-items/:id/location-levels", diff --git a/packages/medusa/src/api-v2/admin/inventory-items/validators.ts b/packages/medusa/src/api-v2/admin/inventory-items/validators.ts index bda00a7edf..ae99b82084 100644 --- a/packages/medusa/src/api-v2/admin/inventory-items/validators.ts +++ b/packages/medusa/src/api-v2/admin/inventory-items/validators.ts @@ -259,6 +259,14 @@ export class AdminPostInventoryItemsReq { metadata?: Record } +export class AdminGetInventoryItemsItemLocationLevelsParams extends FindParams { + /** + * Location IDs to filter location levels. + */ + @IsOptional() + @IsString({ each: true }) + location_id?: string[] +} /** * @schema AdminPostInventoryItemsItemLocationLevelsLevelReq * type: object