import { BadRequestException, ConflictException, ForbiddenException, Injectable, NotFoundException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Children, StatutEnfantType } from 'src/entities/children.entity'; import { Parents } from 'src/entities/parents.entity'; import { ParentsChildren } from 'src/entities/parents_children.entity'; import { RoleType, Users } from 'src/entities/users.entity'; import { CreateEnfantsDto } from './dto/create_enfants.dto'; @Injectable() export class EnfantsService { constructor( @InjectRepository(Children) private readonly childrenRepository: Repository, @InjectRepository(Parents) private readonly parentsRepository: Repository, @InjectRepository(ParentsChildren) private readonly parentsChildrenRepository: Repository, ) { } // Création d'un enfant async create(dto: CreateEnfantsDto, currentUser: Users, photoFile?: Express.Multer.File): Promise { const parent = await this.parentsRepository.findOne({ where: { user_id: currentUser.id }, relations: ['co_parent'], }); if (!parent) throw new NotFoundException('Parent introuvable'); // Vérif métier simple if (dto.status !== StatutEnfantType.A_NAITRE && !dto.birth_date) { throw new BadRequestException('Un enfant actif doit avoir une date de naissance'); } // Vérif doublon éventuel (ex: même prénom + date de naissance pour ce parent) const exist = await this.childrenRepository.findOne({ where: { first_name: dto.first_name, last_name: dto.last_name, birth_date: dto.birth_date ? new Date(dto.birth_date) : undefined, }, }); if (exist) throw new ConflictException('Cet enfant existe déjà'); // Gestion de la photo uploadée if (photoFile) { dto.photo_url = `/uploads/photos/${photoFile.filename}`; if (dto.consent_photo) { dto.consent_photo_at = new Date().toISOString(); } } // Création const child = this.childrenRepository.create(dto); await this.childrenRepository.save(child); // Lien parent-enfant (Parent 1) const parentLink = this.parentsChildrenRepository.create({ parentId: parent.user_id, enfantId: child.id, }); await this.parentsChildrenRepository.save(parentLink); // Rattachement automatique au co-parent s'il existe if (parent.co_parent) { const coParentLink = this.parentsChildrenRepository.create({ parentId: parent.co_parent.id, enfantId: child.id, }); await this.parentsChildrenRepository.save(coParentLink); } return this.findOne(child.id, currentUser); } // Liste des enfants async findAll(): Promise { return this.childrenRepository.find({ relations: ['parentLinks'], order: { last_name: 'ASC', first_name: 'ASC' }, }); } // Récupérer un enfant par id async findOne(id: string, currentUser: Users): Promise { const child = await this.childrenRepository.findOne({ where: { id }, relations: ['parentLinks'], }); if (!child) throw new NotFoundException('Enfant introuvable'); switch (currentUser.role) { case RoleType.PARENT: if (!child.parentLinks.some(link => link.parentId === currentUser.id)) { throw new ForbiddenException('Cet enfant ne vous appartient pas'); } break; case RoleType.ADMINISTRATEUR: case RoleType.SUPER_ADMIN: case RoleType.GESTIONNAIRE: // accès complet break; default: throw new ForbiddenException('Accès interdit'); } return child; } // Mise à jour async update(id: string, dto: Partial, currentUser: Users): Promise { const child = await this.childrenRepository.findOne({ where: { id } }); if (!child) throw new NotFoundException('Enfant introuvable'); await this.childrenRepository.update(id, dto); return this.findOne(id, currentUser); } // Suppression async remove(id: string): Promise { await this.childrenRepository.delete(id); } }