import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../../../prisma/prisma.service'; import { CreatePatientDto } from './dto/create-patient.dto'; import { ListPatientsDto } from './dto/list-patients.dto'; import { UpdatePatientDto } from './dto/update-patient.dto'; import { CreateTreatmentHistoryDto } from './dto/create-treatment-history.dto'; @Injectable() export class PatientsService { constructor(private readonly prisma: PrismaService) {} async create(createPatientDto: CreatePatientDto, organizationId: string) { const patient = await this.prisma.patient.create({ data: { ...createPatientDto, dateOfBirth: createPatientDto.dateOfBirth ? new Date(createPatientDto.dateOfBirth) : null, organizationId, }, }); return { success: true, data: patient }; } async findAll(query: ListPatientsDto, organizationId: string) { const { page = 1, limit = 10, q } = query; const skip = (page - 1) * limit; const where: Prisma.PatientWhereInput = { organizationId, ...(q ? { OR: [ { firstName: { contains: q, mode: 'insensitive' } }, { lastName: { contains: q, mode: 'insensitive' } }, { email: { contains: q, mode: 'insensitive' } }, { phone: { contains: q, mode: 'insensitive' } }, ], } : {}), }; const [items, total] = await Promise.all([ this.prisma.patient.findMany({ where, skip, take: limit, orderBy: [{ updatedAt: 'desc' }], }), this.prisma.patient.count({ where }), ]); return { success: true, data: { items, pagination: { page, limit, total, totalPages: Math.max(1, Math.ceil(total / limit)), }, }, }; } async findOne(id: string, organizationId: string) { const patient = await this.prisma.patient.findFirst({ where: { id, organizationId }, }); if (!patient) { throw new NotFoundException('Patient not found'); } return { success: true, data: patient }; } async update(id: string, updatePatientDto: UpdatePatientDto, organizationId: string) { await this.ensurePatient(id, organizationId); const patient = await this.prisma.patient.update({ where: { id }, data: { ...updatePatientDto, dateOfBirth: updatePatientDto.dateOfBirth ? new Date(updatePatientDto.dateOfBirth) : undefined, }, }); return { success: true, data: patient }; } async findTreatments(patientId: string, organizationId: string, limit = 20) { await this.ensurePatient(patientId, organizationId); const items = await this.prisma.patientTreatmentHistory.findMany({ where: { patientId }, orderBy: [{ treatmentAt: 'desc' }], take: limit, }); return { success: true, data: items }; } async addTreatment( patientId: string, dto: CreateTreatmentHistoryDto, organizationId: string, ) { await this.ensurePatient(patientId, organizationId); const treatment = await this.prisma.patientTreatmentHistory.create({ data: { ...dto, treatmentAt: new Date(dto.treatmentAt), patientId, }, }); return { success: true, data: treatment }; } private async ensurePatient(id: string, organizationId: string) { const patient = await this.prisma.patient.findFirst({ where: { id, organizationId }, select: { id: true }, }); if (!patient) { throw new NotFoundException('Patient not found'); } } getOrganizationIdFromUser(user: { organizationId?: string }) { if (!user?.organizationId) { throw new BadRequestException('Organization is not selected'); } return user.organizationId; } }