diff --git a/integration-tests/http/__tests__/product-category/admin/product-category.spec.ts b/integration-tests/http/__tests__/product-category/admin/product-category.spec.ts index e571d491fb..3e513bb263 100644 --- a/integration-tests/http/__tests__/product-category/admin/product-category.spec.ts +++ b/integration-tests/http/__tests__/product-category/admin/product-category.spec.ts @@ -639,18 +639,79 @@ medusaIntegrationTestRunner({ }) }) - // TODO: Should be migrate to V2 - describe.skip("DELETE /admin/product-categories/:id", () => { - it("returns successfully with an invalid ID", async () => { - const response = await api.delete( - `/admin/product-categories/invalid-id`, - adminHeaders - ) + describe("DELETE /admin/product-categories/:id", () => { + beforeEach(async () => { + productCategoryParent = ( + await api.post( + "/admin/product-categories", + { + name: "category parent", + description: "category parent", + }, + adminHeaders + ) + ).data.product_category - expect(response.status).toEqual(200) - expect(response.data.id).toEqual("invalid-id") - expect(response.data.deleted).toBeTruthy() - expect(response.data.object).toEqual("product-category") + productCategory = ( + await api.post( + "/admin/product-categories", + { + name: "category-0", + parent_category_id: productCategoryParent.id, + rank: 0, + description: "category-0", + }, + adminHeaders + ) + ).data.product_category + + productCategoryChild = ( + await api.post( + "/admin/product-categories", + { + name: "category child", + parent_category_id: productCategory.id, + rank: 0, + description: "category child", + }, + adminHeaders + ) + ).data.product_category + + productCategoryChild2 = ( + await api.post( + "/admin/product-categories", + { + name: "category child 2", + parent_category_id: productCategoryChild.id, + rank: 2, + description: "category child 2", + }, + adminHeaders + ) + ).data.product_category + + productCategoryChild3 = ( + await api.post( + "/admin/product-categories", + { + name: "category child 3", + parent_category_id: productCategoryChild.id, + rank: 2, + description: "category child 3", + }, + adminHeaders + ) + ).data.product_category + }) + + // BREAKING: In v1 we would return 200 on an invalid ID, in v2 we return 404 + it("returns successfully with an invalid ID", async () => { + const err = await api + .delete(`/admin/product-categories/invalid-id`, adminHeaders) + .catch((e) => e) + + expect(err.response.status).toEqual(404) }) it("throws a not allowed error for a category with children", async () => { @@ -669,49 +730,43 @@ medusaIntegrationTestRunner({ }) it("deletes a product category with no children successfully", async () => { - const deleteResponse = await api - .delete( - `/admin/product-categories/${productCategory.id}`, - adminHeaders - ) - .catch((e) => e) + const deleteResponse = await api.delete( + `/admin/product-categories/${productCategoryChild2.id}`, + adminHeaders + ) expect(deleteResponse.status).toEqual(200) - expect(deleteResponse.data.id).toEqual(productCategory.id) + expect(deleteResponse.data.id).toEqual(productCategoryChild2.id) expect(deleteResponse.data.deleted).toBeTruthy() - expect(deleteResponse.data.object).toEqual("product-category") + expect(deleteResponse.data.object).toEqual("product_category") const errorFetchingDeleted = await api - .get(`/admin/product-categories/${productCategory.id}`, adminHeaders) + .get( + `/admin/product-categories/${productCategoryChild2.id}`, + adminHeaders + ) .catch((e) => e) expect(errorFetchingDeleted.response.status).toEqual(404) }) it("deleting a product category reorders siblings accurately", async () => { - const deleteResponse = await api - .delete( - `/admin/product-categories/${productCategory.id}`, - adminHeaders - ) - .catch((e) => e) + const deleteResponse = await api.delete( + `/admin/product-categories/${productCategoryChild2.id}`, + adminHeaders + ) expect(deleteResponse.status).toEqual(200) - const siblingsResponse = await api .get( - `/admin/product-categories?parent_category_id=${productCategoryParent.id}`, + `/admin/product-categories?parent_category_id=${productCategoryChild.id}`, adminHeaders ) .catch((e) => e) expect(siblingsResponse.data.product_categories).toEqual([ expect.objectContaining({ - id: productCategory1.id, - rank: 0, - }), - expect.objectContaining({ - id: productCategory2.id, + id: productCategoryChild3.id, rank: 1, }), ]) diff --git a/packages/core/core-flows/src/product-category/steps/delete-product-category.ts b/packages/core/core-flows/src/product-category/steps/delete-product-category.ts new file mode 100644 index 0000000000..e65aff5c53 --- /dev/null +++ b/packages/core/core-flows/src/product-category/steps/delete-product-category.ts @@ -0,0 +1,28 @@ +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { IProductModuleService } from "@medusajs/types" +import { StepResponse, createStep } from "@medusajs/workflows-sdk" + +export const deleteProductCategoryStepId = "delete-product-category" +export const deleteProductCategoryStep = createStep( + deleteProductCategoryStepId, + async (id: string, { container }) => { + const service = container.resolve( + ModuleRegistrationName.PRODUCT + ) + + await service.deleteCategory(id) + return new StepResponse(void 0, id) + }, + async (prevId, { container }) => { + if (!prevId) { + return + } + + const service = container.resolve( + ModuleRegistrationName.PRODUCT + ) + + // TODO: There is no soft delete support for categories yet + // await service.restoreCategory(prevId) + } +) diff --git a/packages/core/core-flows/src/product-category/steps/index.ts b/packages/core/core-flows/src/product-category/steps/index.ts index cf4dfb072e..c220add809 100644 --- a/packages/core/core-flows/src/product-category/steps/index.ts +++ b/packages/core/core-flows/src/product-category/steps/index.ts @@ -1 +1,3 @@ export * from "./create-product-category" +export * from "./update-product-category" +export * from "./delete-product-category" diff --git a/packages/core/core-flows/src/product-category/workflows/delete-product-category.ts b/packages/core/core-flows/src/product-category/workflows/delete-product-category.ts new file mode 100644 index 0000000000..e04c363187 --- /dev/null +++ b/packages/core/core-flows/src/product-category/workflows/delete-product-category.ts @@ -0,0 +1,10 @@ +import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { deleteProductCategoryStep } from "../steps" + +export const deleteProductCategoryWorkflowId = "delete-product-category" +export const deleteProductCategoryWorkflow = createWorkflow( + deleteProductCategoryWorkflowId, + (input: WorkflowData) => { + return deleteProductCategoryStep(input) + } +) diff --git a/packages/core/core-flows/src/product-category/workflows/index.ts b/packages/core/core-flows/src/product-category/workflows/index.ts index e4d4e700fd..c220add809 100644 --- a/packages/core/core-flows/src/product-category/workflows/index.ts +++ b/packages/core/core-flows/src/product-category/workflows/index.ts @@ -1,2 +1,3 @@ export * from "./create-product-category" export * from "./update-product-category" +export * from "./delete-product-category" diff --git a/packages/core/core-flows/src/product-category/workflows/update-product-category.ts b/packages/core/core-flows/src/product-category/workflows/update-product-category.ts index f114d88dca..7c640ae98c 100644 --- a/packages/core/core-flows/src/product-category/workflows/update-product-category.ts +++ b/packages/core/core-flows/src/product-category/workflows/update-product-category.ts @@ -1,6 +1,6 @@ import { ProductCategoryWorkflow } from "@medusajs/types" import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" -import { updateProductCategoryStep } from "../steps/update-product-category" +import { updateProductCategoryStep } from "../steps" type WorkflowInputData = ProductCategoryWorkflow.UpdateProductCategoryWorkflowInput diff --git a/packages/medusa/src/api/admin/product-categories/[id]/route.ts b/packages/medusa/src/api/admin/product-categories/[id]/route.ts index f374dcefee..2165eeedad 100644 --- a/packages/medusa/src/api/admin/product-categories/[id]/route.ts +++ b/packages/medusa/src/api/admin/product-categories/[id]/route.ts @@ -1,4 +1,7 @@ -import { updateProductCategoryWorkflow } from "@medusajs/core-flows" +import { + deleteProductCategoryWorkflow, + updateProductCategoryWorkflow, +} from "@medusajs/core-flows" import { AdminProductCategoryResponse } from "@medusajs/types" import { AuthenticatedMedusaRequest, @@ -9,6 +12,7 @@ import { AdminProductCategoryParamsType, AdminUpdateProductCategoryType, } from "../validators" +import { MedusaError } from "@medusajs/utils" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -21,6 +25,13 @@ export const GET = async ( req.remoteQueryConfig.fields ) + if (!category) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Product category with id: ${req.params.id} was not found` + ) + } + res.json({ product_category: category }) } @@ -44,3 +55,20 @@ export const POST = async ( res.status(200).json({ product_category: category }) } + +export const DELETE = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const id = req.params.id + + await deleteProductCategoryWorkflow(req.scope).run({ + input: id, + }) + + res.status(200).json({ + id, + object: "product_category", + deleted: true, + }) +} diff --git a/packages/medusa/src/api/admin/product-categories/middlewares.ts b/packages/medusa/src/api/admin/product-categories/middlewares.ts index 3376dc4670..7c83f4b9ac 100644 --- a/packages/medusa/src/api/admin/product-categories/middlewares.ts +++ b/packages/medusa/src/api/admin/product-categories/middlewares.ts @@ -53,6 +53,11 @@ export const adminProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["DELETE"], + matcher: "/admin/product-categories/:id", + middlewares: [], + }, { method: ["POST"], matcher: "/admin/product-categories/:id/products",