fix(medusa): fixes bug for mpath incorrectly updated for nested categories (#3311)

* chore: fix issue with mpath being incorrectly set

* chore: address review changes
This commit is contained in:
Riqwan Thamir
2023-02-22 15:43:58 +01:00
committed by GitHub
parent e8e7d7bb53
commit 68496ffe60
4 changed files with 152 additions and 17 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
fix(medusa): fixes bug for mpath incorrectly updated for nested categories

View File

@@ -243,6 +243,17 @@ describe("/admin/product-categories", () => {
describe("POST /admin/product-categories", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
productCategoryParent = await simpleProductCategoryFactory(dbConnection, {
name: "category parent",
handle: "category-parent",
})
productCategory = await simpleProductCategoryFactory(dbConnection, {
name: "category",
handle: "category",
parent_category: productCategoryParent,
})
})
afterEach(async () => {
@@ -267,11 +278,6 @@ describe("/admin/product-categories", () => {
})
it("successfully creates a product category", async () => {
productCategoryParent = await simpleProductCategoryFactory(dbConnection, {
name: "category parent",
handle: "category-parent",
})
const api = useApi()
const response = await api.post(
@@ -280,7 +286,7 @@ describe("/admin/product-categories", () => {
name: "test",
handle: "test",
is_internal: true,
parent_category_id: productCategoryParent.id,
parent_category_id: productCategory.id,
},
adminHeaders
)
@@ -296,13 +302,49 @@ describe("/admin/product-categories", () => {
created_at: expect.any(String),
updated_at: expect.any(String),
parent_category: expect.objectContaining({
id: productCategoryParent.id
id: productCategory.id
}),
category_children: []
}),
})
)
})
it("root parent returns children correctly on creating new category", async () => {
const api = useApi()
const response = await api.post(
`/admin/product-categories`,
{
name: "last descendant",
parent_category_id: productCategory.id,
},
adminHeaders
)
const lastDescendant = response.data.product_category
const parentResponse = await api.get(
`/admin/product-categories/${productCategoryParent.id}`,
adminHeaders
)
expect(parentResponse.data.product_category).toEqual(
expect.objectContaining({
id: productCategoryParent.id,
category_children: [
expect.objectContaining({
id: productCategory.id,
category_children: [
expect.objectContaining({
id: lastDescendant.id,
category_children: []
})
]
})
]
})
)
})
})
describe("DELETE /admin/product-categories/:id", () => {
@@ -381,14 +423,27 @@ describe("/admin/product-categories", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
productCategory = await simpleProductCategoryFactory(dbConnection, {
name: "skinny jeans",
handle: "skinny-jeans",
productCategoryParent = await simpleProductCategoryFactory(dbConnection, {
name: "category parent",
handle: "category-parent",
})
productCategory2 = await simpleProductCategoryFactory(dbConnection, {
name: "sweater",
handle: "sweater",
productCategory = await simpleProductCategoryFactory(dbConnection, {
name: "category",
handle: "category",
parent_category: productCategoryParent,
})
productCategoryChild = await simpleProductCategoryFactory(dbConnection, {
name: "category child",
handle: "category-child",
parent_category: productCategory,
})
productCategoryChild2 = await simpleProductCategoryFactory(dbConnection, {
name: "category child 2",
handle: "category-child-2",
parent_category: productCategoryChild,
})
})
@@ -437,13 +492,13 @@ describe("/admin/product-categories", () => {
const api = useApi()
const response = await api.post(
`/admin/product-categories/${productCategory.id}`,
`/admin/product-categories/${productCategoryChild2.id}`,
{
name: "test",
handle: "test",
is_internal: true,
is_active: true,
parent_category_id: productCategory2.id,
parent_category_id: productCategory.id,
},
adminHeaders
)
@@ -459,13 +514,52 @@ describe("/admin/product-categories", () => {
created_at: expect.any(String),
updated_at: expect.any(String),
parent_category: expect.objectContaining({
id: productCategory2.id,
id: productCategory.id,
}),
category_children: []
}),
})
)
})
it("root parent returns children correctly on updating new category", async () => {
const api = useApi()
const response = await api.post(
`/admin/product-categories/${productCategoryChild2.id}`,
{
parent_category_id: productCategory.id,
},
adminHeaders
)
const lastDescendant = response.data.product_category
const parentResponse = await api.get(
`/admin/product-categories/${productCategoryParent.id}`,
adminHeaders
)
expect(parentResponse.data.product_category).toEqual(
expect.objectContaining({
id: productCategoryParent.id,
category_children: [
expect.objectContaining({
id: productCategory.id,
category_children: [
expect.objectContaining({
id: productCategoryChild.id,
category_children: []
}),
expect.objectContaining({
id: productCategoryChild2.id,
category_children: []
})
]
})
]
})
)
})
})
describe("POST /admin/product-categories/:id/products/batch", () => {

View File

@@ -121,7 +121,7 @@ class ProductCategoryService extends TransactionBaseService {
/**
* Creates a product category
* @param productCategory - params used to create
* @param productCategoryInput - parameters to create a product category
* @return created product category
*/
async create(
@@ -129,6 +129,9 @@ class ProductCategoryService extends TransactionBaseService {
): Promise<ProductCategory> {
return await this.atomicPhase_(async (manager) => {
const pcRepo = manager.withRepository(this.productCategoryRepo_)
await this.transformParentIdToEntity(productCategoryInput)
let productCategory = pcRepo.create(productCategoryInput)
productCategory = await pcRepo.save(productCategory)
@@ -157,6 +160,8 @@ class ProductCategoryService extends TransactionBaseService {
this.productCategoryRepo_
)
await this.transformParentIdToEntity(productCategoryInput)
let productCategory = await this.retrieve(productCategoryId)
for (const key in productCategoryInput) {
@@ -253,6 +258,34 @@ class ProductCategoryService extends TransactionBaseService {
)
})
}
/**
* Accepts an input object and transforms product_category_id
* into product_category entity.
* @param productCategoryInput - params used to create/update
* @return transformed productCategoryInput
*/
protected async transformParentIdToEntity(
productCategoryInput:
| CreateProductCategoryInput
| UpdateProductCategoryInput
): Promise<CreateProductCategoryInput | UpdateProductCategoryInput> {
// Typeorm only updates mpath when the category entity of the parent
// is passed into create/save. For this reason, everytime we create a
// category, we must fetch the entity and push to create
const parentCategoryId = productCategoryInput.parent_category_id
if (!parentCategoryId) {
return productCategoryInput
}
const parentCategory = await this.retrieve(parentCategoryId)
productCategoryInput.parent_category = parentCategory
delete productCategoryInput.parent_category_id
return productCategoryInput
}
}
export default ProductCategoryService

View File

@@ -1,5 +1,6 @@
import { Transform } from "class-transformer"
import { IsNotEmpty, IsOptional, IsString, IsBoolean } from "class-validator"
import { ProductCategory } from "../models"
export type CreateProductCategoryInput = {
name: string
@@ -7,6 +8,7 @@ export type CreateProductCategoryInput = {
is_internal?: boolean
is_active?: boolean
parent_category_id?: string | null
parent_category?: ProductCategory | null
}
export type UpdateProductCategoryInput = {
@@ -15,6 +17,7 @@ export type UpdateProductCategoryInput = {
is_internal?: boolean
is_active?: boolean
parent_category_id?: string | null
parent_category?: ProductCategory | null
}
export class AdminProductCategoriesReqBase {