import { 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'; import { EntityManager } from '@mikro-orm/postgresql'; import { RequiredEntityData } from '@mikro-orm/core'; import { Category } from '../entities/category.entity'; import { CategoryMessage, RestMessage } from 'src/common/enums/message.enum'; import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity'; @Injectable() export class CategoryService { constructor( private readonly categoryRepository: CategoryRepository, private readonly em: EntityManager, ) { } async create(restId: string, dto: CreateCategoryDto): Promise { const restaurant = await this.em.findOne(Restaurant, { id: restId }); if (!restaurant) { throw new NotFoundException(RestMessage.NOT_FOUND); } const data: RequiredEntityData = { title: dto.title, isActive: dto.isActive ?? true, restaurant: restaurant, avatarUrl: dto.avatarUrl, }; const category = this.categoryRepository.create(data); await this.em.persistAndFlush(category); return category; } async findAllByRestaurant(slug: string): Promise { const restaurant = await this.em.findOne(Restaurant, { slug }); if (!restaurant || !restaurant.id) { throw new NotFoundException(RestMessage.NOT_FOUND); } return this.categoryRepository.find( { restaurant: restaurant, isActive: true }, { orderBy: { order: 'ASC' } }); } async findAllByRestaurantId(restId: string): Promise { return this.categoryRepository.find({ restaurant: { id: restId } }); } // async findAll(opts?: { restId?: string; isActive?: boolean }): Promise { // const where: FilterQuery = {}; // if (opts?.restId) where.restId = opts.restId; // if (opts && typeof opts.isActive === 'boolean') where.isActive = opts.isActive; // const cats = await this.categoryRepository.find(where, { populate: ['foods'] }); // // Return plain objects to avoid circular references during JSON serialization // return cats.map(cat => ({ // id: cat.id, // title: cat.title, // isActive: cat.isActive, // restId: cat.restId, // avatarUrl: cat.avatarUrl, // createdAt: cat.createdAt, // updatedAt: cat.updatedAt, // foods: cat.foods.getItems().map(f => ({ id: f.id, title: f.title })), // })) as unknown as Category[]; // } async findOne(restId: string, id: string): Promise { const cat = await this.categoryRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['foods'] }); if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND); return { id: cat.id, title: cat.title, isActive: cat.isActive, restaurant: cat.restaurant, avatarUrl: cat.avatarUrl, createdAt: cat.createdAt, updatedAt: cat.updatedAt, foods: cat.foods.getItems().map(f => ({ id: f.id, title: f.title })), } as unknown as Category; } async findRestaurantCategories(restId: string): Promise { const cat = await this.categoryRepository.findOne({ restaurant: { id: restId } }, { populate: ['foods'] }); if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND); return { id: cat.id, title: cat.title, isActive: cat.isActive, restaurant: cat.restaurant, avatarUrl: cat.avatarUrl, createdAt: cat.createdAt, updatedAt: cat.updatedAt, } as unknown as Category; } async update(restId: string, id: string, dto: UpdateCategoryDto): Promise { const cat = await this.categoryRepository.findOne({ id, restaurant: { id: restId } }); if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND); this.em.assign(cat, dto); await this.em.persistAndFlush(cat); return cat; } async remove(restId: string, id: string): Promise { const cat = await this.categoryRepository.findOne({ id, restaurant: { id: restId } }); if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND); cat.deletedAt = new Date(); await this.em.persistAndFlush(cat); } }