import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { EntityManager } from '@mikro-orm/postgresql'; import { CreateRequestDto } from './dto/create-request.dto'; import { UpdateRequestDto } from './dto/update-request.dto'; import { FindRequestsDto } from './dto/find-requests.dto'; import { Request } from './entities/request.entity'; import { RequestItem } from './entities/request-item.entity'; import { RequestStatusEnum } from './enum/request'; import { UserService } from '../user/providers/user.service'; import { ProductService } from '../product/providers/product.service'; import { RequestRepository } from './repositories/request.repository'; @Injectable() export class RequestService { constructor( private readonly em: EntityManager, private readonly requestRepository: RequestRepository, private readonly userService: UserService, private readonly productService: ProductService, ) { } async create(createRequestDto: CreateRequestDto, userId: string) { const { items } = createRequestDto; const user = await this.userService.findOrFail(userId); return this.em.transactional(async (em) => { const request = em.create(Request, { user, status: RequestStatusEnum.PENDING, }); em.persist(request); for (const item of items) { const product = await this.productService.findOneOrFail(item.productId); const requestItem = em.create(RequestItem, { request, product, quantity: item.quantity, attributes: item.attributes, description: item.description, attachments: item.attachments, }); request.items.add(requestItem); } await em.flush(); return request; }); } findAll(userId: string, dto: FindRequestsDto) { return this.requestRepository.findAllPaginated({ userId, ...dto }); } findAllAsAdmin(dto: FindRequestsDto) { return this.requestRepository.findAllPaginated(dto); } async findOne(id: string, userId: string) { const request = await this.requestRepository.findOne( { id, user: { id: userId } }, { populate: ['items', 'items.product', 'user'] }, ); if (!request) { throw new NotFoundException('Request not found'); } return request; } async findOneAsAdmin(id: string) { const request = await this.requestRepository.findOne( { id }, { populate: ['items', 'items.product', 'user'] }, ); if (!request) { throw new NotFoundException('Request not found'); } return request; } async update(id: string, updateRequestDto: UpdateRequestDto, userId: string) { const request = await this.requestRepository.findOne( { id, user: { id: userId } }, { populate: ['items', 'items.product', 'user'] }, ); if (!request) { throw new NotFoundException('Request not found'); } if (request.status !== RequestStatusEnum.PENDING) { throw new BadRequestException('Only pending requests can be updated'); } const { items } = updateRequestDto; if (items?.length) { return this.em.transactional(async (em) => { request.items.removeAll(); await em.flush(); for (const item of items) { const product = await this.productService.findOneOrFail(item.productId); const requestItem = em.create(RequestItem, { request, product, quantity: item.quantity, attributes: item.attributes, description: item.description, attachments: item.attachments, }); request.items.add(requestItem); } await em.flush(); return request; }); } return request; } async updateAsAdmin(id: string, updateRequestDto: UpdateRequestDto) { const request = await this.requestRepository.findOne( { id }, { populate: ['items', 'items.product', 'user'] }, ); if (!request) { throw new NotFoundException('Request not found'); } const { items } = updateRequestDto; if (items?.length) { return this.em.transactional(async (em) => { request.items.removeAll(); await em.flush(); for (const item of items) { const product = await this.productService.findOneOrFail(item.productId); const requestItem = em.create(RequestItem, { request, product, quantity: item.quantity, attributes: item.attributes, description: item.description, attachments: item.attachments, }); request.items.add(requestItem); } await em.flush(); return request; }); } return request; } async remove(id: string, userId: string) { const request = await this.requestRepository.findOne( { id, user: { id: userId } }, ); if (!request) { throw new NotFoundException('Request not found'); } if (request.status !== RequestStatusEnum.PENDING) { throw new BadRequestException('Only pending requests can be deleted'); } request.deletedAt = new Date(); await this.em.flush(); return request; } async removeAsAdmin(id: string) { const request = await this.requestRepository.findOne( { id }, ); if (!request) { throw new NotFoundException('Request not found'); } request.deletedAt = new Date(); await this.em.flush(); return request; } }