petitspas/frontend/lib/models/dossier_unifie.dart
Julien Martin cde676c4f9 feat: alignement master sur develop (squash)
- Dossiers unifiés #119, pending-families enrichi, validation admin (wizards)
- Front: modèles dossier_unifie / pending_family, NIR, auth
- Migrations dossier_famille, scripts de test API
- Résolution conflits: parents.*, docs tickets, auth_service, nir_utils

Made-with: Cursor
2026-03-26 00:20:47 +01:00

211 lines
6.3 KiB
Dart

import 'package:p_tits_pas/models/user.dart';
/// Réponse unifiée GET /dossiers/:numeroDossier. Ticket #119, #107.
class DossierUnifie {
final String type; // 'am' | 'family'
final dynamic dossier; // DossierAM | DossierFamille
DossierUnifie({required this.type, required this.dossier});
bool get isAm => type == 'am';
bool get isFamily => type == 'family';
DossierAM get asAm => dossier as DossierAM;
DossierFamille get asFamily => dossier as DossierFamille;
factory DossierUnifie.fromJson(Map<String, dynamic> json) {
final t = json['type'];
final raw = t is String ? t : 'family';
final typeStr = raw.toLowerCase();
final d = json['dossier'];
if (d == null || d is! Map<String, dynamic>) {
throw FormatException('dossier manquant ou invalide');
}
final dossierMap = Map<String, dynamic>.from(d as Map);
// Seul `am` (casse tolérée) charge le dossier AM ; le reste = famille (API : type "family").
final isAm = typeStr == 'am';
final dossier = isAm ? DossierAM.fromJson(dossierMap) : DossierFamille.fromJson(dossierMap);
return DossierUnifie(type: isAm ? 'am' : 'family', dossier: dossier);
}
}
/// Dossier AM (type: 'am'). Champs alignés API.
class DossierAM {
final String? numeroDossier;
final AppUser user;
final String? numeroAgrement;
final String? nir;
final String? presentation;
final String? dateAgrement;
final int? nbMaxEnfants;
final int? placesDisponibles;
final String? villeResidence;
DossierAM({
this.numeroDossier,
required this.user,
this.numeroAgrement,
this.nir,
this.presentation,
this.dateAgrement,
this.nbMaxEnfants,
this.placesDisponibles,
this.villeResidence,
});
factory DossierAM.fromJson(Map<String, dynamic> json) {
final userJson = json['user'];
final userMap = userJson is Map<String, dynamic>
? userJson
: <String, dynamic>{};
final nbMax = json['nb_max_enfants'];
final places = json['place_disponible'];
return DossierAM(
numeroDossier: json['numero_dossier']?.toString(),
user: AppUser.fromJson(Map<String, dynamic>.from(userMap)),
numeroAgrement: json['numero_agrement']?.toString(),
nir: json['nir']?.toString(),
presentation: (json['biographie'] ?? json['presentation'])?.toString(),
dateAgrement: json['date_agrement']?.toString(),
nbMaxEnfants: nbMax is int ? nbMax : (nbMax is num ? nbMax.toInt() : null),
placesDisponibles: places is int ? places : (places is num ? places.toInt() : null),
villeResidence: json['ville_residence']?.toString(),
);
}
}
/// Dossier famille (type: 'family'). Champs alignés API.
class DossierFamille {
final String? numeroDossier;
final List<ParentDossier> parents;
final List<EnfantDossier> enfants;
final String? presentation;
DossierFamille({
this.numeroDossier,
required this.parents,
required this.enfants,
this.presentation,
});
factory DossierFamille.fromJson(Map<String, dynamic> json) {
final parentsRaw = json['parents'];
final parentsList = parentsRaw is List
? (parentsRaw)
.where((e) => e is Map)
.map((e) => ParentDossier.fromJson(Map<String, dynamic>.from(e as Map)))
.toList()
: <ParentDossier>[];
final enfantsRaw = json['enfants'];
final enfantsList = enfantsRaw is List
? (enfantsRaw)
.where((e) => e is Map)
.map((e) => EnfantDossier.fromJson(Map<String, dynamic>.from(e as Map)))
.toList()
: <EnfantDossier>[];
return DossierFamille(
numeroDossier: json['numero_dossier']?.toString(),
parents: parentsList,
enfants: enfantsList,
presentation: (json['texte_motivation'] ?? json['presentation'])?.toString(),
);
}
bool get isEnAttente =>
parents.any((p) => p.statut == 'en_attente');
}
/// Parent dans un dossier famille (champs user exposés).
class ParentDossier {
final String id;
final String email;
final String? prenom;
final String? nom;
final String? telephone;
final String? adresse;
final String? ville;
final String? codePostal;
final String? dateNaissance;
final String? genre;
final String? situationFamiliale;
final String? creeLe;
final String? statut;
ParentDossier({
required this.id,
required this.email,
this.prenom,
this.nom,
this.telephone,
this.adresse,
this.ville,
this.codePostal,
this.dateNaissance,
this.genre,
this.situationFamiliale,
this.creeLe,
this.statut,
});
String get fullName => '${prenom ?? ''} ${nom ?? ''}'.trim();
factory ParentDossier.fromJson(Map<String, dynamic> json) {
return ParentDossier(
id: json['id']?.toString() ?? '',
email: json['email']?.toString() ?? '',
prenom: json['prenom']?.toString(),
nom: json['nom']?.toString(),
telephone: json['telephone']?.toString(),
adresse: json['adresse']?.toString(),
ville: json['ville']?.toString(),
codePostal: json['code_postal']?.toString(),
dateNaissance: json['date_naissance']?.toString(),
genre: json['genre']?.toString(),
situationFamiliale: json['situation_familiale']?.toString(),
creeLe: json['cree_le']?.toString(),
statut: json['statut']?.toString(),
);
}
}
/// Enfant dans un dossier famille.
class EnfantDossier {
final String id;
final String? firstName;
final String? lastName;
final String? birthDate;
final String? gender;
final String? status;
final String? dueDate;
final String? photoUrl;
final bool consentPhoto;
EnfantDossier({
required this.id,
this.firstName,
this.lastName,
this.birthDate,
this.gender,
this.status,
this.dueDate,
this.photoUrl,
this.consentPhoto = false,
});
String get fullName => '${firstName ?? ''} ${lastName ?? ''}'.trim();
factory EnfantDossier.fromJson(Map<String, dynamic> json) {
return EnfantDossier(
id: json['id']?.toString() ?? '',
firstName: (json['first_name'] ?? json['prenom'])?.toString(),
lastName: (json['last_name'] ?? json['nom'])?.toString(),
birthDate: json['birth_date']?.toString(),
gender: (json['gender'] ?? json['genre'])?.toString(),
status: json['status']?.toString(),
dueDate: json['due_date']?.toString(),
photoUrl: json['photo_url']?.toString(),
consentPhoto: json['consent_photo'] == true,
);
}
}