diff --git a/src/modules/product/controllers/product.controller.ts b/src/modules/product/controllers/product.controller.ts index 1a0a96d..08bf72e 100644 --- a/src/modules/product/controllers/product.controller.ts +++ b/src/modules/product/controllers/product.controller.ts @@ -20,6 +20,7 @@ import { Permissions } from 'src/common/decorators/permissions.decorator'; import { CreateCategoryDto } from '../dto/create-category.dto'; import { CategoryService } from '../providers/category.service'; import { FindCategoriesDto } from '../dto/find-categories.dto'; +import { UpdateCategoryDto } from '../dto/update-category.dto'; @ApiTags('products') @Controller() @@ -126,4 +127,36 @@ export class productController { const result = await this.categoryService.findAll(dto); return result; } + + + @Get('admin/products/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Get a category by id' }) + @ApiParam({ name: 'id', required: true }) + findCategoryById(@Param('id') id: string) { + return this.categoryService.findById(+id); + } + + @Patch('admin/products/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Update a category' }) + @ApiParam({ name: 'id', required: true }) + @ApiBody({ type: UpdateCategoryDto }) + updateCategory(@Param('id') id: string, @Body() dto: UpdateCategoryDto) { + return this.categoryService.update(+id, dto); + } + + @Delete('admin/products/category/:id') + // @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_productS) + @ApiOperation({ summary: 'Delete (soft) a category' }) + @ApiParam({ name: 'id', required: true }) + removeCategory(@Param('id') id: string,) { + return this.categoryService.remove(+id); + } } diff --git a/src/modules/product/entities/category.entity.ts b/src/modules/product/entities/category.entity.ts index a46aa0a..2197769 100644 --- a/src/modules/product/entities/category.entity.ts +++ b/src/modules/product/entities/category.entity.ts @@ -15,7 +15,7 @@ export class Category extends BaseEntity { @PrimaryKey({ type: 'bigint', autoincrement: true }) id: number - @Property({ unique: true }) + @Property() title: string; // @OneToMany(() => Product, product => product.category) diff --git a/src/modules/product/providers/category.service.ts b/src/modules/product/providers/category.service.ts index e0dfe43..265f9ca 100644 --- a/src/modules/product/providers/category.service.ts +++ b/src/modules/product/providers/category.service.ts @@ -1,22 +1,18 @@ import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common'; -import { CreateproductDto } from '../dto/create-product.dto'; -import { FindproductsDto } from '../dto/find-products.dto'; -import { ProductRepository } from '../repositories/product.repository'; import { EntityManager } from '@mikro-orm/postgresql'; import { RequiredEntityData } from '@mikro-orm/core'; -import { Product } from '../entities/product.entity'; -import { CategoryMessage, productMessage } from 'src/common/enums/message.enum'; + import { CategoryMessage, productMessage } from 'src/common/enums/message.enum'; import { CategoryRepository } from '../repositories/category.repository'; import { CreateCategoryDto } from '../dto/create-category.dto'; import { Category } from '../entities/category.entity'; import { FindCategoriesDto } from '../dto/find-categories.dto'; +import { UpdateCategoryDto } from '../dto/update-category.dto'; @Injectable() export class CategoryService { constructor( - private readonly productRepository: ProductRepository, - private readonly categoryRepository: CategoryRepository, + private readonly categoryRepository: CategoryRepository, private readonly em: EntityManager, ) { } @@ -46,97 +42,57 @@ export class CategoryService { } - // async update(productId: string, createproductDto: Partial) { - // const { categoryId, ...rest } = createproductDto; - // const product = await this.productRepository.findOne({ id: productId }) - // if (!product) { - // throw new NotFoundException(productMessage.NOT_FOUND); - // } + async update(categoryId: number, dto: UpdateCategoryDto) { - // if (categoryId) { - // const category = await this.categoryRepository.findOne({ id: categoryId }); - // if (!category) { - // throw new NotFoundException(CategoryMessage.NOT_FOUND); - // } - // this.productRepository.assign(product, { category }) - // } + const category = await this.categoryRepository.findOne({ id: categoryId }) - // this.productRepository.assign(product, rest) - // //TODO : which one od these are correct - // // this.productRepository.nativeUpdate(productId,product) - // this.em.persistAndFlush(product) + if (!category) { + throw new NotFoundException(CategoryMessage.NOT_FOUND); + } - // } + + if (dto.parentId) { + console.log('pp', dto.parentId) + const parent = await this.categoryRepository.findOne({ id: dto.parentId }) + if (!parent) { + throw new NotFoundException(CategoryMessage.NOT_FOUND); + } + + this.categoryRepository.assign(category, { parent }) + } + + this.categoryRepository.assign(category, dto) + //TODO : which one od these are correct + // this.productRepository.nativeUpdate(productId,product) + this.em.persistAndFlush(category) + + return category + + } findAll(dto: FindCategoriesDto) { return this.categoryRepository.findAllPaginated(dto); } - async findById(productId: string): Promise { - const product = await this.productRepository.findOne({ id: productId }, { populate: ['category', 'attributes'] }); + async findById(catId: number): Promise { + const category = await this.categoryRepository.findOne({ id: catId }, + { populate: ['children', 'parent'] }); - if (!product) throw new NotFoundException(productMessage.NOT_FOUND); - return product; + if (!category) throw new NotFoundException(CategoryMessage.NOT_FOUND); + return category; } - // async update( id: string, dto: Partial): Promise { - // const { categoryId, dailyStock, ...rest } = dto; - // const product = await this.productRepository.findOne({ id, restaurant: { id: } }, { populate: ['restaurant'] }); - // if (!product) { - // throw new NotFoundException(productMessage.NOT_FOUND); - // } - // // attach new categories if provided (adds, does not attempt to preserve/remove existing ones) - // if (categoryId) { - // const category = await this.categoryRepository.findOne({ id: categoryId, restaurant: { id: } }); - - // if (!category) { - // throw new NotFoundException(CategoryMessage.NOT_FOUND); - // } - - // this.em.assign(product, { category: category }); - // } - - // // assign other fields from DTO (excluding dailyStock handled below) - // this.em.assign(product, rest); - - // // Persist product and update/create related inventory atomically - // await this.em.transactional(async em => { - // await em.persistAndFlush(product); - - // if (typeof dailyStock !== 'undefined') { - // const inventoryRecord = await em.findOne(Inventory, { product: product }); - // if (inventoryRecord) { - // inventoryRecord.totalStock = dailyStock; - // } else { - // em.create(Inventory, { - // product: product, - // availableStock: dailyStock, - // totalStock: dailyStock, - // }); - // } - // } - - // await em.flush(); - // }); - - // // Re-load the product to ensure populated relations and stable instance - // const savedproduct = await this.productRepository.findOne({ id: product.id }, { populate: ['category', 'restaurant'] }); - - // // Invalidate cache for the restaurant if present (optional) - // // await this.invalidateRestaurantproductsCache(savedproduct?.restaurant?.slug); - - // return savedproduct ?? product; - // } - - async remove(id: string): Promise { - const product = await this.productRepository.findOne({ id }); - if (!product) { + async remove(id: number): Promise { + const category = await this.findById(id); + if (!category) { throw new NotFoundException(productMessage.NOT_FOUND); } - - product.deletedAt = new Date(); - return await this.em.persistAndFlush(product); + if (category.children && category.children.length > 0) { + throw new NotFoundException('Category has children'); + } + category.deletedAt = new Date(); + return await this.em.persistAndFlush(category); }