diff --git a/.changeset/lazy-geckos-think.md b/.changeset/lazy-geckos-think.md new file mode 100644 index 0000000000..a29b4cb090 --- /dev/null +++ b/.changeset/lazy-geckos-think.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa): fix error on creating product without FF sales channel diff --git a/integration-tests/api/__tests__/admin/product/without-ff-sales-channel.js b/integration-tests/api/__tests__/admin/product/without-ff-sales-channel.js new file mode 100644 index 0000000000..216051670a --- /dev/null +++ b/integration-tests/api/__tests__/admin/product/without-ff-sales-channel.js @@ -0,0 +1,71 @@ +const path = require("path") +const setupServer = require("../../../../helpers/setup-server") +const { useApi } = require("../../../../helpers/use-api") +const { initDb, useDb } = require("../../../../helpers/use-db") +const adminSeeder = require("../../../helpers/admin-seeder") + +const adminHeaders = { + headers: { + Authorization: "Bearer test_token", + }, +} + +describe("/admin/products", () => { + let medusaProcess + let dataSource + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) + + dataSource = await initDb({ cwd }) + medusaProcess = await setupServer({ + cwd, + env: { + MEDUSA_FF_SALES_CHANNELS: false, + } + }) + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + + medusaProcess.kill() + }) + + describe("POST /admin/products", () => { + beforeEach(async () => { + await adminSeeder(dataSource) + }) + + afterEach(async () => { + const db = useDb() + await db.teardown() + }) + + it("creates a product successfully", async () => { + const api = useApi() + + const payload = { + title: "Test", + description: "test-product-description", + } + + const response = await api + .post("/admin/products", payload, adminHeaders) + + expect(response.status).toEqual(200) + expect(response.data.product).toEqual( + expect.objectContaining({ + id: expect.stringMatching(/^prod_*/), + title: "Test", + description: "test-product-description", + handle: "test", + status: "draft", + created_at: expect.any(String), + updated_at: expect.any(String), + }) + ) + }) + }) +}) diff --git a/integration-tests/api/helpers/admin-seeder.js b/integration-tests/api/helpers/admin-seeder.js index 660bad0470..95f63c6326 100644 --- a/integration-tests/api/helpers/admin-seeder.js +++ b/integration-tests/api/helpers/admin-seeder.js @@ -1,8 +1,8 @@ const Scrypt = require("scrypt-kdf") const { User } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const buf = await Scrypt.kdf("secret_password", { logN: 1, r: 1, p: 1 }) const password_hash = buf.toString("base64") diff --git a/packages/medusa/src/api/routes/admin/products/create-product.ts b/packages/medusa/src/api/routes/admin/products/create-product.ts index a713953003..554994bf5c 100644 --- a/packages/medusa/src/api/routes/admin/products/create-product.ts +++ b/packages/medusa/src/api/routes/admin/products/create-product.ts @@ -42,6 +42,7 @@ import { } from "./transaction/create-product-variant" import { DistributedTransaction } from "../../../../utils/transaction" import { Logger } from "../../../../types/global" +import { FlagRouter } from "../../../../utils/flag-router" /** * @oas [post] /products @@ -117,6 +118,8 @@ export default async (req, res) => { const shippingProfileService: ShippingProfileService = req.scope.resolve( "shippingProfileService" ) + const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") + const productVariantInventoryService: ProductVariantInventoryService = req.scope.resolve("productVariantInventoryService") const inventoryService: IInventoryService | undefined = @@ -148,8 +151,12 @@ export default async (req, res) => { .retrieveDefault() } - // If no sales channel available, set the default one - if (!validated?.sales_channels?.length) { + // Provided that the feature flag is enabled and + // no sales channels are available, set the default one + if ( + featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) && + !validated?.sales_channels?.length + ) { const defaultSalesChannel = await salesChannelService .withTransaction(manager) .retrieveDefault()