From 2b078f06d930e6219b46720f4a916b20015329e5 Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Mon, 11 Sep 2023 14:05:47 +0200 Subject: [PATCH] fix(medusa): default sales channel for store variant endpoints (#4556) * add changeset * include default sales channel when querying variant endpoints * make parameter optional * update default values * add integraiton tests --- .changeset/mighty-humans-chew.md | 5 ++ .../inventory/products/get-variant.js | 49 ++++++++++++++++++- .../inventory/products/list-variants.js | 19 ++++++- .../middlewares/with-default-sales-channel.ts | 16 +++--- .../src/api/routes/store/products/index.ts | 2 +- .../src/api/routes/store/variants/index.ts | 3 ++ .../routes/store/variants/list-variants.ts | 2 + 7 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 .changeset/mighty-humans-chew.md diff --git a/.changeset/mighty-humans-chew.md b/.changeset/mighty-humans-chew.md new file mode 100644 index 0000000000..682e9e54df --- /dev/null +++ b/.changeset/mighty-humans-chew.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa): include default sales channel for store/variant endpoints if no other channel is selected diff --git a/integration-tests/plugins/__tests__/inventory/products/get-variant.js b/integration-tests/plugins/__tests__/inventory/products/get-variant.js index bc9957e556..0d03043453 100644 --- a/integration-tests/plugins/__tests__/inventory/products/get-variant.js +++ b/integration-tests/plugins/__tests__/inventory/products/get-variant.js @@ -10,7 +10,10 @@ const adminSeeder = require("../../../../helpers/admin-seeder") jest.setTimeout(30000) -const { simpleProductFactory } = require("../../../../factories") +const { + simpleProductFactory, + simpleSalesChannelFactory, +} = require("../../../../factories") const adminHeaders = { headers: { Authorization: "Bearer test_token" } } @@ -21,6 +24,10 @@ describe("Get variant", () => { const productId = "test-product" const variantId = "test-variant" let invItem + let salesChannelService + let salesChannelLocationService + let location + let inventoryService beforeAll(async () => { const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) @@ -52,8 +59,16 @@ describe("Get variant", () => { const productVariantInventoryService = appContainer.resolve( "productVariantInventoryService" ) - const inventoryService = appContainer.resolve("inventoryService") + inventoryService = appContainer.resolve("inventoryService") + salesChannelService = appContainer.resolve("salesChannelService") + salesChannelLocationService = appContainer.resolve( + "salesChannelLocationService" + ) + const stockLocationService = appContainer.resolve("stockLocationService") + location = await stockLocationService.create({ + name: "test-location", + }) await simpleProductFactory( dbConnection, { @@ -95,4 +110,34 @@ describe("Get variant", () => { }) ) }) + + it("sets availability correctly", async () => { + const salesChannel = await simpleSalesChannelFactory(dbConnection, { + is_default: true, + }) + + await salesChannelService.addProducts(salesChannel.id, [productId]) + + await salesChannelLocationService.associateLocation( + salesChannel.id, + location.id + ) + + await inventoryService.createInventoryLevel({ + inventory_item_id: invItem.id, + location_id: location.id, + stocked_quantity: 10, + }) + + const api = useApi() + + const response = await api.get(`/store/variants/${variantId}`) + + expect(response.data).toEqual({ + variant: expect.objectContaining({ + purchasable: true, + inventory_quantity: 10, + }), + }) + }) }) diff --git a/integration-tests/plugins/__tests__/inventory/products/list-variants.js b/integration-tests/plugins/__tests__/inventory/products/list-variants.js index b3251f237c..e26f16b1ba 100644 --- a/integration-tests/plugins/__tests__/inventory/products/list-variants.js +++ b/integration-tests/plugins/__tests__/inventory/products/list-variants.js @@ -64,7 +64,9 @@ describe("List Variants", () => { name: "test-location", }) - const salesChannel = await simpleSalesChannelFactory(dbConnection, {}) + const salesChannel = await simpleSalesChannelFactory(dbConnection, { + is_default: true, + }) const product = await simpleProductFactory(dbConnection, { variants: [{ id: variantId }], @@ -125,5 +127,20 @@ describe("List Variants", () => { }) ) }) + + it("sets availability correctly", async () => { + const api = useApi() + + const response = await api.get(`/store/variants?ids=${variantId}`) + + expect(response.data).toEqual({ + variants: [ + expect.objectContaining({ + purchasable: true, + inventory_quantity: 10, + }), + ], + }) + }) }) }) diff --git a/packages/medusa/src/api/middlewares/with-default-sales-channel.ts b/packages/medusa/src/api/middlewares/with-default-sales-channel.ts index 278caf3e3a..1b81097dd1 100644 --- a/packages/medusa/src/api/middlewares/with-default-sales-channel.ts +++ b/packages/medusa/src/api/middlewares/with-default-sales-channel.ts @@ -1,5 +1,6 @@ -import { FlagRouter } from "@medusajs/utils" import { NextFunction, Request, Response } from "express" + +import { FlagRouter } from "@medusajs/utils" import SalesChannelFeatureFlag from "../../loaders/feature-flags/sales-channels" import { SalesChannelService } from "../../services" @@ -8,11 +9,13 @@ import { SalesChannelService } from "../../services" * @param context Object of options * @param context.attachChannelAsArray Whether to attach the default sales channel as an array or just a string */ -export function withDefaultSalesChannel({ - attachChannelAsArray, -}: { - attachChannelAsArray?: boolean -}): (req: Request, res: Response, next: NextFunction) => Promise { +export function withDefaultSalesChannel( + { + attachChannelAsArray, + }: { + attachChannelAsArray: boolean + } = { attachChannelAsArray: false } +): (req: Request, res: Response, next: NextFunction) => Promise { return async (req: Request, _, next: NextFunction) => { const featureFlagRouter = req.scope.resolve( "featureFlagRouter" @@ -38,6 +41,7 @@ export function withDefaultSalesChannel({ : defaultSalesChannel.id } } catch { + // noop } finally { next() } diff --git a/packages/medusa/src/api/routes/store/products/index.ts b/packages/medusa/src/api/routes/store/products/index.ts index c10da46895..d2d8ed1dde 100644 --- a/packages/medusa/src/api/routes/store/products/index.ts +++ b/packages/medusa/src/api/routes/store/products/index.ts @@ -40,7 +40,7 @@ export default (app, featureFlagRouter: FlagRouter) => { route.get( "/:id", - withDefaultSalesChannel({}), + withDefaultSalesChannel(), transformStoreQuery(StoreGetProductsProductParams, { defaultRelations: defaultStoreProductsRelations, defaultFields: defaultStoreProductsFields, diff --git a/packages/medusa/src/api/routes/store/variants/index.ts b/packages/medusa/src/api/routes/store/variants/index.ts index c0854e025e..ebd9b5c0de 100644 --- a/packages/medusa/src/api/routes/store/variants/index.ts +++ b/packages/medusa/src/api/routes/store/variants/index.ts @@ -7,6 +7,7 @@ import { StoreGetVariantsVariantParams } from "./get-variant" import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params" import { validateProductVariantSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-variant-sales-channel-association" import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param" +import { withDefaultSalesChannel } from "../../../middlewares/with-default-sales-channel" const route = Router() @@ -17,6 +18,7 @@ export default (app) => { route.get( "/", + withDefaultSalesChannel(), transformStoreQuery(StoreGetVariantsParams, { defaultRelations: defaultStoreVariantRelations, allowedRelations: allowedStoreVariantRelations, @@ -26,6 +28,7 @@ export default (app) => { ) route.get( "/:id", + withDefaultSalesChannel(), transformStoreQuery(StoreGetVariantsVariantParams, { defaultRelations: defaultStoreVariantRelations, allowedRelations: allowedStoreVariantRelations, diff --git a/packages/medusa/src/api/routes/store/variants/list-variants.ts b/packages/medusa/src/api/routes/store/variants/list-variants.ts index cd450a6285..1f00987614 100644 --- a/packages/medusa/src/api/routes/store/variants/list-variants.ts +++ b/packages/medusa/src/api/routes/store/variants/list-variants.ts @@ -9,6 +9,7 @@ import { IsInt, IsOptional, IsString } from "class-validator" import { FilterableProductVariantProps } from "../../../../types/product-variant" import { IsType } from "../../../../utils/validators/is-type" +import { MedusaError } from "@medusajs/utils" import { NumericalComparisonOperator } from "../../../../types/common" import { PriceSelectionParams } from "../../../../types/price-selection" import { Type } from "class-transformer" @@ -154,6 +155,7 @@ export default async (req, res) => { "cart_id", "region_id", "currency_code", + "sales_channel_id", ]) if (validated.ids) {