This commit is contained in:
2026-02-09 12:34:47 +03:30
parent ef53604d91
commit 837614bc31
5 changed files with 47 additions and 68 deletions
+1 -1
View File
@@ -15,6 +15,6 @@ export const API_HEADER_SLUG = {
required: true,
schema: {
type: 'string',
default: 'zhivan',
default: 'boote',
},
};
@@ -5,11 +5,6 @@ import { UpdateCategoryDto } from '../dto/update-category.dto';
import {
ApiTags,
ApiOperation,
ApiCreatedResponse,
ApiOkResponse,
ApiNotFoundResponse,
ApiParam,
ApiBody,
ApiBearerAuth,
ApiHeader,
} from '@nestjs/swagger';
@@ -28,62 +23,55 @@ export class CategoryController {
@Get('public/categories/shop/:slug')
@ApiOperation({ summary: 'Get all categories by shop slug' })
@ApiHeader(API_HEADER_SLUG)
@ApiParam({ name: 'slug', required: true, description: 'Shop Slug' })
@ApiOkResponse({ description: 'List of all categories for the shop' })
findAllByRestaurant(@Param('slug') slug: string) {
return this.categoryService.findAllByShop(slug);
return this.categoryService.findAllByShopSlug(slug);
}
/*** Admin ***/
@Post('admin/categories')
@ApiOperation({ summary: 'Create category' })
@ApiBody({ type: CreateCategoryDto })
@Permissions(Permission.MANAGE_CATEGORIES)
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Post('admin/categories')
create(@Body() dto: CreateCategoryDto, @ShopId() restId: string) {
return this.categoryService.create(restId, dto);
create(@Body() dto: CreateCategoryDto, @ShopId() shopId: string) {
return this.categoryService.create(shopId, dto);
}
@Get('admin/categories')
@Permissions(Permission.MANAGE_CATEGORIES)
@ApiOperation({ summary: 'my shop categories' })
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Get('admin/categories')
findAll(@ShopId() restId: string) {
return this.categoryService.findAllByShopId(restId);
findAll(@ShopId() shopId: string) {
return this.categoryService.findAllByShopId(shopId);
}
@Permissions(Permission.MANAGE_CATEGORIES)
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Get('admin/categories/:id')
@Permissions(Permission.MANAGE_CATEGORIES)
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: 'Get category' })
@ApiParam({ name: 'id', required: true, type: String })
findOne(@Param('id') id: string, @ShopId() restId: string) {
return this.categoryService.findOne(restId, id);
findOne(@Param('id') id: string, @ShopId() shopId: string) {
return this.categoryService.findOne(shopId, id);
}
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Permissions(Permission.MANAGE_CATEGORIES)
@Patch('admin/categories/:id')
@ApiOperation({ summary: 'Update category' })
@ApiParam({ name: 'id' })
@ApiBody({ type: UpdateCategoryDto })
update(@Param('id') id: string, @Body() dto: UpdateCategoryDto, @ShopId() restId: string) {
return this.categoryService.update(restId, id, dto);
}
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Permissions(Permission.MANAGE_CATEGORIES)
@ApiOperation({ summary: 'Update category' })
update(@Param('id') id: string, @Body() dto: UpdateCategoryDto, @ShopId() shopId: string) {
return this.categoryService.update(shopId, id, dto);
}
@Delete('admin/categories/:id')
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@Permissions(Permission.MANAGE_CATEGORIES)
@ApiOperation({ summary: 'Delete category' })
@ApiParam({ name: 'id' })
@ApiOkResponse({ description: 'Deleted' })
remove(@Param('id') id: string, @ShopId() restId: string) {
return this.categoryService.remove(restId, id);
remove(@Param('id') id: string, @ShopId() shopId: string) {
return this.categoryService.remove(shopId, id);
}
}
@@ -26,7 +26,6 @@ export class CreateCategoryDto {
order?: number;
@IsOptional()
@IsUUID()
@ApiPropertyOptional({ example: '123e4567-e89b-12d3-a456-426614174000' })
parentId?: string;
}
@@ -1,4 +1,4 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { CreateCategoryDto } from '../dto/create-category.dto';
import { UpdateCategoryDto } from '../dto/update-category.dto';
import { CategoryRepository } from '../repositories/category.repository';
@@ -44,34 +44,25 @@ export class CategoryService {
return category;
}
async findAllByShop(shopSlug: string): Promise<Category[]> {
async findAllByShopSlug(shopSlug: string): Promise<Category[]> {
return this.categoryRepository.find(
{ shop: { slug: shopSlug }, isActive: true, parent: null },
{ orderBy: { order: 'ASC' }, populate: ['parent'] });
{ orderBy: { order: 'ASC' }, populate: ['children','parent'] });
}
async findAllByShopId(shopId: string): Promise<Category[]> {
return this.categoryRepository.find(
{ shop: { id: shopId } },
{ orderBy: { order: 'asc' }, populate: ['parent'] });
{ orderBy: { order: 'asc' }, populate: ['children','parent'] });
}
async findOne(shopId: string, id: string): Promise<Category> {
const cat = await this.categoryRepository.findOne({ id, shop: { id: shopId } }, { populate: ['products', 'parent'] });
if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND);
async findOne(shopId: string, categoryId: string): Promise<Category> {
const category = await this.findOrFail(categoryId)
if (category.shop.id !== shopId) {
throw new BadRequestException("Category doesnnot belong to shop")
}
return category
return {
id: cat.id,
title: cat.title,
isActive: cat.isActive,
shop: cat.shop,
avatarUrl: cat.avatarUrl,
order: cat.order,
parent: cat.parent,
createdAt: cat.createdAt,
updatedAt: cat.updatedAt,
products: cat.products.getItems().map(f => ({ id: f.id, title: f.title })),
} as unknown as Category;
}
async update(shopId: string, id: string, dto: UpdateCategoryDto): Promise<Category> {
@@ -102,4 +93,10 @@ export class CategoryService {
cat.deletedAt = new Date();
await this.em.persistAndFlush(cat);
}
async findOrFail(categoryId: string) {
const category = await this.categoryRepository.findOne({ id: categoryId },{populate:['parent','children']});
if (!category) throw new NotFoundException(CategoryMessage.NOT_FOUND);
return category
}
}
@@ -6,16 +6,18 @@ import { CategoryRepository } from '../repositories/category.repository';
import { EntityManager } from '@mikro-orm/postgresql';
import { RequiredEntityData, FilterQuery } from '@mikro-orm/core';
import { Product } from '../entities/product.entity';
import { CategoryMessage, ProductMessage, RestMessage } from 'src/common/enums/message.enum';
import { CategoryMessage, ProductMessage } from 'src/common/enums/message.enum';
import { Favorite } from '../entities/favorite.entity';
import { Variant } from '../entities/variant.entity';
import { ShopService } from 'src/modules/shops/providers/shops.service';
import { CategoryService } from './category.service';
@Injectable()
export class ProductService {
constructor(
private readonly productRepository: ProductRepository,
private readonly categoryRepository: CategoryRepository,
private readonly categoryService: CategoryService,
private readonly shopService: ShopService,
private readonly em: EntityManager,
) { }
@@ -23,13 +25,8 @@ export class ProductService {
async create(shopId: string, dto: CreateProductDto) {
const { categoryId, variants, ...rest } = dto;
const shop = await this.shopService.findOrFail(shopId);
if (!shop) {
throw new NotFoundException(RestMessage.NOT_FOUND);
}
const category = await this.categoryRepository.findOne({ id: categoryId, shop: { id: shopId } });
if (!category) {
throw new NotFoundException(CategoryMessage.NOT_FOUND);
}
const category = await this.categoryService.findOrFail(categoryId)
const product = await this.em.transactional(async em => {
// prepare data with defaults for required fields so repository.create typing is satisfied
@@ -50,8 +47,6 @@ export class ProductService {
const product = em.create(Product, data);
em.persist(product)
for (const variant of variants) {
const variantRecord = em.create(Variant, {
product,
@@ -216,7 +211,7 @@ export class ProductService {
* Helper
*/
async findOrFail(productId: string) {
const product = await this.productRepository.findOne({ id: productId, isActive: true },
const product = await this.productRepository.findOne({ id: productId },
{ populate: ['category', 'variants', 'shop'] });
if (!product) throw new NotFoundException(ProductMessage.NOT_FOUND);