402 lines
12 KiB
Dart
402 lines
12 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import 'demande_aide.dart';
|
|
|
|
/// Entité représentant une proposition d'aide dans le système de solidarité
|
|
///
|
|
/// Cette entité encapsule toutes les informations relatives à une proposition d'aide,
|
|
/// incluant les détails du proposant, les capacités et les conditions.
|
|
class PropositionAide extends Equatable {
|
|
/// Identifiant unique de la proposition
|
|
final String id;
|
|
|
|
/// Numéro de référence unique (format: PA-YYYY-NNNNNN)
|
|
final String numeroReference;
|
|
|
|
/// Titre de la proposition d'aide
|
|
final String titre;
|
|
|
|
/// Description détaillée de la proposition
|
|
final String description;
|
|
|
|
/// Type d'aide proposée
|
|
final TypeAide typeAide;
|
|
|
|
/// Statut actuel de la proposition
|
|
final StatutProposition statut;
|
|
|
|
/// Identifiant du proposant
|
|
final String proposantId;
|
|
|
|
/// Nom complet du proposant
|
|
final String nomProposant;
|
|
|
|
/// Identifiant de l'organisation
|
|
final String organisationId;
|
|
|
|
/// Montant maximum proposé (si applicable)
|
|
final double? montantMaximum;
|
|
|
|
/// Montant minimum proposé (si applicable)
|
|
final double? montantMinimum;
|
|
|
|
/// Nombre maximum de bénéficiaires
|
|
final int nombreMaxBeneficiaires;
|
|
|
|
/// Nombre de bénéficiaires déjà aidés
|
|
final int nombreBeneficiairesAides;
|
|
|
|
/// Nombre de demandes traitées
|
|
final int nombreDemandesTraitees;
|
|
|
|
/// Montant total versé
|
|
final double montantTotalVerse;
|
|
|
|
/// Date de création de la proposition
|
|
final DateTime dateCreation;
|
|
|
|
/// Date de modification
|
|
final DateTime dateModification;
|
|
|
|
/// Date d'expiration
|
|
final DateTime? dateExpiration;
|
|
|
|
/// Délai de réponse en heures
|
|
final int delaiReponseHeures;
|
|
|
|
/// Zones géographiques couvertes
|
|
final List<String> zonesGeographiques;
|
|
|
|
/// Créneaux de disponibilité
|
|
final List<CreneauDisponibilite> creneauxDisponibilite;
|
|
|
|
/// Critères de sélection
|
|
final List<CritereSelection> criteresSelection;
|
|
|
|
/// Contact du proposant
|
|
final ContactProposant contactProposant;
|
|
|
|
/// Conditions particulières
|
|
final String? conditionsParticulieres;
|
|
|
|
/// Instructions spéciales
|
|
final String? instructionsSpeciales;
|
|
|
|
/// Note moyenne des évaluations
|
|
final double? noteMoyenne;
|
|
|
|
/// Nombre d'évaluations reçues
|
|
final int nombreEvaluations;
|
|
|
|
/// Nombre de vues de la proposition
|
|
final int nombreVues;
|
|
|
|
/// Nombre de candidatures reçues
|
|
final int nombreCandidatures;
|
|
|
|
/// Score de pertinence calculé
|
|
final double scorePertinence;
|
|
|
|
/// Données personnalisées
|
|
final Map<String, dynamic> donneesPersonnalisees;
|
|
|
|
/// Indique si la proposition est disponible
|
|
final bool estDisponible;
|
|
|
|
/// Indique si la proposition est vérifiée
|
|
final bool estVerifiee;
|
|
|
|
/// Indique si la proposition est expirée
|
|
final bool estExpiree;
|
|
|
|
const PropositionAide({
|
|
required this.id,
|
|
required this.numeroReference,
|
|
required this.titre,
|
|
required this.description,
|
|
required this.typeAide,
|
|
required this.statut,
|
|
required this.proposantId,
|
|
required this.nomProposant,
|
|
required this.organisationId,
|
|
this.montantMaximum,
|
|
this.montantMinimum,
|
|
required this.nombreMaxBeneficiaires,
|
|
this.nombreBeneficiairesAides = 0,
|
|
this.nombreDemandesTraitees = 0,
|
|
this.montantTotalVerse = 0.0,
|
|
required this.dateCreation,
|
|
required this.dateModification,
|
|
this.dateExpiration,
|
|
this.delaiReponseHeures = 48,
|
|
this.zonesGeographiques = const [],
|
|
this.creneauxDisponibilite = const [],
|
|
this.criteresSelection = const [],
|
|
required this.contactProposant,
|
|
this.conditionsParticulieres,
|
|
this.instructionsSpeciales,
|
|
this.noteMoyenne,
|
|
this.nombreEvaluations = 0,
|
|
this.nombreVues = 0,
|
|
this.nombreCandidatures = 0,
|
|
this.scorePertinence = 50.0,
|
|
this.donneesPersonnalisees = const {},
|
|
this.estDisponible = true,
|
|
this.estVerifiee = false,
|
|
this.estExpiree = false,
|
|
});
|
|
|
|
/// Calcule le nombre de places restantes
|
|
int get placesRestantes {
|
|
return nombreMaxBeneficiaires - nombreBeneficiairesAides;
|
|
}
|
|
|
|
/// Calcule le pourcentage de capacité utilisée
|
|
double get pourcentageCapaciteUtilisee {
|
|
if (nombreMaxBeneficiaires == 0) return 0.0;
|
|
return (nombreBeneficiairesAides / nombreMaxBeneficiaires) * 100;
|
|
}
|
|
|
|
/// Indique si la proposition peut accepter de nouveaux bénéficiaires
|
|
bool get peutAccepterBeneficiaires {
|
|
return estDisponible && !estExpiree && placesRestantes > 0;
|
|
}
|
|
|
|
/// Indique si la proposition est active et disponible
|
|
bool get isActiveEtDisponible {
|
|
return statut == StatutProposition.active && estDisponible && !estExpiree;
|
|
}
|
|
|
|
/// Calcule un score de compatibilité avec une demande
|
|
double calculerScoreCompatibilite(DemandeAide demande) {
|
|
double score = 0.0;
|
|
|
|
// Correspondance du type d'aide (40 points max)
|
|
if (demande.typeAide == typeAide) {
|
|
score += 40.0;
|
|
} else {
|
|
// Bonus partiel pour les types similaires
|
|
score += 20.0;
|
|
}
|
|
|
|
// Compatibilité financière (25 points max)
|
|
if (demande.montantDemande != null && montantMaximum != null) {
|
|
if (demande.montantDemande! <= montantMaximum!) {
|
|
score += 25.0;
|
|
} else {
|
|
// Pénalité proportionnelle
|
|
double ratio = montantMaximum! / demande.montantDemande!;
|
|
score += 25.0 * ratio;
|
|
}
|
|
} else if (demande.montantDemande == null) {
|
|
score += 25.0; // Pas de contrainte financière
|
|
}
|
|
|
|
// Expérience du proposant (15 points max)
|
|
if (nombreBeneficiairesAides > 0) {
|
|
score += (nombreBeneficiairesAides * 2.0).clamp(0.0, 15.0);
|
|
}
|
|
|
|
// Réputation (10 points max)
|
|
if (noteMoyenne != null && nombreEvaluations >= 3) {
|
|
score += (noteMoyenne! - 3.0) * 3.33;
|
|
}
|
|
|
|
// Disponibilité (10 points max)
|
|
if (peutAccepterBeneficiaires) {
|
|
double ratioCapacite = placesRestantes / nombreMaxBeneficiaires;
|
|
score += 10.0 * ratioCapacite;
|
|
}
|
|
|
|
return score.clamp(0.0, 100.0);
|
|
}
|
|
|
|
/// Obtient la couleur associée au statut
|
|
String get couleurStatut => statut.couleur;
|
|
|
|
/// Obtient l'icône associée au type d'aide
|
|
String get iconeTypeAide => typeAide.icone;
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
id,
|
|
numeroReference,
|
|
titre,
|
|
description,
|
|
typeAide,
|
|
statut,
|
|
proposantId,
|
|
nomProposant,
|
|
organisationId,
|
|
montantMaximum,
|
|
montantMinimum,
|
|
nombreMaxBeneficiaires,
|
|
nombreBeneficiairesAides,
|
|
nombreDemandesTraitees,
|
|
montantTotalVerse,
|
|
dateCreation,
|
|
dateModification,
|
|
dateExpiration,
|
|
delaiReponseHeures,
|
|
zonesGeographiques,
|
|
creneauxDisponibilite,
|
|
criteresSelection,
|
|
contactProposant,
|
|
conditionsParticulieres,
|
|
instructionsSpeciales,
|
|
noteMoyenne,
|
|
nombreEvaluations,
|
|
nombreVues,
|
|
nombreCandidatures,
|
|
scorePertinence,
|
|
donneesPersonnalisees,
|
|
estDisponible,
|
|
estVerifiee,
|
|
estExpiree,
|
|
];
|
|
|
|
PropositionAide copyWith({
|
|
String? id,
|
|
String? numeroReference,
|
|
String? titre,
|
|
String? description,
|
|
TypeAide? typeAide,
|
|
StatutProposition? statut,
|
|
String? proposantId,
|
|
String? nomProposant,
|
|
String? organisationId,
|
|
double? montantMaximum,
|
|
double? montantMinimum,
|
|
int? nombreMaxBeneficiaires,
|
|
int? nombreBeneficiairesAides,
|
|
int? nombreDemandesTraitees,
|
|
double? montantTotalVerse,
|
|
DateTime? dateCreation,
|
|
DateTime? dateModification,
|
|
DateTime? dateExpiration,
|
|
int? delaiReponseHeures,
|
|
List<String>? zonesGeographiques,
|
|
List<CreneauDisponibilite>? creneauxDisponibilite,
|
|
List<CritereSelection>? criteresSelection,
|
|
ContactProposant? contactProposant,
|
|
String? conditionsParticulieres,
|
|
String? instructionsSpeciales,
|
|
double? noteMoyenne,
|
|
int? nombreEvaluations,
|
|
int? nombreVues,
|
|
int? nombreCandidatures,
|
|
double? scorePertinence,
|
|
Map<String, dynamic>? donneesPersonnalisees,
|
|
bool? estDisponible,
|
|
bool? estVerifiee,
|
|
bool? estExpiree,
|
|
}) {
|
|
return PropositionAide(
|
|
id: id ?? this.id,
|
|
numeroReference: numeroReference ?? this.numeroReference,
|
|
titre: titre ?? this.titre,
|
|
description: description ?? this.description,
|
|
typeAide: typeAide ?? this.typeAide,
|
|
statut: statut ?? this.statut,
|
|
proposantId: proposantId ?? this.proposantId,
|
|
nomProposant: nomProposant ?? this.nomProposant,
|
|
organisationId: organisationId ?? this.organisationId,
|
|
montantMaximum: montantMaximum ?? this.montantMaximum,
|
|
montantMinimum: montantMinimum ?? this.montantMinimum,
|
|
nombreMaxBeneficiaires: nombreMaxBeneficiaires ?? this.nombreMaxBeneficiaires,
|
|
nombreBeneficiairesAides: nombreBeneficiairesAides ?? this.nombreBeneficiairesAides,
|
|
nombreDemandesTraitees: nombreDemandesTraitees ?? this.nombreDemandesTraitees,
|
|
montantTotalVerse: montantTotalVerse ?? this.montantTotalVerse,
|
|
dateCreation: dateCreation ?? this.dateCreation,
|
|
dateModification: dateModification ?? this.dateModification,
|
|
dateExpiration: dateExpiration ?? this.dateExpiration,
|
|
delaiReponseHeures: delaiReponseHeures ?? this.delaiReponseHeures,
|
|
zonesGeographiques: zonesGeographiques ?? this.zonesGeographiques,
|
|
creneauxDisponibilite: creneauxDisponibilite ?? this.creneauxDisponibilite,
|
|
criteresSelection: criteresSelection ?? this.criteresSelection,
|
|
contactProposant: contactProposant ?? this.contactProposant,
|
|
conditionsParticulieres: conditionsParticulieres ?? this.conditionsParticulieres,
|
|
instructionsSpeciales: instructionsSpeciales ?? this.instructionsSpeciales,
|
|
noteMoyenne: noteMoyenne ?? this.noteMoyenne,
|
|
nombreEvaluations: nombreEvaluations ?? this.nombreEvaluations,
|
|
nombreVues: nombreVues ?? this.nombreVues,
|
|
nombreCandidatures: nombreCandidatures ?? this.nombreCandidatures,
|
|
scorePertinence: scorePertinence ?? this.scorePertinence,
|
|
donneesPersonnalisees: donneesPersonnalisees ?? this.donneesPersonnalisees,
|
|
estDisponible: estDisponible ?? this.estDisponible,
|
|
estVerifiee: estVerifiee ?? this.estVerifiee,
|
|
estExpiree: estExpiree ?? this.estExpiree,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Énumération des statuts de proposition d'aide
|
|
enum StatutProposition {
|
|
active('Active', 'check_circle', '#4CAF50'),
|
|
suspendue('Suspendue', 'pause_circle', '#FF9800'),
|
|
terminee('Terminée', 'done_all', '#607D8B'),
|
|
expiree('Expirée', 'schedule', '#9E9E9E'),
|
|
supprimee('Supprimée', 'delete', '#F44336');
|
|
|
|
const StatutProposition(this.libelle, this.icone, this.couleur);
|
|
|
|
final String libelle;
|
|
final String icone;
|
|
final String couleur;
|
|
}
|
|
|
|
/// Classe représentant un créneau de disponibilité
|
|
class CreneauDisponibilite extends Equatable {
|
|
final String jourSemaine;
|
|
final String heureDebut;
|
|
final String heureFin;
|
|
final String? commentaire;
|
|
|
|
const CreneauDisponibilite({
|
|
required this.jourSemaine,
|
|
required this.heureDebut,
|
|
required this.heureFin,
|
|
this.commentaire,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [jourSemaine, heureDebut, heureFin, commentaire];
|
|
}
|
|
|
|
/// Classe représentant un critère de sélection
|
|
class CritereSelection extends Equatable {
|
|
final String nom;
|
|
final String valeur;
|
|
final bool estObligatoire;
|
|
final String? description;
|
|
|
|
const CritereSelection({
|
|
required this.nom,
|
|
required this.valeur,
|
|
this.estObligatoire = false,
|
|
this.description,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [nom, valeur, estObligatoire, description];
|
|
}
|
|
|
|
/// Classe représentant le contact d'un proposant
|
|
class ContactProposant extends Equatable {
|
|
final String nom;
|
|
final String telephone;
|
|
final String? email;
|
|
final String? adresse;
|
|
final String? methodePrefereee;
|
|
|
|
const ContactProposant({
|
|
required this.nom,
|
|
required this.telephone,
|
|
this.email,
|
|
this.adresse,
|
|
this.methodePrefereee,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [nom, telephone, email, adresse, methodePrefereee];
|
|
}
|