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 { final SolidariteRepository repository; CreerEvaluationUseCase(this.repository); @override Future> 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 { final SolidariteRepository repository; MettreAJourEvaluationUseCase(this.repository); @override Future> 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 { final SolidariteRepository repository; ObtenirEvaluationUseCase(this.repository); @override Future> 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, ObtenirEvaluationsDemandeParams> { final SolidariteRepository repository; ObtenirEvaluationsDemandeUseCase(this.repository); @override Future>> 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, ObtenirEvaluationsPropositionParams> { final SolidariteRepository repository; ObtenirEvaluationsPropositionUseCase(this.repository); @override Future>> 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 { final SolidariteRepository repository; SignalerEvaluationUseCase(this.repository); @override Future> 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 { final SolidariteRepository repository; CalculerMoyenneDemandeUseCase(this.repository); @override Future> 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 { final SolidariteRepository repository; CalculerMoyennePropositionUseCase(this.repository); @override Future> 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 { ValiderEvaluationUseCase(); @override Future> call(ValiderEvaluationParams params) async { try { final evaluation = params.evaluation; final erreurs = []; // 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 { CalculerScoreQualiteEvaluationUseCase(); @override Future> 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().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 { AnalyserTendancesEvaluationUseCase(); @override Future> 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 repartitionNotes; final double pourcentageRecommandations; final Duration tempsReponseEvaluationMoyen; final List criteresLesMieuxNotes; final List typeEvaluateursPlusActifs; final EvolutionSatisfaction evolutionSatisfaction; final List 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 }