Refactoring
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import '../../../../core/error/failures.dart';
|
||||
import '../../../../core/usecases/usecase.dart';
|
||||
import '../entities/evaluation_aide.dart';
|
||||
import '../repositories/solidarite_repository.dart';
|
||||
|
||||
/// Cas d'usage pour créer une nouvelle évaluation
|
||||
class CreerEvaluationUseCase implements UseCase<EvaluationAide, CreerEvaluationParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
CreerEvaluationUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, EvaluationAide>> call(CreerEvaluationParams params) async {
|
||||
return await repository.creerEvaluation(params.evaluation);
|
||||
}
|
||||
}
|
||||
|
||||
class CreerEvaluationParams {
|
||||
final EvaluationAide evaluation;
|
||||
|
||||
CreerEvaluationParams({required this.evaluation});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour mettre à jour une évaluation
|
||||
class MettreAJourEvaluationUseCase implements UseCase<EvaluationAide, MettreAJourEvaluationParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
MettreAJourEvaluationUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, EvaluationAide>> call(MettreAJourEvaluationParams params) async {
|
||||
return await repository.mettreAJourEvaluation(params.evaluation);
|
||||
}
|
||||
}
|
||||
|
||||
class MettreAJourEvaluationParams {
|
||||
final EvaluationAide evaluation;
|
||||
|
||||
MettreAJourEvaluationParams({required this.evaluation});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour obtenir une évaluation par ID
|
||||
class ObtenirEvaluationUseCase implements UseCase<EvaluationAide, ObtenirEvaluationParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
ObtenirEvaluationUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, EvaluationAide>> call(ObtenirEvaluationParams params) async {
|
||||
return await repository.obtenirEvaluation(params.id);
|
||||
}
|
||||
}
|
||||
|
||||
class ObtenirEvaluationParams {
|
||||
final String id;
|
||||
|
||||
ObtenirEvaluationParams({required this.id});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour obtenir les évaluations d'une demande
|
||||
class ObtenirEvaluationsDemandeUseCase implements UseCase<List<EvaluationAide>, ObtenirEvaluationsDemandeParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
ObtenirEvaluationsDemandeUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<EvaluationAide>>> call(ObtenirEvaluationsDemandeParams params) async {
|
||||
return await repository.obtenirEvaluationsDemande(params.demandeId);
|
||||
}
|
||||
}
|
||||
|
||||
class ObtenirEvaluationsDemandeParams {
|
||||
final String demandeId;
|
||||
|
||||
ObtenirEvaluationsDemandeParams({required this.demandeId});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour obtenir les évaluations d'une proposition
|
||||
class ObtenirEvaluationsPropositionUseCase implements UseCase<List<EvaluationAide>, ObtenirEvaluationsPropositionParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
ObtenirEvaluationsPropositionUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<EvaluationAide>>> call(ObtenirEvaluationsPropositionParams params) async {
|
||||
return await repository.obtenirEvaluationsProposition(params.propositionId);
|
||||
}
|
||||
}
|
||||
|
||||
class ObtenirEvaluationsPropositionParams {
|
||||
final String propositionId;
|
||||
|
||||
ObtenirEvaluationsPropositionParams({required this.propositionId});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour signaler une évaluation
|
||||
class SignalerEvaluationUseCase implements UseCase<EvaluationAide, SignalerEvaluationParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
SignalerEvaluationUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, EvaluationAide>> call(SignalerEvaluationParams params) async {
|
||||
return await repository.signalerEvaluation(
|
||||
evaluationId: params.evaluationId,
|
||||
motif: params.motif,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SignalerEvaluationParams {
|
||||
final String evaluationId;
|
||||
final String motif;
|
||||
|
||||
SignalerEvaluationParams({
|
||||
required this.evaluationId,
|
||||
required this.motif,
|
||||
});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour calculer la note moyenne d'une demande
|
||||
class CalculerMoyenneDemandeUseCase implements UseCase<StatistiquesEvaluation, CalculerMoyenneDemandeParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
CalculerMoyenneDemandeUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, StatistiquesEvaluation>> call(CalculerMoyenneDemandeParams params) async {
|
||||
return await repository.calculerMoyenneDemande(params.demandeId);
|
||||
}
|
||||
}
|
||||
|
||||
class CalculerMoyenneDemandeParams {
|
||||
final String demandeId;
|
||||
|
||||
CalculerMoyenneDemandeParams({required this.demandeId});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour calculer la note moyenne d'une proposition
|
||||
class CalculerMoyennePropositionUseCase implements UseCase<StatistiquesEvaluation, CalculerMoyennePropositionParams> {
|
||||
final SolidariteRepository repository;
|
||||
|
||||
CalculerMoyennePropositionUseCase(this.repository);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, StatistiquesEvaluation>> call(CalculerMoyennePropositionParams params) async {
|
||||
return await repository.calculerMoyenneProposition(params.propositionId);
|
||||
}
|
||||
}
|
||||
|
||||
class CalculerMoyennePropositionParams {
|
||||
final String propositionId;
|
||||
|
||||
CalculerMoyennePropositionParams({required this.propositionId});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour valider une évaluation avant création
|
||||
class ValiderEvaluationUseCase implements UseCase<bool, ValiderEvaluationParams> {
|
||||
ValiderEvaluationUseCase();
|
||||
|
||||
@override
|
||||
Future<Either<Failure, bool>> call(ValiderEvaluationParams params) async {
|
||||
try {
|
||||
final evaluation = params.evaluation;
|
||||
final erreurs = <String>[];
|
||||
|
||||
// Validation de la note globale
|
||||
if (evaluation.noteGlobale < 1.0 || evaluation.noteGlobale > 5.0) {
|
||||
erreurs.add('La note globale doit être comprise entre 1 et 5');
|
||||
}
|
||||
|
||||
// Validation des notes détaillées
|
||||
final notesDetaillees = [
|
||||
evaluation.noteDelaiReponse,
|
||||
evaluation.noteCommunication,
|
||||
evaluation.noteProfessionnalisme,
|
||||
evaluation.noteRespectEngagements,
|
||||
];
|
||||
|
||||
for (final note in notesDetaillees) {
|
||||
if (note != null && (note < 1.0 || note > 5.0)) {
|
||||
erreurs.add('Toutes les notes détaillées doivent être comprises entre 1 et 5');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Validation du commentaire principal
|
||||
if (evaluation.commentairePrincipal.trim().isEmpty) {
|
||||
erreurs.add('Le commentaire principal est obligatoire');
|
||||
} else if (evaluation.commentairePrincipal.length < 20) {
|
||||
erreurs.add('Le commentaire principal doit contenir au moins 20 caractères');
|
||||
} else if (evaluation.commentairePrincipal.length > 1000) {
|
||||
erreurs.add('Le commentaire principal ne peut pas dépasser 1000 caractères');
|
||||
}
|
||||
|
||||
// Validation de la cohérence entre note et commentaire
|
||||
if (evaluation.noteGlobale <= 2.0 && evaluation.commentairePrincipal.length < 50) {
|
||||
erreurs.add('Un commentaire détaillé est requis pour les notes faibles');
|
||||
}
|
||||
|
||||
// Validation des points positifs et d'amélioration
|
||||
if (evaluation.pointsPositifs != null && evaluation.pointsPositifs!.length > 500) {
|
||||
erreurs.add('Les points positifs ne peuvent pas dépasser 500 caractères');
|
||||
}
|
||||
|
||||
if (evaluation.pointsAmelioration != null && evaluation.pointsAmelioration!.length > 500) {
|
||||
erreurs.add('Les points d\'amélioration ne peuvent pas dépasser 500 caractères');
|
||||
}
|
||||
|
||||
// Validation des recommandations
|
||||
if (evaluation.recommandations != null && evaluation.recommandations!.length > 500) {
|
||||
erreurs.add('Les recommandations ne peuvent pas dépasser 500 caractères');
|
||||
}
|
||||
|
||||
// Validation de la cohérence de la recommandation
|
||||
if (evaluation.recommande == true && evaluation.noteGlobale < 3.0) {
|
||||
erreurs.add('Impossible de recommander avec une note inférieure à 3');
|
||||
}
|
||||
|
||||
if (evaluation.recommande == false && evaluation.noteGlobale >= 4.0) {
|
||||
erreurs.add('Une note de 4 ou plus devrait normalement être recommandée');
|
||||
}
|
||||
|
||||
// Détection de contenu inapproprié
|
||||
if (_contientContenuInapproprie(evaluation.commentairePrincipal)) {
|
||||
erreurs.add('Le commentaire contient du contenu inapproprié');
|
||||
}
|
||||
|
||||
if (erreurs.isNotEmpty) {
|
||||
return Left(ValidationFailure(erreurs.join(', ')));
|
||||
}
|
||||
|
||||
return const Right(true);
|
||||
} catch (e) {
|
||||
return Left(UnexpectedFailure('Erreur lors de la validation: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
bool _contientContenuInapproprie(String texte) {
|
||||
// Liste simple de mots inappropriés (à étendre selon les besoins)
|
||||
final motsInappropries = [
|
||||
'spam', 'arnaque', 'escroquerie', 'fraude',
|
||||
// Ajouter d'autres mots selon le contexte
|
||||
];
|
||||
|
||||
final texteMinuscule = texte.toLowerCase();
|
||||
return motsInappropries.any((mot) => texteMinuscule.contains(mot));
|
||||
}
|
||||
}
|
||||
|
||||
class ValiderEvaluationParams {
|
||||
final EvaluationAide evaluation;
|
||||
|
||||
ValiderEvaluationParams({required this.evaluation});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour calculer le score de qualité d'une évaluation
|
||||
class CalculerScoreQualiteEvaluationUseCase implements UseCase<double, CalculerScoreQualiteEvaluationParams> {
|
||||
CalculerScoreQualiteEvaluationUseCase();
|
||||
|
||||
@override
|
||||
Future<Either<Failure, double>> call(CalculerScoreQualiteEvaluationParams params) async {
|
||||
try {
|
||||
final evaluation = params.evaluation;
|
||||
double score = 50.0; // Score de base
|
||||
|
||||
// Bonus pour la longueur du commentaire
|
||||
final longueurCommentaire = evaluation.commentairePrincipal.length;
|
||||
if (longueurCommentaire >= 100) {
|
||||
score += 15.0;
|
||||
} else if (longueurCommentaire >= 50) {
|
||||
score += 10.0;
|
||||
} else if (longueurCommentaire >= 20) {
|
||||
score += 5.0;
|
||||
}
|
||||
|
||||
// Bonus pour les notes détaillées
|
||||
final notesDetaillees = [
|
||||
evaluation.noteDelaiReponse,
|
||||
evaluation.noteCommunication,
|
||||
evaluation.noteProfessionnalisme,
|
||||
evaluation.noteRespectEngagements,
|
||||
];
|
||||
|
||||
final nombreNotesDetaillees = notesDetaillees.where((note) => note != null).length;
|
||||
score += nombreNotesDetaillees * 5.0; // 5 points par note détaillée
|
||||
|
||||
// Bonus pour les sections optionnelles remplies
|
||||
if (evaluation.pointsPositifs != null && evaluation.pointsPositifs!.isNotEmpty) {
|
||||
score += 5.0;
|
||||
}
|
||||
|
||||
if (evaluation.pointsAmelioration != null && evaluation.pointsAmelioration!.isNotEmpty) {
|
||||
score += 5.0;
|
||||
}
|
||||
|
||||
if (evaluation.recommandations != null && evaluation.recommandations!.isNotEmpty) {
|
||||
score += 5.0;
|
||||
}
|
||||
|
||||
// Bonus pour la cohérence
|
||||
if (_estCoherente(evaluation)) {
|
||||
score += 10.0;
|
||||
}
|
||||
|
||||
// Malus pour les évaluations extrêmes sans justification
|
||||
if ((evaluation.noteGlobale <= 1.5 || evaluation.noteGlobale >= 4.5) &&
|
||||
longueurCommentaire < 50) {
|
||||
score -= 15.0;
|
||||
}
|
||||
|
||||
// Malus pour les signalements
|
||||
score -= evaluation.nombreSignalements * 10.0;
|
||||
|
||||
return Right(score.clamp(0.0, 100.0));
|
||||
} catch (e) {
|
||||
return Left(UnexpectedFailure('Erreur lors du calcul du score de qualité: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
bool _estCoherente(EvaluationAide evaluation) {
|
||||
// Vérifier la cohérence entre la note globale et les notes détaillées
|
||||
final notesDetaillees = [
|
||||
evaluation.noteDelaiReponse,
|
||||
evaluation.noteCommunication,
|
||||
evaluation.noteProfessionnalisme,
|
||||
evaluation.noteRespectEngagements,
|
||||
].where((note) => note != null).cast<double>().toList();
|
||||
|
||||
if (notesDetaillees.isEmpty) return true;
|
||||
|
||||
final moyenneDetaillees = notesDetaillees.reduce((a, b) => a + b) / notesDetaillees.length;
|
||||
final ecart = (evaluation.noteGlobale - moyenneDetaillees).abs();
|
||||
|
||||
// Cohérent si l'écart est inférieur à 1 point
|
||||
return ecart < 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
class CalculerScoreQualiteEvaluationParams {
|
||||
final EvaluationAide evaluation;
|
||||
|
||||
CalculerScoreQualiteEvaluationParams({required this.evaluation});
|
||||
}
|
||||
|
||||
/// Cas d'usage pour analyser les tendances d'évaluation
|
||||
class AnalyserTendancesEvaluationUseCase implements UseCase<AnalyseTendancesEvaluation, AnalyserTendancesEvaluationParams> {
|
||||
AnalyserTendancesEvaluationUseCase();
|
||||
|
||||
@override
|
||||
Future<Either<Failure, AnalyseTendancesEvaluation>> call(AnalyserTendancesEvaluationParams params) async {
|
||||
try {
|
||||
// Simulation d'analyse des tendances d'évaluation
|
||||
// Dans une vraie implémentation, on analyserait les données historiques
|
||||
|
||||
final analyse = AnalyseTendancesEvaluation(
|
||||
noteMoyenneGlobale: 4.2,
|
||||
nombreTotalEvaluations: 1247,
|
||||
repartitionNotes: {
|
||||
5: 456,
|
||||
4: 523,
|
||||
3: 189,
|
||||
2: 58,
|
||||
1: 21,
|
||||
},
|
||||
pourcentageRecommandations: 78.5,
|
||||
tempsReponseEvaluationMoyen: const Duration(days: 3),
|
||||
criteresLesMieuxNotes: [
|
||||
CritereNote('Respect des engagements', 4.6),
|
||||
CritereNote('Communication', 4.3),
|
||||
CritereNote('Professionnalisme', 4.1),
|
||||
CritereNote('Délai de réponse', 3.9),
|
||||
],
|
||||
typeEvaluateursPlusActifs: [
|
||||
TypeEvaluateurActivite(TypeEvaluateur.beneficiaire, 67.2),
|
||||
TypeEvaluateurActivite(TypeEvaluateur.proposant, 23.8),
|
||||
TypeEvaluateurActivite(TypeEvaluateur.evaluateurOfficial, 6.5),
|
||||
TypeEvaluateurActivite(TypeEvaluateur.administrateur, 2.5),
|
||||
],
|
||||
evolutionSatisfaction: EvolutionSatisfaction(
|
||||
dernierMois: 4.2,
|
||||
moisPrecedent: 4.0,
|
||||
tendance: TendanceSatisfaction.hausse,
|
||||
),
|
||||
recommandationsAmelioration: [
|
||||
'Améliorer les délais de réponse des proposants',
|
||||
'Encourager plus d\'évaluations détaillées',
|
||||
'Former les proposants à la communication',
|
||||
],
|
||||
);
|
||||
|
||||
return Right(analyse);
|
||||
} catch (e) {
|
||||
return Left(UnexpectedFailure('Erreur lors de l\'analyse des tendances: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnalyserTendancesEvaluationParams {
|
||||
final String organisationId;
|
||||
final DateTime? dateDebut;
|
||||
final DateTime? dateFin;
|
||||
|
||||
AnalyserTendancesEvaluationParams({
|
||||
required this.organisationId,
|
||||
this.dateDebut,
|
||||
this.dateFin,
|
||||
});
|
||||
}
|
||||
|
||||
/// Classes pour l'analyse des tendances d'évaluation
|
||||
class AnalyseTendancesEvaluation {
|
||||
final double noteMoyenneGlobale;
|
||||
final int nombreTotalEvaluations;
|
||||
final Map<int, int> repartitionNotes;
|
||||
final double pourcentageRecommandations;
|
||||
final Duration tempsReponseEvaluationMoyen;
|
||||
final List<CritereNote> criteresLesMieuxNotes;
|
||||
final List<TypeEvaluateurActivite> typeEvaluateursPlusActifs;
|
||||
final EvolutionSatisfaction evolutionSatisfaction;
|
||||
final List<String> recommandationsAmelioration;
|
||||
|
||||
const AnalyseTendancesEvaluation({
|
||||
required this.noteMoyenneGlobale,
|
||||
required this.nombreTotalEvaluations,
|
||||
required this.repartitionNotes,
|
||||
required this.pourcentageRecommandations,
|
||||
required this.tempsReponseEvaluationMoyen,
|
||||
required this.criteresLesMieuxNotes,
|
||||
required this.typeEvaluateursPlusActifs,
|
||||
required this.evolutionSatisfaction,
|
||||
required this.recommandationsAmelioration,
|
||||
});
|
||||
}
|
||||
|
||||
class CritereNote {
|
||||
final String nom;
|
||||
final double noteMoyenne;
|
||||
|
||||
const CritereNote(this.nom, this.noteMoyenne);
|
||||
}
|
||||
|
||||
class TypeEvaluateurActivite {
|
||||
final TypeEvaluateur type;
|
||||
final double pourcentage;
|
||||
|
||||
const TypeEvaluateurActivite(this.type, this.pourcentage);
|
||||
}
|
||||
|
||||
class EvolutionSatisfaction {
|
||||
final double dernierMois;
|
||||
final double moisPrecedent;
|
||||
final TendanceSatisfaction tendance;
|
||||
|
||||
const EvolutionSatisfaction({
|
||||
required this.dernierMois,
|
||||
required this.moisPrecedent,
|
||||
required this.tendance,
|
||||
});
|
||||
}
|
||||
|
||||
enum TendanceSatisfaction { hausse, baisse, stable }
|
||||
Reference in New Issue
Block a user