feat(products,types,pricing): allow scoping products by collection_id + pricing by currency_code (#4965)
* chore: allow scoping products by collection_id * chore: scope money amounts by currency code + change category_ids to category_id * chore: add an extra product to test without collection --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
1 parent
b71776738c
commit
66bd9a835c
11 files changed
+438
-140
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/product": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
"@medusajs/pricing": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(products,types,pricing): allow scoping products by collection_id, allow scoping pricing by currency_code
|
||||||
@@ -39,7 +39,7 @@ describe("MoneyAmount Service", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("list", () => {
|
describe("list", () => {
|
||||||
it("list moneyAmounts", async () => {
|
it("should list all moneyAmounts", async () => {
|
||||||
const moneyAmountsResult = await service.list()
|
const moneyAmountsResult = await service.list()
|
||||||
|
|
||||||
expect(moneyAmountsResult).toEqual([
|
expect(moneyAmountsResult).toEqual([
|
||||||
@@ -58,7 +58,7 @@ describe("MoneyAmount Service", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("list moneyAmounts by id", async () => {
|
it("should list moneyAmounts by id", async () => {
|
||||||
const moneyAmountsResult = await service.list({
|
const moneyAmountsResult = await service.list({
|
||||||
id: ["money-amount-USD"],
|
id: ["money-amount-USD"],
|
||||||
})
|
})
|
||||||
@@ -70,7 +70,7 @@ describe("MoneyAmount Service", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("list moneyAmounts with relations and selects", async () => {
|
it("should list moneyAmounts with relations and selects", async () => {
|
||||||
const moneyAmountsResult = await service.list(
|
const moneyAmountsResult = await service.list(
|
||||||
{
|
{
|
||||||
id: ["money-amount-USD"],
|
id: ["money-amount-USD"],
|
||||||
@@ -94,6 +94,31 @@ describe("MoneyAmount Service", () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should list moneyAmounts scoped by currency_code", async () => {
|
||||||
|
const moneyAmountsResult = await service.list(
|
||||||
|
{
|
||||||
|
currency_code: ["USD"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: ["id", "min_quantity", "currency.code"],
|
||||||
|
relations: ["currency"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const serialized = JSON.parse(JSON.stringify(moneyAmountsResult))
|
||||||
|
|
||||||
|
expect(serialized).toEqual([
|
||||||
|
{
|
||||||
|
id: "money-amount-USD",
|
||||||
|
min_quantity: "1",
|
||||||
|
currency_code: "USD",
|
||||||
|
currency: {
|
||||||
|
code: "USD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("listAndCount", () => {
|
describe("listAndCount", () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ProductTypes } from "@medusajs/types"
|
import { ProductTypes } from "@medusajs/types"
|
||||||
import faker from "faker"
|
|
||||||
import { Image } from "@models"
|
import { Image } from "@models"
|
||||||
|
import faker from "faker"
|
||||||
|
|
||||||
export const buildProductOnlyData = ({
|
export const buildProductOnlyData = ({
|
||||||
title,
|
title,
|
||||||
@@ -46,6 +46,7 @@ export const buildProductAndRelationsData = ({
|
|||||||
tags,
|
tags,
|
||||||
options,
|
options,
|
||||||
variants,
|
variants,
|
||||||
|
collection_id,
|
||||||
}: Partial<ProductTypes.CreateProductDTO>) => {
|
}: Partial<ProductTypes.CreateProductDTO>) => {
|
||||||
const defaultOptionTitle = faker.commerce.productName()
|
const defaultOptionTitle = faker.commerce.productName()
|
||||||
return {
|
return {
|
||||||
@@ -59,6 +60,7 @@ export const buildProductAndRelationsData = ({
|
|||||||
images: (images ?? []) as Image[],
|
images: (images ?? []) as Image[],
|
||||||
type: type ? { value: type } : { value: faker.commerce.productName() },
|
type: type ? { value: type } : { value: faker.commerce.productName() },
|
||||||
tags: tags ?? [{ value: "tag-1" }],
|
tags: tags ?? [{ value: "tag-1" }],
|
||||||
|
collection_id,
|
||||||
options: options ?? [
|
options: options ?? [
|
||||||
{
|
{
|
||||||
title: defaultOptionTitle,
|
title: defaultOptionTitle,
|
||||||
|
|||||||
@@ -23,6 +23,17 @@ export const productsData = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "test-3",
|
||||||
|
title: "product 3",
|
||||||
|
status: ProductTypes.ProductStatus.PUBLISHED,
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
id: "tag-3",
|
||||||
|
value: "Germany",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const variantsData = [
|
export const variantsData = [
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export async function createProductAndTags(
|
|||||||
title: string
|
title: string
|
||||||
status: ProductTypes.ProductStatus
|
status: ProductTypes.ProductStatus
|
||||||
tags?: { id: string; value: string }[]
|
tags?: { id: string; value: string }[]
|
||||||
|
collection_id?: string
|
||||||
}[]
|
}[]
|
||||||
) {
|
) {
|
||||||
const products: any[] = data.map((productData) => {
|
const products: any[] = data.map((productData) => {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { MedusaModule } from "@medusajs/modules-sdk"
|
import { MedusaModule } from "@medusajs/modules-sdk"
|
||||||
|
import { IProductModuleService } from "@medusajs/types"
|
||||||
|
import { kebabCase } from "@medusajs/utils"
|
||||||
|
import { knex } from "knex"
|
||||||
import { initialize } from "../../src"
|
import { initialize } from "../../src"
|
||||||
|
import { EventBusService } from "../__fixtures__/event-bus"
|
||||||
import * as CustomRepositories from "../__fixtures__/module"
|
import * as CustomRepositories from "../__fixtures__/module"
|
||||||
import {
|
import {
|
||||||
buildProductAndRelationsData,
|
buildProductAndRelationsData,
|
||||||
@@ -7,10 +11,6 @@ import {
|
|||||||
} from "../__fixtures__/product"
|
} from "../__fixtures__/product"
|
||||||
import { productsData } from "../__fixtures__/product/data"
|
import { productsData } from "../__fixtures__/product/data"
|
||||||
import { DB_URL, TestDatabase } from "../utils"
|
import { DB_URL, TestDatabase } from "../utils"
|
||||||
import { kebabCase } from "@medusajs/utils"
|
|
||||||
import { IProductModuleService } from "@medusajs/types"
|
|
||||||
import { knex } from "knex"
|
|
||||||
import { EventBusService } from "../__fixtures__/event-bus"
|
|
||||||
|
|
||||||
const sharedPgConnection = knex<any, any>({
|
const sharedPgConnection = knex<any, any>({
|
||||||
client: "pg",
|
client: "pg",
|
||||||
@@ -66,7 +66,7 @@ describe("Product module", function () {
|
|||||||
|
|
||||||
it("should return a list of product", async () => {
|
it("should return a list of product", async () => {
|
||||||
const products = await module.list()
|
const products = await module.list()
|
||||||
expect(products).toHaveLength(2)
|
expect(products).toHaveLength(3)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+232
-117
@@ -1,14 +1,20 @@
|
|||||||
import { MedusaModule } from "@medusajs/modules-sdk"
|
import { MedusaModule } from "@medusajs/modules-sdk"
|
||||||
import { Product, ProductCategory, ProductCollection, ProductType, ProductVariant } from "@models"
|
|
||||||
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
import { IProductModuleService, ProductTypes } from "@medusajs/types"
|
||||||
import { kebabCase } from "@medusajs/utils"
|
import { kebabCase } from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
Product,
|
||||||
|
ProductCategory,
|
||||||
|
ProductCollection,
|
||||||
|
ProductType,
|
||||||
|
ProductVariant,
|
||||||
|
} from "@models"
|
||||||
|
|
||||||
import { initialize } from "../../../../src"
|
import { initialize } from "../../../../src"
|
||||||
import { DB_URL, TestDatabase } from "../../../utils"
|
|
||||||
import { buildProductAndRelationsData } from "../../../__fixtures__/product/data/create-product"
|
|
||||||
import { createProductCategories } from "../../../__fixtures__/product-category"
|
|
||||||
import { createCollections, createTypes } from "../../../__fixtures__/product"
|
|
||||||
import { EventBusService } from "../../../__fixtures__/event-bus"
|
import { EventBusService } from "../../../__fixtures__/event-bus"
|
||||||
|
import { createCollections, createTypes } from "../../../__fixtures__/product"
|
||||||
|
import { createProductCategories } from "../../../__fixtures__/product-category"
|
||||||
|
import { buildProductAndRelationsData } from "../../../__fixtures__/product/data/create-product"
|
||||||
|
import { DB_URL, TestDatabase } from "../../../utils"
|
||||||
|
|
||||||
const beforeEach_ = async () => {
|
const beforeEach_ = async () => {
|
||||||
await TestDatabase.setupDatabase()
|
await TestDatabase.setupDatabase()
|
||||||
@@ -21,14 +27,26 @@ const afterEach_ = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("ProductModuleService products", function () {
|
describe("ProductModuleService products", function () {
|
||||||
|
let productCollectionOne: ProductCollection
|
||||||
|
let productCollectionTwo: ProductCollection
|
||||||
|
|
||||||
|
const productCollectionsData = [
|
||||||
|
{
|
||||||
|
id: "test-1",
|
||||||
|
title: "col 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-2",
|
||||||
|
title: "col 2",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
describe("update", function () {
|
describe("update", function () {
|
||||||
let module: IProductModuleService
|
let module: IProductModuleService
|
||||||
let productOne: Product
|
let productOne: Product
|
||||||
let productTwo: Product
|
let productTwo: Product
|
||||||
let productCategoryOne: ProductCategory
|
let productCategoryOne: ProductCategory
|
||||||
let productCategoryTwo: ProductCategory
|
let productCategoryTwo: ProductCategory
|
||||||
let productCollectionOne: ProductCollection
|
|
||||||
let productCollectionTwo: ProductCollection
|
|
||||||
let variantOne: ProductVariant
|
let variantOne: ProductVariant
|
||||||
let variantTwo: ProductVariant
|
let variantTwo: ProductVariant
|
||||||
let variantThree: ProductVariant
|
let variantThree: ProductVariant
|
||||||
@@ -37,22 +55,14 @@ describe("ProductModuleService products", function () {
|
|||||||
let images = ["image-1"]
|
let images = ["image-1"]
|
||||||
let eventBus
|
let eventBus
|
||||||
|
|
||||||
const productCategoriesData = [{
|
const productCategoriesData = [
|
||||||
id: "test-1",
|
|
||||||
name: "category 1",
|
|
||||||
}, {
|
|
||||||
id: "test-2",
|
|
||||||
name: "category 2",
|
|
||||||
}]
|
|
||||||
|
|
||||||
const productCollectionsData = [
|
|
||||||
{
|
{
|
||||||
id: "test-1",
|
id: "test-1",
|
||||||
title: "col 1",
|
name: "category 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "test-2",
|
id: "test-2",
|
||||||
title: "col 2",
|
name: "category 2",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -67,10 +77,12 @@ describe("ProductModuleService products", function () {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const tagsData = [{
|
const tagsData = [
|
||||||
id: "tag-1",
|
{
|
||||||
value: "tag 1",
|
id: "tag-1",
|
||||||
}]
|
value: "tag 1",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const testManager = await beforeEach_()
|
const testManager = await beforeEach_()
|
||||||
@@ -83,18 +95,15 @@ describe("ProductModuleService products", function () {
|
|||||||
productCollectionOne = collections[0]
|
productCollectionOne = collections[0]
|
||||||
productCollectionTwo = collections[1]
|
productCollectionTwo = collections[1]
|
||||||
|
|
||||||
const types = await createTypes(
|
const types = await createTypes(testManager, productTypesData)
|
||||||
testManager,
|
|
||||||
productTypesData,
|
|
||||||
)
|
|
||||||
|
|
||||||
productTypeOne = types[0]
|
productTypeOne = types[0]
|
||||||
productTypeTwo = types[1]
|
productTypeTwo = types[1]
|
||||||
|
|
||||||
const categories = (await createProductCategories(
|
const categories = await createProductCategories(
|
||||||
testManager,
|
testManager,
|
||||||
productCategoriesData
|
productCategoriesData
|
||||||
))
|
)
|
||||||
|
|
||||||
productCategoryOne = categories[0]
|
productCategoryOne = categories[0]
|
||||||
productCategoryTwo = categories[1]
|
productCategoryTwo = categories[1]
|
||||||
@@ -140,14 +149,17 @@ describe("ProductModuleService products", function () {
|
|||||||
MedusaModule.clearInstances()
|
MedusaModule.clearInstances()
|
||||||
|
|
||||||
eventBus = new EventBusService()
|
eventBus = new EventBusService()
|
||||||
module = await initialize({
|
module = await initialize(
|
||||||
database: {
|
{
|
||||||
clientUrl: DB_URL,
|
database: {
|
||||||
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
clientUrl: DB_URL,
|
||||||
|
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, {
|
{
|
||||||
eventBusModuleService: eventBus
|
eventBusModuleService: eventBus,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(afterEach_)
|
afterEach(afterEach_)
|
||||||
@@ -161,14 +173,22 @@ describe("ProductModuleService products", function () {
|
|||||||
const updateData = {
|
const updateData = {
|
||||||
...data,
|
...data,
|
||||||
id: productOne.id,
|
id: productOne.id,
|
||||||
title: "updated title"
|
title: "updated title",
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedProducts = await module.update([updateData])
|
const updatedProducts = await module.update([updateData])
|
||||||
expect(updatedProducts).toHaveLength(1)
|
expect(updatedProducts).toHaveLength(1)
|
||||||
|
|
||||||
const product = await module.retrieve(updateData.id, {
|
const product = await module.retrieve(updateData.id, {
|
||||||
relations: ["images", "variants", "options", "options.values", "variants.options", "tags", "type",]
|
relations: [
|
||||||
|
"images",
|
||||||
|
"variants",
|
||||||
|
"options",
|
||||||
|
"options.values",
|
||||||
|
"variants.options",
|
||||||
|
"tags",
|
||||||
|
"type",
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product.images).toHaveLength(1)
|
expect(product.images).toHaveLength(1)
|
||||||
@@ -236,7 +256,7 @@ describe("ProductModuleService products", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should emit events through event bus", async () => {
|
it("should emit events through event bus", async () => {
|
||||||
const eventBusSpy = jest.spyOn(EventBusService.prototype, 'emit')
|
const eventBusSpy = jest.spyOn(EventBusService.prototype, "emit")
|
||||||
const data = buildProductAndRelationsData({
|
const data = buildProductAndRelationsData({
|
||||||
images,
|
images,
|
||||||
thumbnail: images[0],
|
thumbnail: images[0],
|
||||||
@@ -245,32 +265,36 @@ describe("ProductModuleService products", function () {
|
|||||||
const updateData = {
|
const updateData = {
|
||||||
...data,
|
...data,
|
||||||
id: productOne.id,
|
id: productOne.id,
|
||||||
title: "updated title"
|
title: "updated title",
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||||
expect(eventBusSpy).toHaveBeenCalledWith([{
|
expect(eventBusSpy).toHaveBeenCalledWith([
|
||||||
eventName: "product.updated",
|
{
|
||||||
data: { id: productOne.id }
|
eventName: "product.updated",
|
||||||
}])
|
data: { id: productOne.id },
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should add relationships to a product", async () => {
|
it("should add relationships to a product", async () => {
|
||||||
const updateData = {
|
const updateData = {
|
||||||
id: productOne.id,
|
id: productOne.id,
|
||||||
categories: [{
|
categories: [
|
||||||
id: productCategoryOne.id
|
{
|
||||||
}],
|
id: productCategoryOne.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
collection_id: productCollectionOne.id,
|
collection_id: productCollectionOne.id,
|
||||||
type_id: productTypeOne.id
|
type_id: productTypeOne.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
const product = await module.retrieve(updateData.id, {
|
const product = await module.retrieve(updateData.id, {
|
||||||
relations: ["categories", "collection", "type"]
|
relations: ["categories", "collection", "type"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product).toEqual(
|
expect(product).toEqual(
|
||||||
@@ -278,15 +302,15 @@ describe("ProductModuleService products", function () {
|
|||||||
id: productOne.id,
|
id: productOne.id,
|
||||||
categories: [
|
categories: [
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productCategoryOne.id
|
id: productCategoryOne.id,
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
collection: expect.objectContaining({
|
collection: expect.objectContaining({
|
||||||
id: productCollectionOne.id
|
id: productCollectionOne.id,
|
||||||
}),
|
}),
|
||||||
type: expect.objectContaining({
|
type: expect.objectContaining({
|
||||||
id: productTypeOne.id
|
id: productTypeOne.id,
|
||||||
})
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -296,22 +320,22 @@ describe("ProductModuleService products", function () {
|
|||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
type: {
|
type: {
|
||||||
id: productTypeOne.id,
|
id: productTypeOne.id,
|
||||||
value: productTypeOne.value
|
value: productTypeOne.value,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
let product = await module.retrieve(updateData.id, {
|
let product = await module.retrieve(updateData.id, {
|
||||||
relations: ["type"]
|
relations: ["type"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product).toEqual(
|
expect(product).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
type: expect.objectContaining({
|
type: expect.objectContaining({
|
||||||
id: productTypeOne.id
|
id: productTypeOne.id,
|
||||||
})
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -319,22 +343,22 @@ describe("ProductModuleService products", function () {
|
|||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
type: {
|
type: {
|
||||||
id: "new-type-id",
|
id: "new-type-id",
|
||||||
value: "new-type-value"
|
value: "new-type-value",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
product = await module.retrieve(updateData.id, {
|
product = await module.retrieve(updateData.id, {
|
||||||
relations: ["type"]
|
relations: ["type"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product).toEqual(
|
expect(product).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
type: expect.objectContaining({
|
type: expect.objectContaining({
|
||||||
...updateData.type
|
...updateData.type,
|
||||||
})
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -347,9 +371,11 @@ describe("ProductModuleService products", function () {
|
|||||||
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
categories: [{
|
categories: [
|
||||||
id: productCategoryTwo.id
|
{
|
||||||
}],
|
id: productCategoryTwo.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
collection_id: productCollectionTwo.id,
|
collection_id: productCollectionTwo.id,
|
||||||
type_id: productTypeTwo.id,
|
type_id: productTypeTwo.id,
|
||||||
tags: [newTagData],
|
tags: [newTagData],
|
||||||
@@ -358,7 +384,7 @@ describe("ProductModuleService products", function () {
|
|||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
const product = await module.retrieve(updateData.id, {
|
const product = await module.retrieve(updateData.id, {
|
||||||
relations: ["categories", "collection", "tags", "type"]
|
relations: ["categories", "collection", "tags", "type"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product).toEqual(
|
expect(product).toEqual(
|
||||||
@@ -366,21 +392,21 @@ describe("ProductModuleService products", function () {
|
|||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
categories: [
|
categories: [
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productCategoryTwo.id
|
id: productCategoryTwo.id,
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
collection: expect.objectContaining({
|
collection: expect.objectContaining({
|
||||||
id: productCollectionTwo.id
|
id: productCollectionTwo.id,
|
||||||
}),
|
}),
|
||||||
tags: [
|
tags: [
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: newTagData.id,
|
id: newTagData.id,
|
||||||
value: newTagData.value
|
value: newTagData.value,
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
type: expect.objectContaining({
|
type: expect.objectContaining({
|
||||||
id: productTypeTwo.id
|
id: productTypeTwo.id,
|
||||||
})
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -391,13 +417,13 @@ describe("ProductModuleService products", function () {
|
|||||||
categories: [],
|
categories: [],
|
||||||
collection_id: null,
|
collection_id: null,
|
||||||
type_id: null,
|
type_id: null,
|
||||||
tags: []
|
tags: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
const product = await module.retrieve(updateData.id, {
|
const product = await module.retrieve(updateData.id, {
|
||||||
relations: ["categories", "collection", "tags"]
|
relations: ["categories", "collection", "tags"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product).toEqual(
|
expect(product).toEqual(
|
||||||
@@ -406,7 +432,7 @@ describe("ProductModuleService products", function () {
|
|||||||
categories: [],
|
categories: [],
|
||||||
tags: [],
|
tags: [],
|
||||||
collection: null,
|
collection: null,
|
||||||
type: null
|
type: null,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -415,7 +441,7 @@ describe("ProductModuleService products", function () {
|
|||||||
let error
|
let error
|
||||||
const updateData = {
|
const updateData = {
|
||||||
id: "does-not-exist",
|
id: "does-not-exist",
|
||||||
title: "test"
|
title: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -431,18 +457,21 @@ describe("ProductModuleService products", function () {
|
|||||||
const updateData = {
|
const updateData = {
|
||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
// Note: VariantThree is already assigned to productTwo, that should be deleted
|
// Note: VariantThree is already assigned to productTwo, that should be deleted
|
||||||
variants: [{
|
variants: [
|
||||||
id: variantTwo.id,
|
{
|
||||||
title: "updated-variant"
|
id: variantTwo.id,
|
||||||
}, {
|
title: "updated-variant",
|
||||||
title: "created-variant"
|
},
|
||||||
}]
|
{
|
||||||
|
title: "created-variant",
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
await module.update([updateData])
|
await module.update([updateData])
|
||||||
|
|
||||||
const product = await module.retrieve(updateData.id, {
|
const product = await module.retrieve(updateData.id, {
|
||||||
relations: ["variants"]
|
relations: ["variants"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(product.variants).toHaveLength(2)
|
expect(product.variants).toHaveLength(2)
|
||||||
@@ -469,12 +498,15 @@ describe("ProductModuleService products", function () {
|
|||||||
const updateData = {
|
const updateData = {
|
||||||
id: productTwo.id,
|
id: productTwo.id,
|
||||||
// Note: VariantThree is already assigned to productTwo, that should be deleted
|
// Note: VariantThree is already assigned to productTwo, that should be deleted
|
||||||
variants: [{
|
variants: [
|
||||||
id: "does-not-exist",
|
{
|
||||||
title: "updated-variant"
|
id: "does-not-exist",
|
||||||
}, {
|
title: "updated-variant",
|
||||||
title: "created-variant"
|
},
|
||||||
}]
|
{
|
||||||
|
title: "created-variant",
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -484,10 +516,12 @@ describe("ProductModuleService products", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await module.retrieve(updateData.id, {
|
await module.retrieve(updateData.id, {
|
||||||
relations: ["variants"]
|
relations: ["variants"],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(error.message).toEqual(`ProductVariant with id "does-not-exist" not found`)
|
expect(error.message).toEqual(
|
||||||
|
`ProductVariant with id "does-not-exist" not found`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -502,14 +536,17 @@ describe("ProductModuleService products", function () {
|
|||||||
MedusaModule.clearInstances()
|
MedusaModule.clearInstances()
|
||||||
|
|
||||||
eventBus = new EventBusService()
|
eventBus = new EventBusService()
|
||||||
module = await initialize({
|
module = await initialize(
|
||||||
database: {
|
{
|
||||||
clientUrl: DB_URL,
|
database: {
|
||||||
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
clientUrl: DB_URL,
|
||||||
|
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, {
|
{
|
||||||
eventBusModuleService: eventBus
|
eventBusModuleService: eventBus,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(afterEach_)
|
afterEach(afterEach_)
|
||||||
@@ -590,7 +627,7 @@ describe("ProductModuleService products", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should emit events through eventBus", async () => {
|
it("should emit events through eventBus", async () => {
|
||||||
const eventBusSpy = jest.spyOn(EventBusService.prototype, 'emit')
|
const eventBusSpy = jest.spyOn(EventBusService.prototype, "emit")
|
||||||
const data = buildProductAndRelationsData({
|
const data = buildProductAndRelationsData({
|
||||||
images,
|
images,
|
||||||
thumbnail: images[0],
|
thumbnail: images[0],
|
||||||
@@ -599,10 +636,12 @@ describe("ProductModuleService products", function () {
|
|||||||
const products = await module.create([data])
|
const products = await module.create([data])
|
||||||
|
|
||||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||||
expect(eventBusSpy).toHaveBeenCalledWith([{
|
expect(eventBusSpy).toHaveBeenCalledWith([
|
||||||
eventName: "product.created",
|
{
|
||||||
data: { id: products[0].id }
|
eventName: "product.created",
|
||||||
}])
|
data: { id: products[0].id },
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -617,14 +656,17 @@ describe("ProductModuleService products", function () {
|
|||||||
MedusaModule.clearInstances()
|
MedusaModule.clearInstances()
|
||||||
|
|
||||||
eventBus = new EventBusService()
|
eventBus = new EventBusService()
|
||||||
module = await initialize({
|
module = await initialize(
|
||||||
database: {
|
{
|
||||||
clientUrl: DB_URL,
|
database: {
|
||||||
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
clientUrl: DB_URL,
|
||||||
|
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, {
|
{
|
||||||
eventBusModuleService: eventBus
|
eventBusModuleService: eventBus,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(afterEach_)
|
afterEach(afterEach_)
|
||||||
@@ -681,7 +723,7 @@ describe("ProductModuleService products", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should emit events through eventBus", async () => {
|
it("should emit events through eventBus", async () => {
|
||||||
const eventBusSpy = jest.spyOn(EventBusService.prototype, 'emit')
|
const eventBusSpy = jest.spyOn(EventBusService.prototype, "emit")
|
||||||
const data = buildProductAndRelationsData({
|
const data = buildProductAndRelationsData({
|
||||||
images,
|
images,
|
||||||
thumbnail: images[0],
|
thumbnail: images[0],
|
||||||
@@ -691,10 +733,12 @@ describe("ProductModuleService products", function () {
|
|||||||
|
|
||||||
await module.softDelete([products[0].id])
|
await module.softDelete([products[0].id])
|
||||||
|
|
||||||
expect(eventBusSpy).toHaveBeenCalledWith([{
|
expect(eventBusSpy).toHaveBeenCalledWith([
|
||||||
eventName: "product.created",
|
{
|
||||||
data: { id: products[0].id }
|
eventName: "product.created",
|
||||||
}])
|
data: { id: products[0].id },
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -770,4 +814,75 @@ describe("ProductModuleService products", function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("list", function () {
|
||||||
|
let module: IProductModuleService
|
||||||
|
let collections: ProductCollection
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const testManager = await beforeEach_()
|
||||||
|
|
||||||
|
const collections = await createCollections(
|
||||||
|
testManager,
|
||||||
|
productCollectionsData
|
||||||
|
)
|
||||||
|
|
||||||
|
productCollectionOne = collections[0]
|
||||||
|
productCollectionTwo = collections[1]
|
||||||
|
|
||||||
|
MedusaModule.clearInstances()
|
||||||
|
|
||||||
|
module = await initialize({
|
||||||
|
database: {
|
||||||
|
clientUrl: DB_URL,
|
||||||
|
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const productOneData = buildProductAndRelationsData({
|
||||||
|
collection_id: productCollectionOne.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const productTwoData = buildProductAndRelationsData({
|
||||||
|
collection_id: productCollectionTwo.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
await module.create([productOneData, productTwoData])
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(afterEach_)
|
||||||
|
|
||||||
|
it("should return a list of products scoped by collection id", async () => {
|
||||||
|
const productsWithCollectionOne = await module.list(
|
||||||
|
{ collection_id: productCollectionOne.id },
|
||||||
|
{
|
||||||
|
relations: ["collection"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(productsWithCollectionOne).toHaveLength(1)
|
||||||
|
|
||||||
|
expect([
|
||||||
|
expect.objectContaining({
|
||||||
|
collection: expect.objectContaining({
|
||||||
|
id: productCollectionOne.id,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should returns empty array when querying for a collection that doesnt exist", async () => {
|
||||||
|
const products = await module.list(
|
||||||
|
{
|
||||||
|
categories: { id: ["collection-doesnt-exist-id"] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: ["title", "collection.title"],
|
||||||
|
relations: ["collection"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(products).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
import { Image, Product, ProductCategory, ProductVariant } from "@models"
|
import {
|
||||||
|
Image,
|
||||||
|
Product,
|
||||||
|
ProductCategory,
|
||||||
|
ProductCollection,
|
||||||
|
ProductVariant,
|
||||||
|
} from "@models"
|
||||||
import {
|
import {
|
||||||
assignCategoriesToProduct,
|
assignCategoriesToProduct,
|
||||||
buildProductOnlyData,
|
buildProductOnlyData,
|
||||||
|
createCollections,
|
||||||
createImages,
|
createImages,
|
||||||
createProductAndTags,
|
createProductAndTags,
|
||||||
createProductVariants,
|
createProductVariants,
|
||||||
} from "../../../__fixtures__/product"
|
} from "../../../__fixtures__/product"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
categoriesData,
|
categoriesData,
|
||||||
productsData,
|
productsData,
|
||||||
@@ -30,6 +38,7 @@ describe("Product Service", () => {
|
|||||||
let productOne: Product
|
let productOne: Product
|
||||||
let variants!: ProductVariant[]
|
let variants!: ProductVariant[]
|
||||||
let categories!: ProductCategory[]
|
let categories!: ProductCategory[]
|
||||||
|
let collections!: ProductCollection[]
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestDatabase.setupDatabase()
|
await TestDatabase.setupDatabase()
|
||||||
@@ -252,14 +261,14 @@ describe("Product Service", () => {
|
|||||||
it("should list all products that are not deleted", async () => {
|
it("should list all products that are not deleted", async () => {
|
||||||
const products = await service.list()
|
const products = await service.list()
|
||||||
|
|
||||||
expect(products).toHaveLength(1)
|
expect(products).toHaveLength(2)
|
||||||
expect(products[0].id).toEqual(product.id)
|
expect(products[0].id).toEqual(product.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should list all products including the deleted", async () => {
|
it("should list all products including the deleted", async () => {
|
||||||
const products = await service.list({}, { withDeleted: true })
|
const products = await service.list({}, { withDeleted: true })
|
||||||
|
|
||||||
expect(products).toHaveLength(2)
|
expect(products).toHaveLength(3)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -412,6 +421,132 @@ describe("Product Service", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("relation: collections", () => {
|
||||||
|
let workingProduct: Product
|
||||||
|
let workingProductTwo: Product
|
||||||
|
let workingCollection: ProductCollection
|
||||||
|
let workingCollectionTwo: ProductCollection
|
||||||
|
const collectionData = [
|
||||||
|
{
|
||||||
|
id: "test-1",
|
||||||
|
title: "col 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-2",
|
||||||
|
title: "col 2",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
testManager = await TestDatabase.forkManager()
|
||||||
|
collections = await createCollections(testManager, collectionData)
|
||||||
|
workingCollection = (await testManager.findOne(
|
||||||
|
ProductCollection,
|
||||||
|
"test-1"
|
||||||
|
)) as ProductCollection
|
||||||
|
workingCollectionTwo = (await testManager.findOne(
|
||||||
|
ProductCollection,
|
||||||
|
"test-2"
|
||||||
|
)) as ProductCollection
|
||||||
|
|
||||||
|
products = await createProductAndTags(testManager, [
|
||||||
|
{
|
||||||
|
...productsData[0],
|
||||||
|
collection_id: workingCollection.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...productsData[1],
|
||||||
|
collection_id: workingCollectionTwo.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...productsData[2],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
workingProduct = products.find((p) => p.id === "test-1") as Product
|
||||||
|
workingProductTwo = products.find((p) => p.id === "test-2") as Product
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should filter by collection relation and scope fields", async () => {
|
||||||
|
const products = await service.list(
|
||||||
|
{
|
||||||
|
id: workingProduct.id,
|
||||||
|
collection_id: workingCollection.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: ["title", "collection.title"],
|
||||||
|
relations: ["collection"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const serialized = JSON.parse(JSON.stringify(products))
|
||||||
|
|
||||||
|
expect(serialized.length).toEqual(1)
|
||||||
|
expect(serialized).toEqual([
|
||||||
|
{
|
||||||
|
id: workingProduct.id,
|
||||||
|
title: workingProduct.title,
|
||||||
|
collection_id: workingCollection.id,
|
||||||
|
collection: {
|
||||||
|
id: workingCollection.id,
|
||||||
|
title: workingCollection.title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should filter by collection when multiple collection ids are passed", async () => {
|
||||||
|
const products = await service.list(
|
||||||
|
{
|
||||||
|
collection_id: [workingCollection.id, workingCollectionTwo.id],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: ["title", "collection.title"],
|
||||||
|
relations: ["collection"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const serialized = JSON.parse(JSON.stringify(products))
|
||||||
|
|
||||||
|
expect(serialized.length).toEqual(2)
|
||||||
|
expect(serialized).toEqual([
|
||||||
|
{
|
||||||
|
id: workingProduct.id,
|
||||||
|
title: workingProduct.title,
|
||||||
|
collection_id: workingCollection.id,
|
||||||
|
collection: {
|
||||||
|
id: workingCollection.id,
|
||||||
|
title: workingCollection.title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: workingProductTwo.id,
|
||||||
|
title: workingProductTwo.title,
|
||||||
|
collection_id: workingCollectionTwo.id,
|
||||||
|
collection: {
|
||||||
|
id: workingCollectionTwo.id,
|
||||||
|
title: workingCollectionTwo.title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should returns empty array when querying for a collection that doesnt exist", async () => {
|
||||||
|
const products = await service.list(
|
||||||
|
{
|
||||||
|
id: workingProduct.id,
|
||||||
|
collection_id: "collection-doesnt-exist-id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
select: ["title", "collection.title"] as (keyof ProductDTO)[],
|
||||||
|
relations: ["collection"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(products).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("relation: variants", () => {
|
describe("relation: variants", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
testManager = await TestDatabase.forkManager()
|
testManager = await TestDatabase.forkManager()
|
||||||
|
|||||||
@@ -72,17 +72,17 @@ export default class ProductService<TEntity extends Product = Product> {
|
|||||||
config: FindConfig<ProductTypes.ProductDTO> = {},
|
config: FindConfig<ProductTypes.ProductDTO> = {},
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<TEntity[]> {
|
): Promise<TEntity[]> {
|
||||||
if (filters.category_ids) {
|
if (filters.category_id) {
|
||||||
if (Array.isArray(filters.category_ids)) {
|
if (Array.isArray(filters.category_id)) {
|
||||||
filters.categories = {
|
filters.categories = {
|
||||||
id: { $in: filters.category_ids },
|
id: { $in: filters.category_id },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filters.categories = {
|
filters.categories = {
|
||||||
id: filters.category_ids,
|
id: filters.category_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete filters.category_ids
|
delete filters.category_id
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
|
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
|
||||||
@@ -98,17 +98,17 @@ export default class ProductService<TEntity extends Product = Product> {
|
|||||||
config: FindConfig<ProductTypes.ProductDTO> = {},
|
config: FindConfig<ProductTypes.ProductDTO> = {},
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<[TEntity[], number]> {
|
): Promise<[TEntity[], number]> {
|
||||||
if (filters.category_ids) {
|
if (filters.category_id) {
|
||||||
if (Array.isArray(filters.category_ids)) {
|
if (Array.isArray(filters.category_id)) {
|
||||||
filters.categories = {
|
filters.categories = {
|
||||||
id: { $in: filters.category_ids },
|
id: { $in: filters.category_id },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filters.categories = {
|
filters.categories = {
|
||||||
id: filters.category_ids,
|
id: filters.category_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete filters.category_ids
|
delete filters.category_id
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
|
const queryOptions = ModulesSdkUtils.buildQuery<Product>(filters, config)
|
||||||
|
|||||||
@@ -30,4 +30,5 @@ export interface UpdateMoneyAmountDTO {
|
|||||||
export interface FilterableMoneyAmountProps
|
export interface FilterableMoneyAmountProps
|
||||||
extends BaseFilterable<FilterableMoneyAmountProps> {
|
extends BaseFilterable<FilterableMoneyAmountProps> {
|
||||||
id?: string[]
|
id?: string[]
|
||||||
|
currency_code?: string | string[]
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,8 @@ export interface FilterableProductProps
|
|||||||
categories?: {
|
categories?: {
|
||||||
id?: string | string[] | OperatorMap<string>
|
id?: string | string[] | OperatorMap<string>
|
||||||
}
|
}
|
||||||
category_ids?: string | string[] | OperatorMap<string>
|
category_id?: string | string[] | OperatorMap<string>
|
||||||
|
collection_id?: string | string[] | OperatorMap<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterableProductTagProps
|
export interface FilterableProductTagProps
|
||||||
|
|||||||
Reference in new issue
Block a user