feat(#119): dossier famille = 1 par famille, N enfants; retrait repas/type_contrat/budget; adresse dans API parents
Made-with: Cursor
This commit is contained in:
parent
5465117238
commit
1772744c81
65
backend/src/entities/dossier_famille.entity.ts
Normal file
65
backend/src/entities/dossier_famille.entity.ts
Normal file
@ -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;
|
||||||
|
}
|
||||||
@ -15,6 +15,12 @@ export class DossierFamilleParentDto {
|
|||||||
nom?: string;
|
nom?: string;
|
||||||
@ApiProperty({ required: false })
|
@ApiProperty({ required: false })
|
||||||
telephone?: string;
|
telephone?: string;
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
adresse?: string;
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
ville?: string;
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
code_postal?: string;
|
||||||
@ApiProperty({ enum: StatutUtilisateurType })
|
@ApiProperty({ enum: StatutUtilisateurType })
|
||||||
statut: StatutUtilisateurType;
|
statut: StatutUtilisateurType;
|
||||||
@ApiProperty({ required: false, description: 'Id du co-parent si couple' })
|
@ApiProperty({ required: false, description: 'Id du co-parent si couple' })
|
||||||
@ -39,7 +45,7 @@ export class DossierFamilleEnfantDto {
|
|||||||
status: StatutEnfantType;
|
status: StatutEnfantType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Dossier (parent+enfant) avec presentation */
|
/** Dossier (parent+enfant) avec presentation – inscription famille, pas dossier de garde */
|
||||||
export class DossierFamillePresentationDto {
|
export class DossierFamillePresentationDto {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
id: string;
|
id: string;
|
||||||
@ -47,14 +53,8 @@ export class DossierFamillePresentationDto {
|
|||||||
id_parent: string;
|
id_parent: string;
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
id_enfant: string;
|
id_enfant: string;
|
||||||
@ApiProperty({ required: false, description: 'Texte de présentation' })
|
@ApiProperty({ required: false, description: 'Texte de motivation' })
|
||||||
presentation?: string;
|
presentation?: string;
|
||||||
@ApiProperty({ required: false })
|
|
||||||
type_contrat?: string;
|
|
||||||
@ApiProperty()
|
|
||||||
repas: boolean;
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
budget?: number;
|
|
||||||
@ApiProperty({ enum: StatutDossierType })
|
@ApiProperty({ enum: StatutDossierType })
|
||||||
statut: StatutDossierType;
|
statut: StatutDossierType;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
|||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { Parents } from 'src/entities/parents.entity';
|
import { Parents } from 'src/entities/parents.entity';
|
||||||
|
import { DossierFamille, DossierFamilleEnfant } from 'src/entities/dossier_famille.entity';
|
||||||
import { ParentsController } from './parents.controller';
|
import { ParentsController } from './parents.controller';
|
||||||
import { ParentsService } from './parents.service';
|
import { ParentsService } from './parents.service';
|
||||||
import { Users } from 'src/entities/users.entity';
|
import { Users } from 'src/entities/users.entity';
|
||||||
@ -10,7 +11,7 @@ import { UserModule } from '../user/user.module';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([Parents, Users]),
|
TypeOrmModule.forFeature([Parents, Users, DossierFamille, DossierFamilleEnfant]),
|
||||||
forwardRef(() => UserModule),
|
forwardRef(() => UserModule),
|
||||||
JwtModule.registerAsync({
|
JwtModule.registerAsync({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { In, Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { Parents } from 'src/entities/parents.entity';
|
import { Parents } from 'src/entities/parents.entity';
|
||||||
|
import { DossierFamille } from 'src/entities/dossier_famille.entity';
|
||||||
import { RoleType, Users } from 'src/entities/users.entity';
|
import { RoleType, Users } from 'src/entities/users.entity';
|
||||||
import { CreateParentDto } from '../user/dto/create_parent.dto';
|
import { CreateParentDto } from '../user/dto/create_parent.dto';
|
||||||
import { UpdateParentsDto } from '../user/dto/update_parent.dto';
|
import { UpdateParentsDto } from '../user/dto/update_parent.dto';
|
||||||
@ -25,6 +26,8 @@ export class ParentsService {
|
|||||||
private readonly parentsRepository: Repository<Parents>,
|
private readonly parentsRepository: Repository<Parents>,
|
||||||
@InjectRepository(Users)
|
@InjectRepository(Users)
|
||||||
private readonly usersRepository: Repository<Users>,
|
private readonly usersRepository: Repository<Users>,
|
||||||
|
@InjectRepository(DossierFamille)
|
||||||
|
private readonly dossierFamilleRepository: Repository<DossierFamille>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// Création d’un parent
|
// Création d’un parent
|
||||||
@ -165,7 +168,29 @@ export class ParentsService {
|
|||||||
relations: ['user', 'co_parent', 'parentChildren', 'parentChildren.child', 'dossiers', 'dossiers.child'],
|
relations: ['user', 'co_parent', 'parentChildren', 'parentChildren.child', 'dossiers', 'dossiers.child'],
|
||||||
});
|
});
|
||||||
const enfantsMap = new Map<string, DossierFamilleEnfantDto>();
|
const enfantsMap = new Map<string, DossierFamilleEnfantDto>();
|
||||||
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) {
|
for (const p of parents) {
|
||||||
// Enfants via parentChildren
|
// Enfants via parentChildren
|
||||||
if (p.parentChildren) {
|
if (p.parentChildren) {
|
||||||
@ -183,17 +208,14 @@ export class ParentsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dossiers (présentation)
|
// Si pas de dossier_famille : fallback sur anciens dossiers (parent+enfant)
|
||||||
if (p.dossiers) {
|
if (presentationList.length === 0 && p.dossiers) {
|
||||||
for (const d of p.dossiers) {
|
for (const d of p.dossiers) {
|
||||||
presentationList.push({
|
presentationList.push({
|
||||||
id: d.id,
|
id: d.id,
|
||||||
id_parent: p.user_id,
|
id_parent: p.user_id,
|
||||||
id_enfant: d.child?.id ?? '',
|
id_enfant: d.child?.id ?? '',
|
||||||
presentation: d.presentation,
|
presentation: d.presentation,
|
||||||
type_contrat: d.type_contrat,
|
|
||||||
repas: d.meals,
|
|
||||||
budget: d.budget != null ? Number(d.budget) : undefined,
|
|
||||||
statut: d.status,
|
statut: d.status,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -205,6 +227,9 @@ export class ParentsService {
|
|||||||
prenom: p.user.prenom,
|
prenom: p.user.prenom,
|
||||||
nom: p.user.nom,
|
nom: p.user.nom,
|
||||||
telephone: p.user.telephone,
|
telephone: p.user.telephone,
|
||||||
|
adresse: p.user.adresse,
|
||||||
|
ville: p.user.ville,
|
||||||
|
code_postal: p.user.code_postal,
|
||||||
statut: p.user.statut,
|
statut: p.user.statut,
|
||||||
co_parent_id: p.co_parent?.id,
|
co_parent_id: p.co_parent?.id,
|
||||||
}));
|
}));
|
||||||
|
|||||||
27
database/migrations/2026_dossier_famille.sql
Normal file
27
database/migrations/2026_dossier_famille.sql
Normal file
@ -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);
|
||||||
5
database/migrations/2026_dossier_famille_simplifier.sql
Normal file
5
database/migrations/2026_dossier_famille_simplifier.sql
Normal file
@ -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;
|
||||||
Loading…
x
Reference in New Issue
Block a user