fix: Add some tests and test cleanup for product module (#6586)
This commit is contained in:
@@ -16,11 +16,11 @@ const {
|
|||||||
module.exports = async (dataSource, data = {}) => {
|
module.exports = async (dataSource, data = {}) => {
|
||||||
const manager = dataSource.manager
|
const manager = dataSource.manager
|
||||||
|
|
||||||
const defaultProfile = await manager.findOne(ShippingProfile, {
|
const defaultProfile = (await manager.findOne(ShippingProfile, {
|
||||||
where: {
|
where: {
|
||||||
type: ShippingProfileType.DEFAULT,
|
type: ShippingProfileType.DEFAULT,
|
||||||
},
|
},
|
||||||
})
|
})) || { id: "default-profile" }
|
||||||
|
|
||||||
const coll = manager.create(ProductCollection, {
|
const coll = manager.create(ProductCollection, {
|
||||||
id: "test-collection",
|
id: "test-collection",
|
||||||
|
|||||||
@@ -0,0 +1,494 @@
|
|||||||
|
import path from "path"
|
||||||
|
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
||||||
|
import { useApi } from "../../../../environment-helpers/use-api"
|
||||||
|
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
||||||
|
|
||||||
|
import productSeeder from "../../../../helpers/product-seeder"
|
||||||
|
|
||||||
|
import { AxiosInstance } from "axios"
|
||||||
|
import { getContainer } from "../../../../environment-helpers/use-container"
|
||||||
|
import {
|
||||||
|
simpleProductFactory,
|
||||||
|
simpleSalesChannelFactory,
|
||||||
|
} from "../../../../factories"
|
||||||
|
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||||
|
import { createAdminUser } from "../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
const adminHeaders = {
|
||||||
|
headers: {
|
||||||
|
"x-medusa-access-token": "test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = {
|
||||||
|
MEDUSA_FF_MEDUSA_V2: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("/admin/products", () => {
|
||||||
|
let dbConnection
|
||||||
|
let shutdownServer
|
||||||
|
let medusaContainer
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd, env })
|
||||||
|
shutdownServer = await startBootstrapApp({ cwd, env })
|
||||||
|
medusaContainer = getContainer()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
await shutdownServer()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/products", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createAdminUser(dbConnection, adminHeaders)
|
||||||
|
|
||||||
|
// await productSeeder(dbConnection)
|
||||||
|
// await createDefaultRuleTypes(medusaContainer)
|
||||||
|
// await simpleSalesChannelFactory(dbConnection, {
|
||||||
|
// name: "Default channel",
|
||||||
|
// id: "default-channel",
|
||||||
|
// is_default: true,
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a product", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "Test",
|
||||||
|
description: "test-product-description",
|
||||||
|
// type: { value: "test-type" },
|
||||||
|
images: ["test-image.png", "test-image-2.png"],
|
||||||
|
// collection_id: "test-collection",
|
||||||
|
// tags: [{ value: "123" }, { value: "456" }],
|
||||||
|
options: [{ title: "size" }, { title: "color" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [
|
||||||
|
// {
|
||||||
|
// currency_code: "usd",
|
||||||
|
// amount: 100,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// currency_code: "eur",
|
||||||
|
// amount: 45,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// currency_code: "dkk",
|
||||||
|
// amount: 30,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post("/admin/products", payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^prod_*/),
|
||||||
|
title: "Test",
|
||||||
|
discountable: true,
|
||||||
|
is_giftcard: false,
|
||||||
|
handle: "test",
|
||||||
|
status: "draft",
|
||||||
|
// profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
thumbnail: "test-image.png",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response?.data.product.images).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
url: "test-image.png",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
url: "test-image-2.png",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(response?.data.product)
|
||||||
|
|
||||||
|
expect(response?.data.product.variants).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^variant_*/),
|
||||||
|
title: "Test variant",
|
||||||
|
// product_id: expect.stringMatching(/^prod_*/),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
// prices: expect.arrayContaining([
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.stringMatching(/^ma_*/),
|
||||||
|
// currency_code: "usd",
|
||||||
|
// amount: 100,
|
||||||
|
// // TODO: enable this in the Pricing Module PR
|
||||||
|
// // created_at: expect.any(String),
|
||||||
|
// // updated_at: expect.any(String),
|
||||||
|
// // variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
// }),
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.stringMatching(/^ma_*/),
|
||||||
|
// currency_code: "eur",
|
||||||
|
// amount: 45,
|
||||||
|
// // TODO: enable this in the Pricing Module PR
|
||||||
|
// // created_at: expect.any(String),
|
||||||
|
// // updated_at: expect.any(String),
|
||||||
|
// // variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
// }),
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.stringMatching(/^ma_*/),
|
||||||
|
// currency_code: "dkk",
|
||||||
|
// amount: 30,
|
||||||
|
// // TODO: enable this in the Pricing Module PR
|
||||||
|
// // created_at: expect.any(String),
|
||||||
|
// // updated_at: expect.any(String),
|
||||||
|
// // variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
// }),
|
||||||
|
// ]),
|
||||||
|
// options: expect.arrayContaining([
|
||||||
|
// expect.objectContaining({
|
||||||
|
// value: "large",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
// option_id: expect.stringMatching(/^opt_*/),
|
||||||
|
// id: expect.stringMatching(/^optval_*/),
|
||||||
|
// }),
|
||||||
|
// expect.objectContaining({
|
||||||
|
// value: "green",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
// option_id: expect.stringMatching(/^opt_*/),
|
||||||
|
// id: expect.stringMatching(/^optval_*/),
|
||||||
|
// }),
|
||||||
|
// ]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response?.data.product.options).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^opt_*/),
|
||||||
|
// product_id: expect.stringMatching(/^prod_*/),
|
||||||
|
title: "size",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^opt_*/),
|
||||||
|
// product_id: expect.stringMatching(/^prod_*/),
|
||||||
|
title: "color",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
// tags: expect.arrayContaining([
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.any(String),
|
||||||
|
// value: "123",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// }),
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.any(String),
|
||||||
|
// value: "456",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// }),
|
||||||
|
// ]),
|
||||||
|
// type: expect.objectContaining({
|
||||||
|
// value: "test-type",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// }),
|
||||||
|
// collection: expect.objectContaining({
|
||||||
|
// id: "test-collection",
|
||||||
|
// title: "Test collection",
|
||||||
|
// created_at: expect.any(String),
|
||||||
|
// updated_at: expect.any(String),
|
||||||
|
// }),
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a product that is not discountable", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "Test",
|
||||||
|
discountable: false,
|
||||||
|
description: "test-product-description",
|
||||||
|
// type: { value: "test-type" },
|
||||||
|
images: ["test-image.png", "test-image-2.png"],
|
||||||
|
// collection_id: "test-collection",
|
||||||
|
// tags: [{ value: "123" }, { value: "456" }],
|
||||||
|
options: [{ title: "size" }, { title: "color" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post("/admin/products", payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
discountable: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should sets the variant ranks when creating a product", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "Test product - 1",
|
||||||
|
description: "test-product-description 1",
|
||||||
|
// type: { value: "test-type 1" },
|
||||||
|
images: ["test-image.png", "test-image-2.png"],
|
||||||
|
// collection_id: "test-collection",
|
||||||
|
// tags: [{ value: "123" }, { value: "456" }],
|
||||||
|
options: [{ title: "size" }, { title: "color" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant 1",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test variant 2",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const creationResponse = await api
|
||||||
|
.post("/admin/products", payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(creationResponse?.status).toEqual(200)
|
||||||
|
|
||||||
|
const productId = creationResponse?.data.product.id
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get(
|
||||||
|
`/admin/products/${productId}?fields=title,variants.title`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Test product - 1",
|
||||||
|
variants: [
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Test variant 1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Test variant 2",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a giftcard", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "Test Giftcard",
|
||||||
|
is_giftcard: true,
|
||||||
|
description: "test-giftcard-description",
|
||||||
|
options: [{ title: "Denominations" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "100" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post("/admin/products", payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Test Giftcard",
|
||||||
|
discountable: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create variants with inventory items", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/products`,
|
||||||
|
{
|
||||||
|
title: "Test product - 1",
|
||||||
|
description: "test-product-description 1",
|
||||||
|
// type: { value: "test-type 1" },
|
||||||
|
images: ["test-image.png", "test-image-2.png"],
|
||||||
|
// collection_id: "test-collection",
|
||||||
|
// tags: [{ value: "123" }, { value: "456" }],
|
||||||
|
options: [{ title: "size" }, { title: "color" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant 1",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test variant 2",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
// prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
// options: [{ value: "large" }, { value: "green" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
|
// const variantIds = response.data.product.variants.map(
|
||||||
|
// (v: { id: string }) => v.id
|
||||||
|
// )
|
||||||
|
|
||||||
|
// const variantInventoryService = medusaContainer.resolve(
|
||||||
|
// "productVariantInventoryService"
|
||||||
|
// )
|
||||||
|
// const inventory = await variantInventoryService.listByVariant(variantIds)
|
||||||
|
|
||||||
|
// expect(inventory).toHaveLength(2)
|
||||||
|
// expect(inventory).toContainEqual(
|
||||||
|
// expect.objectContaining({
|
||||||
|
// variant_id: variantIds[0],
|
||||||
|
// required_quantity: 1,
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// expect(inventory).toContainEqual(
|
||||||
|
// expect.objectContaining({
|
||||||
|
// variant_id: variantIds[1],
|
||||||
|
// required_quantity: 1,
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
})
|
||||||
|
|
||||||
|
// it("should create prices with region_id and currency_code context", async () => {
|
||||||
|
// const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
// const data = {
|
||||||
|
// title: "test product",
|
||||||
|
// options: [{ title: "test-option" }],
|
||||||
|
// variants: [
|
||||||
|
// {
|
||||||
|
// title: "test variant",
|
||||||
|
// prices: [
|
||||||
|
// {
|
||||||
|
// amount: 66600,
|
||||||
|
// region_id: "test-region",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// amount: 55500,
|
||||||
|
// currency_code: "usd",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// options: [{ value: "test-option" }],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let response = await api.post(
|
||||||
|
// "/admin/products?relations=variants.prices",
|
||||||
|
// data,
|
||||||
|
// adminHeaders
|
||||||
|
// )
|
||||||
|
|
||||||
|
// expect(response.status).toEqual(200)
|
||||||
|
// expect(response.data).toEqual({
|
||||||
|
// product: expect.objectContaining({
|
||||||
|
// id: expect.any(String),
|
||||||
|
// title: "test product",
|
||||||
|
// variants: expect.arrayContaining([
|
||||||
|
// expect.objectContaining({
|
||||||
|
// id: expect.any(String),
|
||||||
|
// title: "test variant",
|
||||||
|
// prices: expect.arrayContaining([
|
||||||
|
// expect.objectContaining({
|
||||||
|
// amount: 66600,
|
||||||
|
// currency_code: "usd",
|
||||||
|
// }),
|
||||||
|
// expect.objectContaining({
|
||||||
|
// amount: 55500,
|
||||||
|
// currency_code: "usd",
|
||||||
|
// }),
|
||||||
|
// ]),
|
||||||
|
// }),
|
||||||
|
// ]),
|
||||||
|
// }),
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const pricingModuleService: IPricingModuleService = appContainer.resolve(
|
||||||
|
// "pricingModuleService"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// const [_, count] = await pricingModuleService.listAndCount()
|
||||||
|
// expect(count).toEqual(1)
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
|
||||||
|
|
||||||
import { Region } from "@medusajs/medusa"
|
|
||||||
import { IPricingModuleService } from "@medusajs/types"
|
|
||||||
import { AxiosInstance } from "axios"
|
|
||||||
import path from "path"
|
|
||||||
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
|
||||||
import { useApi } from "../../../../environment-helpers/use-api"
|
|
||||||
import { getContainer } from "../../../../environment-helpers/use-container"
|
|
||||||
import { simpleSalesChannelFactory } from "../../../../factories"
|
|
||||||
import adminSeeder from "../../../../helpers/admin-seeder"
|
|
||||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
|
||||||
|
|
||||||
const adminHeaders = {
|
|
||||||
headers: {
|
|
||||||
"x-medusa-access-token": "test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = {
|
|
||||||
MEDUSA_FF_MEDUSA_V2: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
describe.skip("POST /admin/products", () => {
|
|
||||||
let dbConnection
|
|
||||||
let appContainer
|
|
||||||
let shutdownServer
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
|
||||||
dbConnection = await initDb({ cwd, env } as any)
|
|
||||||
shutdownServer = await startBootstrapApp({ cwd, env })
|
|
||||||
appContainer = getContainer()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.shutdown()
|
|
||||||
await shutdownServer()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const manager = dbConnection.manager
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await createDefaultRuleTypes(appContainer)
|
|
||||||
|
|
||||||
await manager.insert(Region, {
|
|
||||||
id: "test-region",
|
|
||||||
name: "Test Region",
|
|
||||||
currency_code: "usd",
|
|
||||||
tax_rate: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleSalesChannelFactory(dbConnection, { is_default: true })
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create prices with region_id and currency_code context", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
title: "test product",
|
|
||||||
options: [{ title: "test-option" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "test variant",
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
amount: 66600,
|
|
||||||
region_id: "test-region",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
amount: 55500,
|
|
||||||
currency_code: "usd",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [{ value: "test-option" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = await api.post(
|
|
||||||
"/admin/products?relations=variants.prices",
|
|
||||||
data,
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
product: expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
title: "test product",
|
|
||||||
variants: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
title: "test variant",
|
|
||||||
prices: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
amount: 66600,
|
|
||||||
currency_code: "usd",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
amount: 55500,
|
|
||||||
currency_code: "usd",
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
const pricingModuleService: IPricingModuleService = appContainer.resolve(
|
|
||||||
"pricingModuleService"
|
|
||||||
)
|
|
||||||
|
|
||||||
const [_, count] = await pricingModuleService.listAndCount()
|
|
||||||
expect(count).toEqual(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -21,7 +21,13 @@ const adminReqConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getImportFile() {
|
function getImportFile() {
|
||||||
return path.resolve("__tests__", "product", "admin", "product-import.csv")
|
return path.resolve(
|
||||||
|
"__tests__",
|
||||||
|
"product",
|
||||||
|
"admin",
|
||||||
|
"__fixtures__",
|
||||||
|
"product-import.csv"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyTemplateFile() {
|
function copyTemplateFile() {
|
||||||
@@ -29,6 +35,7 @@ function copyTemplateFile() {
|
|||||||
"__tests__",
|
"__tests__",
|
||||||
"product",
|
"product",
|
||||||
"admin",
|
"admin",
|
||||||
|
"__fixtures__",
|
||||||
"product-import-template.csv"
|
"product-import-template.csv"
|
||||||
)
|
)
|
||||||
const destination = getImportFile()
|
const destination = getImportFile()
|
||||||
|
|||||||
@@ -1,655 +0,0 @@
|
|||||||
import path from "path"
|
|
||||||
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
|
|
||||||
import { useApi } from "../../../../environment-helpers/use-api"
|
|
||||||
import { initDb, useDb } from "../../../../environment-helpers/use-db"
|
|
||||||
|
|
||||||
import adminSeeder from "../../../../helpers/admin-seeder"
|
|
||||||
import productSeeder from "../../../../helpers/product-seeder"
|
|
||||||
|
|
||||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
|
||||||
import { MedusaV2Flag } from "@medusajs/utils"
|
|
||||||
import { AxiosInstance } from "axios"
|
|
||||||
import { getContainer } from "../../../../environment-helpers/use-container"
|
|
||||||
import {
|
|
||||||
simpleProductFactory,
|
|
||||||
simpleSalesChannelFactory,
|
|
||||||
} from "../../../../factories"
|
|
||||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
|
||||||
|
|
||||||
const adminHeaders = {
|
|
||||||
headers: {
|
|
||||||
"x-medusa-access-token": "test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = {
|
|
||||||
MEDUSA_FF_MEDUSA_V2: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
describe.skip("/admin/products", () => {
|
|
||||||
let dbConnection
|
|
||||||
let shutdownServer
|
|
||||||
let medusaContainer
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
|
||||||
dbConnection = await initDb({ cwd, env })
|
|
||||||
shutdownServer = await startBootstrapApp({ cwd, env })
|
|
||||||
medusaContainer = getContainer()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.shutdown()
|
|
||||||
await shutdownServer()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("Should have loaded the product module", function () {
|
|
||||||
const productRegistrationName =
|
|
||||||
ModulesDefinition[Modules.PRODUCT].registrationName
|
|
||||||
expect(
|
|
||||||
medusaContainer.hasRegistration(productRegistrationName)
|
|
||||||
).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("Should have enabled workflows feature flag", function () {
|
|
||||||
const flagRouter = medusaContainer.resolve("featureFlagRouter")
|
|
||||||
|
|
||||||
const workflowsFlag = flagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
|
||||||
|
|
||||||
expect(workflowsFlag).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/products", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await productSeeder(dbConnection)
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await createDefaultRuleTypes(medusaContainer)
|
|
||||||
|
|
||||||
await simpleSalesChannelFactory(dbConnection, {
|
|
||||||
name: "Default channel",
|
|
||||||
id: "default-channel",
|
|
||||||
is_default: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create a product", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "Test",
|
|
||||||
description: "test-product-description",
|
|
||||||
type: { value: "test-type" },
|
|
||||||
images: ["test-image.png", "test-image-2.png"],
|
|
||||||
collection_id: "test-collection",
|
|
||||||
tags: [{ value: "123" }, { value: "456" }],
|
|
||||||
options: [{ title: "size" }, { title: "color" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "Test variant",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
currency_code: "usd",
|
|
||||||
amount: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
currency_code: "eur",
|
|
||||||
amount: 45,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
currency_code: "dkk",
|
|
||||||
amount: 30,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post("/admin/products", payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^prod_*/),
|
|
||||||
title: "Test",
|
|
||||||
discountable: true,
|
|
||||||
is_giftcard: false,
|
|
||||||
handle: "test",
|
|
||||||
status: "draft",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
|
||||||
images: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
url: "test-image.png",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
url: "test-image-2.png",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
thumbnail: "test-image.png",
|
|
||||||
tags: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
value: "123",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
value: "456",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
type: expect.objectContaining({
|
|
||||||
value: "test-type",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
collection: expect.objectContaining({
|
|
||||||
id: "test-collection",
|
|
||||||
title: "Test collection",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
options: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^opt_*/),
|
|
||||||
product_id: expect.stringMatching(/^prod_*/),
|
|
||||||
title: "size",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^opt_*/),
|
|
||||||
product_id: expect.stringMatching(/^prod_*/),
|
|
||||||
title: "color",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
variants: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^variant_*/),
|
|
||||||
product_id: expect.stringMatching(/^prod_*/),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
title: "Test variant",
|
|
||||||
prices: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^ma_*/),
|
|
||||||
currency_code: "usd",
|
|
||||||
amount: 100,
|
|
||||||
// TODO: enable this in the Pricing Module PR
|
|
||||||
// created_at: expect.any(String),
|
|
||||||
// updated_at: expect.any(String),
|
|
||||||
// variant_id: expect.stringMatching(/^variant_*/),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^ma_*/),
|
|
||||||
currency_code: "eur",
|
|
||||||
amount: 45,
|
|
||||||
// TODO: enable this in the Pricing Module PR
|
|
||||||
// created_at: expect.any(String),
|
|
||||||
// updated_at: expect.any(String),
|
|
||||||
// variant_id: expect.stringMatching(/^variant_*/),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.stringMatching(/^ma_*/),
|
|
||||||
currency_code: "dkk",
|
|
||||||
amount: 30,
|
|
||||||
// TODO: enable this in the Pricing Module PR
|
|
||||||
// created_at: expect.any(String),
|
|
||||||
// updated_at: expect.any(String),
|
|
||||||
// variant_id: expect.stringMatching(/^variant_*/),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
options: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
value: "large",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
variant_id: expect.stringMatching(/^variant_*/),
|
|
||||||
option_id: expect.stringMatching(/^opt_*/),
|
|
||||||
id: expect.stringMatching(/^optval_*/),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
value: "green",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
variant_id: expect.stringMatching(/^variant_*/),
|
|
||||||
option_id: expect.stringMatching(/^opt_*/),
|
|
||||||
id: expect.stringMatching(/^optval_*/),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create a product that is not discountable", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "Test",
|
|
||||||
discountable: false,
|
|
||||||
description: "test-product-description",
|
|
||||||
type: { value: "test-type" },
|
|
||||||
images: ["test-image.png", "test-image-2.png"],
|
|
||||||
collection_id: "test-collection",
|
|
||||||
tags: [{ value: "123" }, { value: "456" }],
|
|
||||||
options: [{ title: "size" }, { title: "color" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "Test variant",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post("/admin/products", payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
discountable: false,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should sets the variant ranks when creating a product", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "Test product - 1",
|
|
||||||
description: "test-product-description 1",
|
|
||||||
type: { value: "test-type 1" },
|
|
||||||
images: ["test-image.png", "test-image-2.png"],
|
|
||||||
collection_id: "test-collection",
|
|
||||||
tags: [{ value: "123" }, { value: "456" }],
|
|
||||||
options: [{ title: "size" }, { title: "color" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "Test variant 1",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test variant 2",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const creationResponse = await api
|
|
||||||
.post("/admin/products", payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(creationResponse?.status).toEqual(200)
|
|
||||||
|
|
||||||
const productId = creationResponse?.data.product.id
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.get(`/admin/products/${productId}`, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Test product - 1",
|
|
||||||
variants: [
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Test variant 1",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Test variant 2",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create a giftcard", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "Test Giftcard",
|
|
||||||
is_giftcard: true,
|
|
||||||
description: "test-giftcard-description",
|
|
||||||
options: [{ title: "Denominations" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "Test variant",
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "100" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post("/admin/products", payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Test Giftcard",
|
|
||||||
discountable: false,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create variants with inventory items", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const response = await api.post(
|
|
||||||
`/admin/products`,
|
|
||||||
{
|
|
||||||
title: "Test product - 1",
|
|
||||||
description: "test-product-description 1",
|
|
||||||
type: { value: "test-type 1" },
|
|
||||||
images: ["test-image.png", "test-image-2.png"],
|
|
||||||
collection_id: "test-collection",
|
|
||||||
tags: [{ value: "123" }, { value: "456" }],
|
|
||||||
options: [{ title: "size" }, { title: "color" }],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
title: "Test variant 1",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test variant 2",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
prices: [{ currency_code: "usd", amount: 100 }],
|
|
||||||
options: [{ value: "large" }, { value: "green" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ headers: { "x-medusa-access-token": "test_token" } }
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
|
|
||||||
const variantIds = response.data.product.variants.map(
|
|
||||||
(v: { id: string }) => v.id
|
|
||||||
)
|
|
||||||
|
|
||||||
const variantInventoryService = medusaContainer.resolve(
|
|
||||||
"productVariantInventoryService"
|
|
||||||
)
|
|
||||||
const inventory = await variantInventoryService.listByVariant(variantIds)
|
|
||||||
|
|
||||||
expect(inventory).toHaveLength(2)
|
|
||||||
expect(inventory).toContainEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
variant_id: variantIds[0],
|
|
||||||
required_quantity: 1,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
expect(inventory).toContainEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
variant_id: variantIds[1],
|
|
||||||
required_quantity: 1,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/products/:id", () => {
|
|
||||||
const toUpdateWithSalesChannels = "to-update-with-sales-channels"
|
|
||||||
const toUpdateWithVariants = "to-update-with-variants"
|
|
||||||
const toUpdate = "to-update"
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await productSeeder(dbConnection)
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await createDefaultRuleTypes(medusaContainer)
|
|
||||||
|
|
||||||
await simpleSalesChannelFactory(dbConnection, {
|
|
||||||
name: "Default channel",
|
|
||||||
id: "default-channel",
|
|
||||||
is_default: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleSalesChannelFactory(dbConnection, {
|
|
||||||
name: "Channel 3",
|
|
||||||
id: "channel-3",
|
|
||||||
is_default: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleProductFactory(dbConnection, {
|
|
||||||
title: "To update product",
|
|
||||||
id: toUpdate,
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleProductFactory(dbConnection, {
|
|
||||||
title: "To update product with channels",
|
|
||||||
id: toUpdateWithSalesChannels,
|
|
||||||
sales_channels: [
|
|
||||||
{ name: "channel 1", id: "channel-1" },
|
|
||||||
{ name: "channel 2", id: "channel-2" },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleSalesChannelFactory(dbConnection, {
|
|
||||||
name: "To be added",
|
|
||||||
id: "to-be-added",
|
|
||||||
})
|
|
||||||
|
|
||||||
await simpleProductFactory(dbConnection, {
|
|
||||||
title: "To update product with variants",
|
|
||||||
id: toUpdateWithVariants,
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
id: "variant-1",
|
|
||||||
title: "Variant 1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "variant-2",
|
|
||||||
title: "Variant 2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should do a basic product update", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post(`/admin/products/${toUpdate}`, payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: toUpdate,
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update product and also update a variant and create a variant", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
id: "variant-1",
|
|
||||||
title: "Variant 1 updated",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Variant 3",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post(`/admin/products/${toUpdateWithVariants}`, payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: toUpdateWithVariants,
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
variants: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "variant-1",
|
|
||||||
title: "Variant 1 updated",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Variant 3",
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update product's sales channels", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
sales_channels: [{ id: "channel-2" }, { id: "channel-3" }],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post(
|
|
||||||
`/admin/products/${toUpdateWithSalesChannels}?expand=sales_channels`,
|
|
||||||
payload,
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: toUpdateWithSalesChannels,
|
|
||||||
sales_channels: [
|
|
||||||
expect.objectContaining({ id: "channel-2" }),
|
|
||||||
expect.objectContaining({ id: "channel-3" }),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update inventory when variants are updated", async () => {
|
|
||||||
const api = useApi()! as AxiosInstance
|
|
||||||
|
|
||||||
const variantInventoryService = medusaContainer.resolve(
|
|
||||||
"productVariantInventoryService"
|
|
||||||
)
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
id: "variant-1",
|
|
||||||
title: "Variant 1 updated",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Variant 3",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post(`/admin/products/${toUpdateWithVariants}`, payload, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
let inventory = await variantInventoryService.listInventoryItemsByVariant(
|
|
||||||
"variant-2"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response?.status).toEqual(200)
|
|
||||||
expect(response?.data.product).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: toUpdateWithVariants,
|
|
||||||
title: "New title",
|
|
||||||
description: "test-product-description",
|
|
||||||
variants: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "variant-1",
|
|
||||||
title: "Variant 1 updated",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
title: "Variant 3",
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(inventory).toEqual([]) // no inventory items for removed variant
|
|
||||||
|
|
||||||
inventory = await variantInventoryService.listInventoryItemsByVariant(
|
|
||||||
response?.data.product.variants.find((v) => v.title === "Variant 3").id
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(inventory).toEqual([
|
|
||||||
expect.objectContaining({ id: expect.any(String) }),
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -78,6 +78,163 @@ describe.skip("POST /admin/products/:id", () => {
|
|||||||
await db.teardown()
|
await db.teardown()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should do a basic product update", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/admin/products/${product.id}`, payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: product.id,
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update product and also update a variant and create a variant", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: "variant-1",
|
||||||
|
title: "Variant 1 updated",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Variant 3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/admin/products/${product.id}`, payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: product.id,
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
variants: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "variant-1",
|
||||||
|
title: "Variant 1 updated",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Variant 3",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update product's sales channels", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
sales_channels: [{ id: "channel-2" }, { id: "channel-3" }],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
`/admin/products/${product.id}?expand=sales_channels`,
|
||||||
|
payload,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: product.id,
|
||||||
|
sales_channels: [
|
||||||
|
expect.objectContaining({ id: "channel-2" }),
|
||||||
|
expect.objectContaining({ id: "channel-3" }),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update inventory when variants are updated", async () => {
|
||||||
|
const api = useApi()! as AxiosInstance
|
||||||
|
|
||||||
|
const variantInventoryService = appContainer.resolve(
|
||||||
|
"productVariantInventoryService"
|
||||||
|
)
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: "variant-1",
|
||||||
|
title: "Variant 1 updated",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Variant 3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/admin/products/${product.id}`, payload, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
let inventory = await variantInventoryService.listInventoryItemsByVariant(
|
||||||
|
"variant-2"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response?.status).toEqual(200)
|
||||||
|
expect(response?.data.product).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: product.id,
|
||||||
|
title: "New title",
|
||||||
|
description: "test-product-description",
|
||||||
|
variants: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "variant-1",
|
||||||
|
title: "Variant 1 updated",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "Variant 3",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(inventory).toEqual([]) // no inventory items for removed variant
|
||||||
|
|
||||||
|
inventory = await variantInventoryService.listInventoryItemsByVariant(
|
||||||
|
response?.data.product.variants.find((v) => v.title === "Variant 3").id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(inventory).toEqual([
|
||||||
|
expect.objectContaining({ id: expect.any(String) }),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it("should update product variant price sets and prices", async () => {
|
it("should update product variant price sets and prices", async () => {
|
||||||
const api = useApi() as any
|
const api = useApi() as any
|
||||||
const data = {
|
const data = {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
|
|
||||||
import { UpdateProductDTO } from "@medusajs/types"
|
import { UpdateProductDTO } from "@medusajs/types"
|
||||||
import { defaultAdminProductsOptionFields } from "../../../query-config"
|
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
@@ -26,7 +25,7 @@ export const GET = async (
|
|||||||
const queryObject = remoteQueryObjectFromString({
|
const queryObject = remoteQueryObjectFromString({
|
||||||
entryPoint: "product_option",
|
entryPoint: "product_option",
|
||||||
variables,
|
variables,
|
||||||
fields: defaultAdminProductsOptionFields,
|
fields: req.retrieveConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const [product_option] = await remoteQuery(queryObject)
|
const [product_option] = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
|
|
||||||
import { CreateProductOptionDTO } from "@medusajs/types"
|
import { CreateProductOptionDTO } from "@medusajs/types"
|
||||||
import { createProductOptionsWorkflow } from "@medusajs/core-flows"
|
import { createProductOptionsWorkflow } from "@medusajs/core-flows"
|
||||||
import { defaultAdminProductsOptionFields } from "../../query-config"
|
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
@@ -23,7 +22,7 @@ export const GET = async (
|
|||||||
skip: req.listConfig.skip,
|
skip: req.listConfig.skip,
|
||||||
take: req.listConfig.take,
|
take: req.listConfig.take,
|
||||||
},
|
},
|
||||||
fields: defaultAdminProductsOptionFields,
|
fields: req.listConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const { rows: product_options, metadata } = await remoteQuery(queryObject)
|
const { rows: product_options, metadata } = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
|
|
||||||
import { UpdateProductDTO } from "@medusajs/types"
|
import { UpdateProductDTO } from "@medusajs/types"
|
||||||
import { defaultAdminProductFields } from "../query-config"
|
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
@@ -22,7 +21,7 @@ export const GET = async (
|
|||||||
const queryObject = remoteQueryObjectFromString({
|
const queryObject = remoteQueryObjectFromString({
|
||||||
entryPoint: "product",
|
entryPoint: "product",
|
||||||
variables,
|
variables,
|
||||||
fields: defaultAdminProductFields,
|
fields: req.retrieveConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const [product] = await remoteQuery(queryObject)
|
const [product] = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const GET = async (
|
|||||||
const queryObject = remoteQueryObjectFromString({
|
const queryObject = remoteQueryObjectFromString({
|
||||||
entryPoint: "product_variant",
|
entryPoint: "product_variant",
|
||||||
variables,
|
variables,
|
||||||
fields: defaultAdminProductsVariantFields,
|
fields: req.retrieveConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const [product_variant] = await remoteQuery(queryObject)
|
const [product_variant] = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
|
|
||||||
import { CreateProductVariantDTO } from "@medusajs/types"
|
import { CreateProductVariantDTO } from "@medusajs/types"
|
||||||
import { createProductVariantsWorkflow } from "@medusajs/core-flows"
|
import { createProductVariantsWorkflow } from "@medusajs/core-flows"
|
||||||
import { defaultAdminProductsVariantFields } from "../../query-config"
|
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
@@ -23,7 +22,7 @@ export const GET = async (
|
|||||||
skip: req.listConfig.skip,
|
skip: req.listConfig.skip,
|
||||||
take: req.listConfig.take,
|
take: req.listConfig.take,
|
||||||
},
|
},
|
||||||
fields: defaultAdminProductsVariantFields,
|
fields: req.listConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const { rows: product_variants, metadata } = await remoteQuery(queryObject)
|
const { rows: product_variants, metadata } = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
transformQuery(
|
||||||
AdminGetProductsVariantsParams,
|
AdminGetProductsVariantsParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.listVariantConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -79,7 +79,7 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
transformQuery(
|
||||||
AdminGetProductsProductVariantsVariantParams,
|
AdminGetProductsProductVariantsVariantParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveVariantConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -106,7 +106,7 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
transformQuery(
|
||||||
AdminGetProductsOptionsParams,
|
AdminGetProductsOptionsParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.listOptionConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -117,7 +117,7 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
transformQuery(
|
||||||
AdminGetProductsProductOptionsOptionParams,
|
AdminGetProductsProductOptionsOptionParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveOptionConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export const defaultAdminProductRelations = [
|
export const allowedAdminProductRelations = [
|
||||||
"variants",
|
"variants",
|
||||||
// TODO: Add in next iteration
|
// TODO: Add in next iteration
|
||||||
// "variants.prices",
|
// "variants.prices",
|
||||||
@@ -15,7 +15,7 @@ export const defaultAdminProductRelations = [
|
|||||||
// "type",
|
// "type",
|
||||||
// "collection",
|
// "collection",
|
||||||
]
|
]
|
||||||
export const allowedAdminProductRelations = [...defaultAdminProductRelations]
|
export const defaultAdminProductRelations = []
|
||||||
export const defaultAdminProductFields = [
|
export const defaultAdminProductFields = [
|
||||||
"id",
|
"id",
|
||||||
"title",
|
"title",
|
||||||
@@ -52,6 +52,7 @@ export const retrieveTransformQueryConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const listTransformQueryConfig = {
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
defaultLimit: 50,
|
defaultLimit: 50,
|
||||||
isList: true,
|
isList: true,
|
||||||
}
|
}
|
||||||
@@ -82,4 +83,30 @@ export const defaultAdminProductsVariantFields = [
|
|||||||
"barcode",
|
"barcode",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const retrieveVariantConfig = {
|
||||||
|
defaultFields: defaultAdminProductsVariantFields,
|
||||||
|
defaultRelations: [],
|
||||||
|
allowedRelations: [],
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listVariantConfig = {
|
||||||
|
...retrieveVariantConfig,
|
||||||
|
defaultLimit: 50,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
|
|
||||||
export const defaultAdminProductsOptionFields = ["id", "title"]
|
export const defaultAdminProductsOptionFields = ["id", "title"]
|
||||||
|
|
||||||
|
export const retrieveOptionConfig = {
|
||||||
|
defaultFields: defaultAdminProductsOptionFields,
|
||||||
|
defaultRelations: [],
|
||||||
|
allowedRelations: [],
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listOptionConfig = {
|
||||||
|
...retrieveVariantConfig,
|
||||||
|
defaultLimit: 50,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
|
|
||||||
import { CreateProductDTO } from "@medusajs/types"
|
import { CreateProductDTO } from "@medusajs/types"
|
||||||
import { createProductsWorkflow } from "@medusajs/core-flows"
|
import { createProductsWorkflow } from "@medusajs/core-flows"
|
||||||
import { defaultAdminProductFields } from "./query-config"
|
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
@@ -22,7 +21,7 @@ export const GET = async (
|
|||||||
skip: req.listConfig.skip,
|
skip: req.listConfig.skip,
|
||||||
take: req.listConfig.take,
|
take: req.listConfig.take,
|
||||||
},
|
},
|
||||||
fields: defaultAdminProductFields,
|
fields: req.listConfig.select as string[],
|
||||||
})
|
})
|
||||||
|
|
||||||
const { rows: products, metadata } = await remoteQuery(queryObject)
|
const { rows: products, metadata } = await remoteQuery(queryObject)
|
||||||
|
|||||||
@@ -551,9 +551,10 @@ export default class ProductModuleService<
|
|||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<ProductTypes.ProductDTO[]> {
|
): Promise<ProductTypes.ProductDTO[]> {
|
||||||
const products = await this.create_(data, sharedContext)
|
const products = await this.create_(data, sharedContext)
|
||||||
|
|
||||||
const createdProducts = await this.baseRepository_.serialize<
|
const createdProducts = await this.baseRepository_.serialize<
|
||||||
ProductTypes.ProductDTO[]
|
ProductTypes.ProductDTO[]
|
||||||
>(products)
|
>(products, { populate: true })
|
||||||
|
|
||||||
await this.eventBusModuleService_?.emit<ProductEventData>(
|
await this.eventBusModuleService_?.emit<ProductEventData>(
|
||||||
createdProducts.map(({ id }) => ({
|
createdProducts.map(({ id }) => ({
|
||||||
@@ -692,6 +693,14 @@ export default class ProductModuleService<
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: An ugly hack to populate the options in the entity map. The options and variants are created independently of the product create request,
|
||||||
|
// so they are not populated in the response. Refactor the create method so this is no longer necessary
|
||||||
|
await this.productOptionService_.list(
|
||||||
|
{ id: productOptions.map((po) => po.id) },
|
||||||
|
{ take: null },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
return products
|
return products
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user