From 8e313c9b0413d2021e19e25362722b75bef9fd0c Mon Sep 17 00:00:00 2001 From: sdraris Date: Wed, 1 Oct 2025 21:45:39 +0200 Subject: [PATCH] enfants corrected --- src/routes/enfants/dto/create_enfants.dto.ts | 66 +++++++++++++ .../enfants/dto/enfants_response.dto.ts | 37 ++++++++ src/routes/enfants/dto/update_enfants.dto.ts | 4 + src/routes/enfants/enfants.controller.spec.ts | 18 ++++ src/routes/enfants/enfants.controller.ts | 50 ++++++++++ src/routes/enfants/enfants.module.ts | 14 +++ src/routes/enfants/enfants.service.spec.ts | 18 ++++ src/routes/enfants/enfants.service.ts | 93 +++++++++++++++++++ 8 files changed, 300 insertions(+) create mode 100644 src/routes/enfants/dto/create_enfants.dto.ts create mode 100644 src/routes/enfants/dto/enfants_response.dto.ts create mode 100644 src/routes/enfants/dto/update_enfants.dto.ts create mode 100644 src/routes/enfants/enfants.controller.spec.ts create mode 100644 src/routes/enfants/enfants.controller.ts create mode 100644 src/routes/enfants/enfants.module.ts create mode 100644 src/routes/enfants/enfants.service.spec.ts create mode 100644 src/routes/enfants/enfants.service.ts diff --git a/src/routes/enfants/dto/create_enfants.dto.ts b/src/routes/enfants/dto/create_enfants.dto.ts new file mode 100644 index 0000000..7b55282 --- /dev/null +++ b/src/routes/enfants/dto/create_enfants.dto.ts @@ -0,0 +1,66 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsBoolean, + IsDateString, + IsEnum, + IsNotEmpty, + IsOptional, + IsString, + MaxLength, + ValidateIf, +} from 'class-validator'; +import { GenreType, StatutEnfantType } from 'src/entities/children.entity'; + +export class CreateEnfantsDto { + @ApiProperty({ enum: StatutEnfantType, example: StatutEnfantType.ACTIF }) + @IsEnum(StatutEnfantType) + @IsNotEmpty() + status: StatutEnfantType; + + @ApiProperty({ example: 'Georges', required: false }) + @IsOptional() + @IsString() + @MaxLength(100) + first_name?: string; + + @ApiProperty({ example: 'Dupont', required: false }) + @IsOptional() + @IsString() + @MaxLength(100) + last_name?: string; + + @ApiProperty({ enum: GenreType, required: false }) + @IsOptional() + @IsEnum(GenreType) + gender?: GenreType; + + @ApiProperty({ example: '2018-06-24', required: false }) + @ValidateIf(o => o.status !== StatutEnfantType.A_NAITRE) + @IsOptional() + @IsDateString() + birth_date?: string; + + @ApiProperty({ example: '2025-12-15', required: false }) + @ValidateIf(o => o.status === StatutEnfantType.A_NAITRE) + @IsOptional() + @IsDateString() + due_date?: string; + + @ApiProperty({ example: 'https://monimage.com/photo.jpg', required: false }) + @IsOptional() + @IsString() + photo_url?: string; + + @ApiProperty({ default: false }) + @IsBoolean() + consent_photo: boolean; + + @ApiProperty({ required: false }) + @IsOptional() + @IsDateString() + consent_photo_at?: string; + + @ApiProperty({ default: false }) + @IsBoolean() + is_multiple: boolean; +} diff --git a/src/routes/enfants/dto/enfants_response.dto.ts b/src/routes/enfants/dto/enfants_response.dto.ts new file mode 100644 index 0000000..41f0b1e --- /dev/null +++ b/src/routes/enfants/dto/enfants_response.dto.ts @@ -0,0 +1,37 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { GenreType, StatutEnfantType } from 'src/entities/children.entity'; + +export class EnfantResponseDto { + @ApiProperty({ example: 'UUID-enfant' }) + id: string; + + @ApiProperty({ enum: StatutEnfantType }) + status: StatutEnfantType; + + @ApiProperty({ example: 'Georges', required: false }) + first_name?: string; + + @ApiProperty({ example: 'Dupont', required: false }) + last_name?: string; + + @ApiProperty({ enum: GenreType, required: false }) + gender?: GenreType; + + @ApiProperty({ example: '2018-06-24', required: false }) + birth_date?: string; + + @ApiProperty({ example: '2025-12-15', required: false }) + due_date?: string; + + @ApiProperty({ example: 'https://monimage.com/photo.jpg', required: false }) + photo_url?: string; + + @ApiProperty({ example: false }) + consent_photo: boolean; + + @ApiProperty({ example: false }) + is_multiple: boolean; + + @ApiProperty({ example: 'UUID-parent' }) + parent_id: string; +} diff --git a/src/routes/enfants/dto/update_enfants.dto.ts b/src/routes/enfants/dto/update_enfants.dto.ts new file mode 100644 index 0000000..bcaea31 --- /dev/null +++ b/src/routes/enfants/dto/update_enfants.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateEnfantsDto } from './create_enfants.dto'; + +export class UpdateEnfantsDto extends PartialType(CreateEnfantsDto) {} diff --git a/src/routes/enfants/enfants.controller.spec.ts b/src/routes/enfants/enfants.controller.spec.ts new file mode 100644 index 0000000..04e9e0e --- /dev/null +++ b/src/routes/enfants/enfants.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { EnfantsController } from './enfants.controller'; + +describe('EnfantsController', () => { + let controller: EnfantsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [EnfantsController], + }).compile(); + + controller = module.get(EnfantsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/routes/enfants/enfants.controller.ts b/src/routes/enfants/enfants.controller.ts new file mode 100644 index 0000000..6e0ac8d --- /dev/null +++ b/src/routes/enfants/enfants.controller.ts @@ -0,0 +1,50 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + ParseUUIDPipe, + Patch, + Post, +} from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { EnfantsService } from './enfants.service'; +import { CreateEnfantsDto } from './dto/create_enfants.dto'; +import { UpdateEnfantsDto } from './dto/update_enfants.dto'; +import { Users } from 'src/entities/users.entity'; +import { User } from 'src/common/decorators/user.decorator'; + +@ApiTags('Enfants') +@Controller('enfants') +export class EnfantsController { + constructor(private readonly enfantsService: EnfantsService) {} + + @Post() + create(@Body() dto: CreateEnfantsDto, @User() currentUser: Users) { + return this.enfantsService.create(dto, currentUser); + } + + @Get() + findAll() { + return this.enfantsService.findAll(); + } + + @Get(':id') + findOne(@Param('id', new ParseUUIDPipe()) id: string) { + return this.enfantsService.findOne(id); + } + + @Patch(':id') + update( + @Param('id', new ParseUUIDPipe()) id: string, + @Body() dto: UpdateEnfantsDto, + ) { + return this.enfantsService.update(id, dto); + } + + @Delete(':id') + remove(@Param('id', new ParseUUIDPipe()) id: string) { + return this.enfantsService.remove(id); + } +} diff --git a/src/routes/enfants/enfants.module.ts b/src/routes/enfants/enfants.module.ts new file mode 100644 index 0000000..cd749e3 --- /dev/null +++ b/src/routes/enfants/enfants.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { EnfantsController } from './enfants.controller'; +import { EnfantsService } from './enfants.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Children } from 'src/entities/children.entity'; +import { Parents } from 'src/entities/parents.entity'; +import { ParentsChildren } from 'src/entities/parents_children.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Children, Parents, ParentsChildren])], + controllers: [EnfantsController], + providers: [EnfantsService] +}) +export class EnfantsModule {} diff --git a/src/routes/enfants/enfants.service.spec.ts b/src/routes/enfants/enfants.service.spec.ts new file mode 100644 index 0000000..c1ded59 --- /dev/null +++ b/src/routes/enfants/enfants.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { EnfantsService } from './enfants.service'; + +describe('EnfantsService', () => { + let service: EnfantsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [EnfantsService], + }).compile(); + + service = module.get(EnfantsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/routes/enfants/enfants.service.ts b/src/routes/enfants/enfants.service.ts new file mode 100644 index 0000000..fbb31b2 --- /dev/null +++ b/src/routes/enfants/enfants.service.ts @@ -0,0 +1,93 @@ +import { + BadRequestException, + ConflictException, + 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 { 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): Promise { + const parent = await this.parentsRepository.findOne({ + where: { user_id: currentUser.id }, + }); + 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à'); + + // Création + const child = this.childrenRepository.create(dto); + await this.childrenRepository.save(child); + + // Lien parent-enfant + const parentLink = this.parentsChildrenRepository.create({ + parentId: parent.user_id, + enfantId: child.id, + }); + await this.parentsChildrenRepository.save(parentLink); + + return this.findOne(child.id); + } + + // 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): Promise { + const child = await this.childrenRepository.findOne({ + where: { id }, + relations: ['parentLinks'], + }); + if (!child) throw new NotFoundException('Enfant introuvable'); + return child; + } + + // Mise à jour + async update(id: string, dto: Partial): 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); + } + + // Suppression + async remove(id: string): Promise { + await this.childrenRepository.delete(id); + } +}