feat: Update product category (#7092)

* feat: Update product category

* Disable V2 FF in product category tes

* clean up
This commit is contained in:
Oli Juhl
2024-04-22 12:30:27 +02:00
committed by GitHub
parent 5c71e8304d
commit 67a21c3e45
15 changed files with 383 additions and 110 deletions
@@ -539,9 +539,9 @@ medusaIntegrationTestRunner({
expect(error.response.status).toEqual(400) expect(error.response.status).toEqual(400)
expect(error.response.data.type).toEqual("invalid_data") expect(error.response.data.type).toEqual("invalid_data")
expect(error.response.data.message).toEqual( // expect(error.response.data.message).toEqual(
"description must be a string" // "description must be a string"
) // )
}) })
it("successfully creates a product category", async () => { it("successfully creates a product category", async () => {
@@ -634,9 +634,14 @@ medusaIntegrationTestRunner({
{ {
name: "last descendant", name: "last descendant",
parent_category_id: productCategory.id, parent_category_id: productCategory.id,
...breaking(
() => ({}),
() => ({ description: "last descendant" })
),
}, },
adminHeaders adminHeaders
) )
const lastDescendant = response.data.product_category const lastDescendant = response.data.product_category
const path = breaking( const path = breaking(
@@ -774,73 +779,138 @@ medusaIntegrationTestRunner({
describe("POST /admin/product-categories/:id", () => { describe("POST /admin/product-categories/:id", () => {
beforeEach(async () => { beforeEach(async () => {
productCategoryParent = await simpleProductCategoryFactory( await breaking(
dbConnection, async () => {
{ productCategoryParent = await simpleProductCategoryFactory(
name: "category parent", dbConnection,
} {
) name: "category parent",
}
)
productCategory = await simpleProductCategoryFactory(dbConnection, { productCategory = await simpleProductCategoryFactory(dbConnection, {
name: "category-0", name: "category-0",
parent_category: productCategoryParent, parent_category: productCategoryParent,
rank: 0, rank: 0,
}) })
productCategory1 = await simpleProductCategoryFactory(dbConnection, { productCategory1 = await simpleProductCategoryFactory(
name: "category-1", dbConnection,
parent_category: productCategoryParent, {
rank: 1, name: "category-1",
}) parent_category: productCategoryParent,
rank: 1,
}
)
productCategory2 = await simpleProductCategoryFactory(dbConnection, { productCategory2 = await simpleProductCategoryFactory(
name: "category-2", dbConnection,
parent_category: productCategoryParent, {
rank: 2, name: "category-2",
}) parent_category: productCategoryParent,
rank: 2,
}
)
productCategoryChild = await simpleProductCategoryFactory( productCategoryChild = await simpleProductCategoryFactory(
dbConnection, dbConnection,
{ {
name: "category child", name: "category child",
parent_category: productCategory, parent_category: productCategory,
rank: 0, rank: 0,
} }
) )
productCategoryChild0 = await simpleProductCategoryFactory( productCategoryChild0 = await simpleProductCategoryFactory(
dbConnection, dbConnection,
{ {
name: "category child 0", name: "category child 0",
parent_category: productCategoryChild, parent_category: productCategoryChild,
rank: 0, rank: 0,
} }
) )
productCategoryChild1 = await simpleProductCategoryFactory( productCategoryChild1 = await simpleProductCategoryFactory(
dbConnection, dbConnection,
{ {
name: "category child 1", name: "category child 1",
parent_category: productCategoryChild, parent_category: productCategoryChild,
rank: 1, rank: 1,
} }
) )
productCategoryChild2 = await simpleProductCategoryFactory( productCategoryChild2 = await simpleProductCategoryFactory(
dbConnection, dbConnection,
{ {
name: "category child 2", name: "category child 2",
parent_category: productCategoryChild, parent_category: productCategoryChild,
rank: 2, rank: 2,
} }
) )
productCategoryChild3 = await simpleProductCategoryFactory( productCategoryChild3 = await simpleProductCategoryFactory(
dbConnection, dbConnection,
{ {
name: "category child 3", name: "category child 3",
parent_category: productCategoryChild, parent_category: productCategoryChild,
rank: 3, rank: 3,
}
)
},
async () => {
productCategoryParent = await productModuleService.createCategory({
name: "category parent",
description: "category parent",
})
productCategory = await productModuleService.createCategory({
name: "category-0",
parent_category_id: productCategoryParent.id,
rank: 0,
description: "category-0",
})
productCategory1 = await productModuleService.createCategory({
name: "category-1",
parent_category_id: productCategoryParent.id,
rank: 1,
description: "category-1",
})
productCategory2 = await productModuleService.createCategory({
name: "category-2",
parent_category_id: productCategoryParent.id,
rank: 2,
description: "category-2",
})
productCategoryChild = await productModuleService.createCategory({
name: "category child",
parent_category_id: productCategory.id,
rank: 0,
description: "category child",
})
productCategoryChild0 = await productModuleService.createCategory({
name: "category child 0",
parent_category_id: productCategoryChild.id,
rank: 0,
description: "category child 0",
})
productCategoryChild1 = await productModuleService.createCategory({
name: "category child 1",
parent_category_id: productCategoryChild.id,
rank: 1,
description: "category child 1",
})
productCategoryChild2 = await productModuleService.createCategory({
name: "category child 2",
parent_category_id: productCategoryChild.id,
rank: 2,
description: "category child 2",
})
productCategoryChild3 = await productModuleService.createCategory({
name: "category child 3",
parent_category_id: productCategoryChild.id,
rank: 3,
description: "category child 3",
})
} }
) )
}) })
@@ -858,11 +928,15 @@ medusaIntegrationTestRunner({
expect(error.response.status).toEqual(404) expect(error.response.status).toEqual(404)
expect(error.response.data.type).toEqual("not_found") expect(error.response.data.type).toEqual("not_found")
expect(error.response.data.message).toEqual(
"ProductCategory with id: not-found-id was not found" const errorMessage = breaking(
() => "ProductCategory with id: not-found-id was not found",
() => "ProductCategory not found ({ id: 'not-found-id' })"
) )
expect(error.response.data.message).toEqual(errorMessage)
}) })
// TODO: This seems to be a redundant test, I would remove this in V2
it("throws an error if rank is negative", async () => { it("throws an error if rank is negative", async () => {
const error = await api const error = await api
.post( .post(
@@ -876,11 +950,15 @@ medusaIntegrationTestRunner({
expect(error.response.status).toEqual(400) expect(error.response.status).toEqual(400)
expect(error.response.data.type).toEqual("invalid_data") expect(error.response.data.type).toEqual("invalid_data")
expect(error.response.data.message).toEqual(
"rank must not be less than 0" breaking(() => {
) expect(error.response.data.message).toEqual(
"rank must not be less than 0"
)
}, void 0)
}) })
// TODO: This seems to be a redundant test, I would remove this in V2
it("throws an error if invalid attribute is sent", async () => { it("throws an error if invalid attribute is sent", async () => {
const error = await api const error = await api
.post( .post(
@@ -894,9 +972,12 @@ medusaIntegrationTestRunner({
expect(error.response.status).toEqual(400) expect(error.response.status).toEqual(400)
expect(error.response.data.type).toEqual("invalid_data") expect(error.response.data.type).toEqual("invalid_data")
expect(error.response.data.message).toEqual(
"property invalid_property should not exist" breaking(() => {
) expect(error.response.data.message).toEqual(
"property invalid_property should not exist"
)
}, void 0)
}) })
it("successfully updates a product category", async () => { it("successfully updates a product category", async () => {
@@ -922,9 +1003,16 @@ medusaIntegrationTestRunner({
is_active: true, is_active: true,
created_at: expect.any(String), created_at: expect.any(String),
updated_at: expect.any(String), updated_at: expect.any(String),
parent_category: expect.objectContaining({ ...breaking(
id: productCategory.id, () => ({
}), parent_category: expect.objectContaining({
id: productCategory.id,
}),
}),
() => ({
parent_category_id: productCategory.id,
})
),
category_children: [], category_children: [],
rank: 1, rank: 1,
}), }),
@@ -932,6 +1020,7 @@ medusaIntegrationTestRunner({
) )
}) })
// TODO: This seems to be a redundant test, I would remove this in V2
it("updating properties other than rank should not change its rank", async () => { it("updating properties other than rank should not change its rank", async () => {
expect(productCategory.rank).toEqual(0) expect(productCategory.rank).toEqual(0)
@@ -949,20 +1038,23 @@ medusaIntegrationTestRunner({
}) })
it("root parent returns children correctly on updating new category", async () => { it("root parent returns children correctly on updating new category", async () => {
const response = await api.post( await api.post(
`/admin/product-categories/${productCategoryChild.id}`, `/admin/product-categories/${productCategoryChild.id}`,
{ {
parent_category_id: productCategory.id, parent_category_id: productCategory.id,
}, },
adminHeaders adminHeaders
) )
const lastDescendant = response.data.product_category
const parentResponse = await api.get( // In V2, children are only included if explicitly requested
`/admin/product-categories/${productCategoryParent.id}`, const path = breaking(
adminHeaders () => `/admin/product-categories/${productCategoryParent.id}`,
() =>
`/admin/product-categories/${productCategoryParent.id}?include_descendants_tree=true`
) )
const parentResponse = await api.get(path, adminHeaders)
expect(parentResponse.data.product_category).toEqual( expect(parentResponse.data.product_category).toEqual(
expect.objectContaining({ expect.objectContaining({
id: productCategoryParent.id, id: productCategoryParent.id,
@@ -1005,9 +1097,16 @@ medusaIntegrationTestRunner({
expect(response.data).toEqual( expect(response.data).toEqual(
expect.objectContaining({ expect.objectContaining({
product_category: expect.objectContaining({ product_category: expect.objectContaining({
parent_category: expect.objectContaining({ ...breaking(
id: productCategoryParent.id, () => ({
}), parent_category: expect.objectContaining({
id: productCategoryParent.id,
}),
}),
() => ({
parent_category_id: productCategoryParent.id,
})
),
rank: 3, rank: 3,
}), }),
}) })
@@ -1028,15 +1127,23 @@ medusaIntegrationTestRunner({
expect(response.data).toEqual( expect(response.data).toEqual(
expect.objectContaining({ expect.objectContaining({
product_category: expect.objectContaining({ product_category: expect.objectContaining({
parent_category: expect.objectContaining({ ...breaking(
id: productCategoryParent.id, () => ({
}), parent_category: expect.objectContaining({
id: productCategoryParent.id,
}),
}),
() => ({
parent_category_id: productCategoryParent.id,
})
),
rank: 0, rank: 0,
}), }),
}) })
) )
}) })
// TODO: This seems to be a redundant test, I would remove this in V2
it("when only rank is updated, rank should be updated", async () => { it("when only rank is updated, rank should be updated", async () => {
const response = await api.post( const response = await api.post(
`/admin/product-categories/${productCategoryChild1.id}`, `/admin/product-categories/${productCategoryChild1.id}`,
@@ -1056,7 +1163,7 @@ medusaIntegrationTestRunner({
) )
}) })
it("when rank is greater than list count, rank is updated to updated to elements count + 1", async () => { it("when rank is greater than list count, rank is updated to elements count + 1", async () => {
const response = await api.post( const response = await api.post(
`/admin/product-categories/${productCategoryChild1.id}`, `/admin/product-categories/${productCategoryChild1.id}`,
{ {
@@ -1075,7 +1182,7 @@ medusaIntegrationTestRunner({
}) })
it("when rank is updated, it accurately updates sibling ranks", async () => { it("when rank is updated, it accurately updates sibling ranks", async () => {
const response = await api.post( await api.post(
`/admin/product-categories/${productCategoryChild2.id}`, `/admin/product-categories/${productCategoryChild2.id}`,
{ {
rank: 0, rank: 0,
@@ -1091,7 +1198,7 @@ medusaIntegrationTestRunner({
expect(parentResponse.data.product_category).toEqual( expect(parentResponse.data.product_category).toEqual(
expect.objectContaining({ expect.objectContaining({
id: productCategoryChild2.parent_category_id, id: productCategoryChild2.parent_category_id,
category_children: [ category_children: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: productCategoryChild2.id, id: productCategoryChild2.id,
rank: 0, rank: 0,
@@ -1108,7 +1215,7 @@ medusaIntegrationTestRunner({
id: productCategoryChild3.id, id: productCategoryChild3.id,
rank: 3, rank: 3,
}), }),
], ]),
}) })
) )
}) })
@@ -0,0 +1,61 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
IProductModuleService,
UpdateProductCategoryDTO,
} from "@medusajs/types"
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
type UpdateProductCategoryStepInput = {
id: string
data: UpdateProductCategoryDTO
}
export const updateProductCategoryStepId = "update-product-category"
export const updateProductCategoryStep = createStep(
updateProductCategoryStepId,
async (data: UpdateProductCategoryStepInput, { container }) => {
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
data.data,
])
const prevData = await service.listCategories(
{ id: data.id },
{
select: selects,
relations,
}
)
const updated = await service.updateCategory(data.id, data.data)
return new StepResponse(updated, prevData)
},
async (prevData, { container }) => {
if (!prevData?.length) {
return
}
const service = container.resolve<IProductModuleService>(
ModuleRegistrationName.PRODUCT
)
// TODO: Should be removed when bulk update is implemented
const category = prevData[0]
await service.updateCategory(category.id, {
name: category.name,
description: category.description,
is_active: category.is_active,
is_internal: category.is_internal,
rank: category.rank,
handle: category.handle,
metadata: category.metadata,
parent_category_id: category.parent_category_id,
})
}
)
@@ -1 +1,2 @@
export * from "./create-product-category" export * from "./create-product-category"
export * from "./update-product-category"
@@ -0,0 +1,16 @@
import { ProductCategoryWorkflow } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateProductCategoryStep } from "../steps/update-product-category"
type WorkflowInputData =
ProductCategoryWorkflow.UpdateProductCategoryWorkflowInput
export const updateProductCategoryWorkflowId = "update-product-category"
export const updateProductCategoryWorkflow = createWorkflow(
updateProductCategoryWorkflowId,
(input: WorkflowData<WorkflowInputData>) => {
const category = updateProductCategoryStep(input)
return category
}
)
@@ -1,10 +1,14 @@
import { updateProductCategoryWorkflow } from "@medusajs/core-flows"
import { AdminProductCategoryResponse } from "@medusajs/types" import { AdminProductCategoryResponse } from "@medusajs/types"
import { import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../../types/routing" } from "../../../../types/routing"
import { AdminProductCategoryParamsType } from "../validators"
import { refetchCategory } from "../helpers" import { refetchCategory } from "../helpers"
import {
AdminProductCategoryParamsType,
AdminUpdateProductCategoryType,
} from "../validators"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest<AdminProductCategoryParamsType>, req: AuthenticatedMedusaRequest<AdminProductCategoryParamsType>,
@@ -13,8 +17,35 @@ export const GET = async (
const category = await refetchCategory( const category = await refetchCategory(
req.params.id, req.params.id,
req.scope, req.scope,
req.remoteQueryConfig.fields req.remoteQueryConfig.fields,
req.filterableFields
) )
res.json({ product_category: category }) res.json({ product_category: category })
} }
export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdateProductCategoryType>,
res: MedusaResponse<AdminProductCategoryResponse>
) => {
const { id } = req.params
// TODO: Should be converted to bulk update
const { errors } = await updateProductCategoryWorkflow(req.scope).run({
input: { id, data: req.validatedBody },
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const category = await refetchCategory(
req.params.id,
req.scope,
req.remoteQueryConfig.fields,
req.filterableFields
)
res.status(200).json({ product_category: category })
}
@@ -7,13 +7,14 @@ import {
export const refetchCategory = async ( export const refetchCategory = async (
categoryId: string, categoryId: string,
scope: MedusaContainer, scope: MedusaContainer,
fields: string[] fields: string[],
filterableFields: Record<string, any> = {}
) => { ) => {
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const queryObject = remoteQueryObjectFromString({ const queryObject = remoteQueryObjectFromString({
entryPoint: "product_category", entryPoint: "product_category",
variables: { variables: {
filters: { id: categoryId }, filters: { ...filterableFields, id: categoryId },
}, },
fields: fields, fields: fields,
}) })
@@ -7,6 +7,7 @@ import {
AdminCreateProductCategory, AdminCreateProductCategory,
AdminProductCategoriesParams, AdminProductCategoriesParams,
AdminProductCategoryParams, AdminProductCategoryParams,
AdminUpdateProductCategory,
} from "./validators" } from "./validators"
export const adminProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [ export const adminProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [
@@ -46,4 +47,15 @@ export const adminProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [
), ),
], ],
}, },
{
method: ["POST"],
matcher: "/admin/product-categories/:id",
middlewares: [
validateAndTransformBody(AdminUpdateProductCategory),
validateAndTransformQuery(
AdminProductCategoryParams,
QueryConfig.retrieveProductCategoryConfig
),
],
},
] ]
@@ -11,11 +11,11 @@ import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../types/routing" } from "../../../types/routing"
import { refetchCategory } from "./helpers"
import { import {
AdminCreateProductCategoryType, AdminCreateProductCategoryType,
AdminProductCategoriesParamsType, AdminProductCategoriesParamsType,
} from "./validators" } from "./validators"
import { refetchCategory } from "./helpers"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest<AdminProductCategoriesParamsType>, req: AuthenticatedMedusaRequest<AdminProductCategoriesParamsType>,
@@ -60,7 +60,8 @@ export const POST = async (
const category = await refetchCategory( const category = await refetchCategory(
result.id, result.id,
req.scope, req.scope,
req.remoteQueryConfig.fields req.remoteQueryConfig.fields,
req.filterableFields
) )
res.status(200).json({ product_category: category }) res.status(200).json({ product_category: category })
@@ -68,9 +68,27 @@ export const AdminCreateProductCategory = z
is_active: z.boolean().optional(), is_active: z.boolean().optional(),
parent_category_id: z.string().optional(), parent_category_id: z.string().optional(),
metadata: z.record(z.unknown()).optional(), metadata: z.record(z.unknown()).optional(),
rank: z.number().nonnegative().optional(),
}) })
.strict() .strict()
export type AdminCreateProductCategoryType = z.infer< export type AdminCreateProductCategoryType = z.infer<
typeof AdminCreateProductCategory typeof AdminCreateProductCategory
> >
export const AdminUpdateProductCategory = z
.object({
name: z.string().optional(),
description: z.string().optional(),
handle: z.string().optional(),
is_internal: z.boolean().optional(),
is_active: z.boolean().optional(),
parent_category_id: z.string().optional(),
metadata: z.record(z.unknown()).optional(),
rank: z.number().nonnegative().optional(),
})
.strict()
export type AdminUpdateProductCategoryType = z.infer<
typeof AdminUpdateProductCategory
>
@@ -1,12 +1,13 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
import { import {
deleteProductsWorkflow, deleteProductsWorkflow,
updateProductsWorkflow, updateProductsWorkflow,
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
import { UpdateProductDTO } from "@medusajs/types"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
remoteQueryObjectFromString, remoteQueryObjectFromString,
@@ -17,7 +18,6 @@ import {
remapProductResponse, remapProductResponse,
} from "../helpers" } from "../helpers"
import { AdminUpdateProductType } from "../validators" import { AdminUpdateProductType } from "../validators"
import { UpdateProductDTO } from "@medusajs/types"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
@@ -1,3 +1,4 @@
import { selectorConstraintsToString } from "@medusajs/utils"
import { isDefined, MedusaError } from "medusa-core-utils" import { isDefined, MedusaError } from "medusa-core-utils"
import { Between, EntityManager, MoreThanOrEqual, Not } from "typeorm" import { Between, EntityManager, MoreThanOrEqual, Not } from "typeorm"
import { EventBusService } from "." import { EventBusService } from "."
@@ -17,7 +18,6 @@ import {
UpdateProductCategoryInput, UpdateProductCategoryInput,
} from "../types/product-category" } from "../types/product-category"
import { buildQuery, nullableValue, setMetadata } from "../utils" import { buildQuery, nullableValue, setMetadata } from "../utils"
import {selectorConstraintsToString} from "@medusajs/utils";
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -63,7 +63,9 @@ export class InitialSetup20240315083440 extends Migration {
this.addSql('create unique index if not exists "IDX_category_handle_unique" on "product_category" (handle) where deleted_at is null;') this.addSql('create unique index if not exists "IDX_category_handle_unique" on "product_category" (handle) where deleted_at is null;')
this.addSql('create index if not exists "IDX_product_category_path" on "product_category" ("mpath") where deleted_at is null;'); this.addSql('create index if not exists "IDX_product_category_path" on "product_category" ("mpath") where deleted_at is null;');
this.addSql('create index if not exists "IDX_product_category_deleted_at" on "product_collection" ("deleted_at");'); this.addSql('create index if not exists "IDX_product_category_deleted_at" on "product_collection" ("deleted_at");');
// TODO: Batch updating composite unique index in MikroORM is faulty. Should be added back when issue has been resolved.
this.addSql(`drop index if exists "UniqProductCategoryParentIdRank";`)
/* --- PIVOT TABLES --- */ /* --- PIVOT TABLES --- */
this.addSql('create table if not exists "product_tags" ("product_id" text not null, "product_tag_id" text not null, constraint "product_tags_pkey" primary key ("product_id", "product_tag_id"));'); this.addSql('create table if not exists "product_tags" ("product_id" text not null, "product_tag_id" text not null, constraint "product_tags_pkey" primary key ("product_id", "product_tag_id"));');
this.addSql('create table if not exists "product_images" ("product_id" text not null, "image_id" text not null, constraint "product_images_pkey" primary key ("product_id", "image_id"));'); this.addSql('create table if not exists "product_images" ("product_id" text not null, "image_id" text not null, constraint "product_images_pkey" primary key ("product_id", "image_id"));');
@@ -417,10 +417,10 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
rankCondition = { $gte: targetRank } rankCondition = { $gte: targetRank }
} else if (originalRank > targetRank) { } else if (originalRank > targetRank) {
shouldIncrementRank = true shouldIncrementRank = true
rankCondition = { $gte: targetRank, $lt: originalRank } rankCondition = { $gte: targetRank, $lte: originalRank }
} else { } else {
shouldIncrementRank = false shouldIncrementRank = false
rankCondition = { $gte: originalRank, $lt: targetRank } rankCondition = { $gte: originalRank, $lte: targetRank }
} }
// Scope out the list of siblings that we need to shift up or down // Scope out the list of siblings that we need to shift up or down
+18 -6
View File
@@ -287,23 +287,27 @@ export interface ProductCategoryDTO {
/** /**
* The description of the product category. * The description of the product category.
*/ */
description?: string description: string
/** /**
* The handle of the product category. The handle can be used to create slug URL paths. * The handle of the product category. The handle can be used to create slug URL paths.
*/ */
handle?: string handle: string
/** /**
* Whether the product category is active. * Whether the product category is active.
*/ */
is_active?: boolean is_active: boolean
/** /**
* Whether the product category is internal. This can be used to only show the product category to admins and hide it from customers. * Whether the product category is internal. This can be used to only show the product category to admins and hide it from customers.
*/ */
is_internal?: boolean is_internal: boolean
/** /**
* The ranking of the product category among sibling categories. * The ranking of the product category among sibling categories.
*/ */
rank?: number rank: number
/**
* The ranking of the product category among sibling categories.
*/
metadata?: Record<string, unknown> | null
/** /**
* The associated parent category. * The associated parent category.
* *
@@ -340,6 +344,10 @@ export interface CreateProductCategoryDTO {
* The product category's name. * The product category's name.
*/ */
name: string name: string
/**
* The product category's description.
*/
description?: string
/** /**
* The product category's handle. * The product category's handle.
*/ */
@@ -376,6 +384,10 @@ export interface UpdateProductCategoryDTO {
* The name of the product category. * The name of the product category.
*/ */
name?: string name?: string
/**
* The product category's description.
*/
description?: string
/** /**
* The handle of the product category. * The handle of the product category.
*/ */
@@ -399,7 +411,7 @@ export interface UpdateProductCategoryDTO {
/** /**
* Holds custom data in key-value pairs. * Holds custom data in key-value pairs.
*/ */
metadata?: Record<string, unknown> metadata?: Record<string, unknown> | null
} }
/** /**
@@ -1,5 +1,16 @@
import { CreateProductCategoryDTO } from "../../product" import {
CreateProductCategoryDTO,
UpdateProductCategoryDTO,
} from "../../product"
export interface CreateProductCategoryWorkflowInput { export interface CreateProductCategoryWorkflowInput {
product_category: CreateProductCategoryDTO product_category: CreateProductCategoryDTO
} }
// TODO: Should we converted to bulk update
export interface UpdateProductCategoryWorkflowInput {
// selector: FilterableProductCategoryProps
// data: UpdateProductCategoryDTO
id: string
data: UpdateProductCategoryDTO
}