diff --git a/backend/src/entities/dossier_famille.entity.ts b/backend/src/entities/dossier_famille.entity.ts new file mode 100644 index 0000000..92082ed --- /dev/null +++ b/backend/src/entities/dossier_famille.entity.ts @@ -0,0 +1,65 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + OneToMany, + CreateDateColumn, + UpdateDateColumn, + JoinColumn, +} from 'typeorm'; +import { Parents } from './parents.entity'; +import { Children } from './children.entity'; +import { StatutDossierType } from './dossiers.entity'; + +/** Un dossier = une famille, N enfants (texte de motivation unique, liste d'enfants). */ +@Entity('dossier_famille') +export class DossierFamille { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ name: 'numero_dossier', length: 20 }) + numero_dossier: string; + + @ManyToOne(() => Parents, { onDelete: 'CASCADE', nullable: false }) + @JoinColumn({ name: 'id_parent', referencedColumnName: 'user_id' }) + parent: Parents; + + @Column({ type: 'text', nullable: true }) + presentation?: string; + + @Column({ + type: 'enum', + enum: StatutDossierType, + enumName: 'statut_dossier_type', + default: StatutDossierType.ENVOYE, + name: 'statut', + }) + statut: StatutDossierType; + + @CreateDateColumn({ name: 'cree_le', type: 'timestamptz' }) + cree_le: Date; + + @UpdateDateColumn({ name: 'modifie_le', type: 'timestamptz' }) + modifie_le: Date; + + @OneToMany(() => DossierFamilleEnfant, (dfe) => dfe.dossier_famille) + enfants: DossierFamilleEnfant[]; +} + +@Entity('dossier_famille_enfants') +export class DossierFamilleEnfant { + @Column({ name: 'id_dossier_famille', primary: true }) + id_dossier_famille: string; + + @Column({ name: 'id_enfant', primary: true }) + id_enfant: string; + + @ManyToOne(() => DossierFamille, (df) => df.enfants, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'id_dossier_famille' }) + dossier_famille: DossierFamille; + + @ManyToOne(() => Children, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'id_enfant' }) + enfant: Children; +} diff --git a/backend/src/routes/parents/dto/dossier-famille-complet.dto.ts b/backend/src/routes/parents/dto/dossier-famille-complet.dto.ts index 2d1dc9d..778a589 100644 --- a/backend/src/routes/parents/dto/dossier-famille-complet.dto.ts +++ b/backend/src/routes/parents/dto/dossier-famille-complet.dto.ts @@ -15,6 +15,12 @@ export class DossierFamilleParentDto { nom?: string; @ApiProperty({ required: false }) telephone?: string; + @ApiProperty({ required: false }) + adresse?: string; + @ApiProperty({ required: false }) + ville?: string; + @ApiProperty({ required: false }) + code_postal?: string; @ApiProperty({ enum: StatutUtilisateurType }) statut: StatutUtilisateurType; @ApiProperty({ required: false, description: 'Id du co-parent si couple' }) @@ -39,7 +45,7 @@ export class DossierFamilleEnfantDto { status: StatutEnfantType; } -/** Dossier (parent+enfant) avec presentation */ +/** Dossier (parent+enfant) avec presentation – inscription famille, pas dossier de garde */ export class DossierFamillePresentationDto { @ApiProperty() id: string; @@ -47,14 +53,8 @@ export class DossierFamillePresentationDto { id_parent: string; @ApiProperty() id_enfant: string; - @ApiProperty({ required: false, description: 'Texte de présentation' }) + @ApiProperty({ required: false, description: 'Texte de motivation' }) presentation?: string; - @ApiProperty({ required: false }) - type_contrat?: string; - @ApiProperty() - repas: boolean; - @ApiProperty({ required: false }) - budget?: number; @ApiProperty({ enum: StatutDossierType }) statut: StatutDossierType; } diff --git a/backend/src/routes/parents/parents.module.ts b/backend/src/routes/parents/parents.module.ts index c2a89db..7506259 100644 --- a/backend/src/routes/parents/parents.module.ts +++ b/backend/src/routes/parents/parents.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { JwtModule } from '@nestjs/jwt'; import { Parents } from 'src/entities/parents.entity'; +import { DossierFamille, DossierFamilleEnfant } from 'src/entities/dossier_famille.entity'; import { ParentsController } from './parents.controller'; import { ParentsService } from './parents.service'; import { Users } from 'src/entities/users.entity'; @@ -10,7 +11,7 @@ import { UserModule } from '../user/user.module'; @Module({ imports: [ - TypeOrmModule.forFeature([Parents, Users]), + TypeOrmModule.forFeature([Parents, Users, DossierFamille, DossierFamilleEnfant]), forwardRef(() => UserModule), JwtModule.registerAsync({ imports: [ConfigModule], diff --git a/backend/src/routes/parents/parents.service.ts b/backend/src/routes/parents/parents.service.ts index 03cd29b..d151d4d 100644 --- a/backend/src/routes/parents/parents.service.ts +++ b/backend/src/routes/parents/parents.service.ts @@ -7,6 +7,7 @@ import { import { InjectRepository } from '@nestjs/typeorm'; import { In, Repository } from 'typeorm'; import { Parents } from 'src/entities/parents.entity'; +import { DossierFamille } from 'src/entities/dossier_famille.entity'; import { RoleType, Users } from 'src/entities/users.entity'; import { CreateParentDto } from '../user/dto/create_parent.dto'; import { UpdateParentsDto } from '../user/dto/update_parent.dto'; @@ -25,6 +26,8 @@ export class ParentsService { private readonly parentsRepository: Repository, @InjectRepository(Users) private readonly usersRepository: Repository, + @InjectRepository(DossierFamille) + private readonly dossierFamilleRepository: Repository, ) {} // Création d’un parent @@ -165,7 +168,29 @@ export class ParentsService { relations: ['user', 'co_parent', 'parentChildren', 'parentChildren.child', 'dossiers', 'dossiers.child'], }); const enfantsMap = new Map(); - const presentationList: DossierFamillePresentationDto[] = []; + let presentationList: DossierFamillePresentationDto[] = []; + + // Un dossier = une famille : priorité à dossier_famille (un texte, N enfants) + const dossierFamille = await this.dossierFamilleRepository.findOne({ + where: { numero_dossier: num }, + relations: ['parent', 'enfants', 'enfants.enfant'], + }); + if (dossierFamille?.enfants?.length) { + const idParent = dossierFamille.parent?.user_id ?? familyUserIds[0]; + for (const dfe of dossierFamille.enfants) { + const idEnfant = dfe.enfant?.id ?? dfe.id_enfant; + if (idEnfant) { + presentationList.push({ + id: dossierFamille.id, + id_parent: idParent, + id_enfant: idEnfant, + presentation: dossierFamille.presentation, + statut: dossierFamille.statut, + }); + } + } + } + for (const p of parents) { // Enfants via parentChildren if (p.parentChildren) { @@ -183,17 +208,14 @@ export class ParentsService { } } } - // Dossiers (présentation) - if (p.dossiers) { + // Si pas de dossier_famille : fallback sur anciens dossiers (parent+enfant) + if (presentationList.length === 0 && p.dossiers) { for (const d of p.dossiers) { presentationList.push({ id: d.id, id_parent: p.user_id, id_enfant: d.child?.id ?? '', presentation: d.presentation, - type_contrat: d.type_contrat, - repas: d.meals, - budget: d.budget != null ? Number(d.budget) : undefined, statut: d.status, }); } @@ -205,6 +227,9 @@ export class ParentsService { prenom: p.user.prenom, nom: p.user.nom, telephone: p.user.telephone, + adresse: p.user.adresse, + ville: p.user.ville, + code_postal: p.user.code_postal, statut: p.user.statut, co_parent_id: p.co_parent?.id, })); diff --git a/database/migrations/2026_dossier_famille.sql b/database/migrations/2026_dossier_famille.sql new file mode 100644 index 0000000..4afaa5e --- /dev/null +++ b/database/migrations/2026_dossier_famille.sql @@ -0,0 +1,27 @@ +-- Un dossier = une famille, N enfants. Ticket #119 évolution. +-- Table: un enregistrement par famille (lien via numero_dossier / id_parent). +CREATE TABLE IF NOT EXISTS dossier_famille ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + numero_dossier VARCHAR(20) NOT NULL, + id_parent UUID NOT NULL REFERENCES parents(id_utilisateur) ON DELETE CASCADE, + presentation TEXT, + type_contrat VARCHAR(50), + repas BOOLEAN NOT NULL DEFAULT false, + budget NUMERIC(10,2), + planning_souhaite JSONB, + statut statut_dossier_type NOT NULL DEFAULT 'envoye', + cree_le TIMESTAMPTZ NOT NULL DEFAULT now(), + modifie_le TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX IF NOT EXISTS idx_dossier_famille_numero ON dossier_famille(numero_dossier); +CREATE INDEX IF NOT EXISTS idx_dossier_famille_id_parent ON dossier_famille(id_parent); + +-- Enfants concernés par ce dossier famille (N par dossier). +CREATE TABLE IF NOT EXISTS dossier_famille_enfants ( + id_dossier_famille UUID NOT NULL REFERENCES dossier_famille(id) ON DELETE CASCADE, + id_enfant UUID NOT NULL REFERENCES enfants(id) ON DELETE CASCADE, + PRIMARY KEY (id_dossier_famille, id_enfant) +); + +CREATE INDEX IF NOT EXISTS idx_dossier_famille_enfants_enfant ON dossier_famille_enfants(id_enfant); diff --git a/database/migrations/2026_dossier_famille_simplifier.sql b/database/migrations/2026_dossier_famille_simplifier.sql new file mode 100644 index 0000000..809dc1c --- /dev/null +++ b/database/migrations/2026_dossier_famille_simplifier.sql @@ -0,0 +1,5 @@ +-- Dossier famille = inscription uniquement, pas les données de dossier de garde (repas, type_contrat, budget, etc.) +ALTER TABLE dossier_famille DROP COLUMN IF EXISTS repas; +ALTER TABLE dossier_famille DROP COLUMN IF EXISTS type_contrat; +ALTER TABLE dossier_famille DROP COLUMN IF EXISTS budget; +ALTER TABLE dossier_famille DROP COLUMN IF EXISTS planning_souhaite;