208 lines
7.9 KiB
Dart
208 lines
7.9 KiB
Dart
import 'package:dartz/dartz.dart';
|
|
import 'package:equatable/equatable.dart';
|
|
import '../../../../core/error/failures.dart';
|
|
import '../../../../core/usecases/usecase.dart';
|
|
import '../entities/analytics_data.dart';
|
|
import '../repositories/analytics_repository.dart';
|
|
|
|
/// Use case pour calculer une métrique analytics
|
|
class CalculerMetriqueUseCase implements UseCase<AnalyticsData, CalculerMetriqueParams> {
|
|
const CalculerMetriqueUseCase(this.repository);
|
|
|
|
final AnalyticsRepository repository;
|
|
|
|
@override
|
|
Future<Either<Failure, AnalyticsData>> call(CalculerMetriqueParams params) async {
|
|
// Vérifier d'abord le cache
|
|
final cacheKey = _genererCleCacheMetrique(params);
|
|
final cacheResult = await repository.recupererDepuisCache(cle: cacheKey);
|
|
|
|
return cacheResult.fold(
|
|
(failure) => _calculerEtCacherMetrique(params, cacheKey),
|
|
(cachedData) {
|
|
if (cachedData != null && _isCacheValide(cachedData)) {
|
|
// Retourner les données du cache si elles sont valides
|
|
return Right(_mapCacheToAnalyticsData(cachedData));
|
|
} else {
|
|
// Recalculer si le cache est expiré ou invalide
|
|
return _calculerEtCacherMetrique(params, cacheKey);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
/// Calcule la métrique et la met en cache
|
|
Future<Either<Failure, AnalyticsData>> _calculerEtCacherMetrique(
|
|
CalculerMetriqueParams params,
|
|
String cacheKey,
|
|
) async {
|
|
final result = await repository.calculerMetrique(
|
|
typeMetrique: params.typeMetrique,
|
|
periodeAnalyse: params.periodeAnalyse,
|
|
organisationId: params.organisationId,
|
|
);
|
|
|
|
return result.fold(
|
|
(failure) => Left(failure),
|
|
(analyticsData) async {
|
|
// Mettre en cache le résultat
|
|
await repository.mettreEnCache(
|
|
cle: cacheKey,
|
|
donnees: _mapAnalyticsDataToCache(analyticsData),
|
|
dureeVie: _determinerDureeVieCache(params.periodeAnalyse),
|
|
);
|
|
|
|
return Right(analyticsData);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// Génère une clé de cache unique pour la métrique
|
|
String _genererCleCacheMetrique(CalculerMetriqueParams params) {
|
|
return 'metrique_${params.typeMetrique.name}_${params.periodeAnalyse.name}_${params.organisationId ?? 'global'}';
|
|
}
|
|
|
|
/// Vérifie si les données du cache sont encore valides
|
|
bool _isCacheValide(Map<String, dynamic> cachedData) {
|
|
final dateCache = DateTime.tryParse(cachedData['dateCache'] ?? '');
|
|
if (dateCache == null) return false;
|
|
|
|
final dureeVie = Duration(minutes: cachedData['dureeVieMinutes'] ?? 60);
|
|
return DateTime.now().difference(dateCache) < dureeVie;
|
|
}
|
|
|
|
/// Convertit les données analytics en format cache
|
|
Map<String, dynamic> _mapAnalyticsDataToCache(AnalyticsData data) {
|
|
return {
|
|
'id': data.id,
|
|
'typeMetrique': data.typeMetrique.name,
|
|
'periodeAnalyse': data.periodeAnalyse.name,
|
|
'valeur': data.valeur,
|
|
'valeurPrecedente': data.valeurPrecedente,
|
|
'pourcentageEvolution': data.pourcentageEvolution,
|
|
'dateDebut': data.dateDebut.toIso8601String(),
|
|
'dateFin': data.dateFin.toIso8601String(),
|
|
'dateCalcul': data.dateCalcul.toIso8601String(),
|
|
'organisationId': data.organisationId,
|
|
'nomOrganisation': data.nomOrganisation,
|
|
'utilisateurId': data.utilisateurId,
|
|
'nomUtilisateur': data.nomUtilisateur,
|
|
'libellePersonnalise': data.libellePersonnalise,
|
|
'description': data.description,
|
|
'donneesDetaillees': data.donneesDetaillees,
|
|
'configurationGraphique': data.configurationGraphique,
|
|
'metadonnees': data.metadonnees,
|
|
'indicateurFiabilite': data.indicateurFiabilite,
|
|
'nombreElementsAnalyses': data.nombreElementsAnalyses,
|
|
'tempsCalculMs': data.tempsCalculMs,
|
|
'tempsReel': data.tempsReel,
|
|
'necessiteMiseAJour': data.necessiteMiseAJour,
|
|
'niveauPriorite': data.niveauPriorite,
|
|
'tags': data.tags,
|
|
'dateCache': DateTime.now().toIso8601String(),
|
|
'dureeVieMinutes': _determinerDureeVieCache(data.periodeAnalyse).inMinutes,
|
|
};
|
|
}
|
|
|
|
/// Convertit les données du cache en AnalyticsData
|
|
AnalyticsData _mapCacheToAnalyticsData(Map<String, dynamic> cachedData) {
|
|
return AnalyticsData(
|
|
id: cachedData['id'],
|
|
typeMetrique: TypeMetrique.values.firstWhere(
|
|
(e) => e.name == cachedData['typeMetrique'],
|
|
),
|
|
periodeAnalyse: PeriodeAnalyse.values.firstWhere(
|
|
(e) => e.name == cachedData['periodeAnalyse'],
|
|
),
|
|
valeur: cachedData['valeur']?.toDouble() ?? 0.0,
|
|
valeurPrecedente: cachedData['valeurPrecedente']?.toDouble(),
|
|
pourcentageEvolution: cachedData['pourcentageEvolution']?.toDouble(),
|
|
dateDebut: DateTime.parse(cachedData['dateDebut']),
|
|
dateFin: DateTime.parse(cachedData['dateFin']),
|
|
dateCalcul: DateTime.parse(cachedData['dateCalcul']),
|
|
organisationId: cachedData['organisationId'],
|
|
nomOrganisation: cachedData['nomOrganisation'],
|
|
utilisateurId: cachedData['utilisateurId'],
|
|
nomUtilisateur: cachedData['nomUtilisateur'],
|
|
libellePersonnalise: cachedData['libellePersonnalise'],
|
|
description: cachedData['description'],
|
|
donneesDetaillees: cachedData['donneesDetaillees'],
|
|
configurationGraphique: cachedData['configurationGraphique'],
|
|
metadonnees: cachedData['metadonnees'] != null
|
|
? Map<String, dynamic>.from(cachedData['metadonnees'])
|
|
: null,
|
|
indicateurFiabilite: cachedData['indicateurFiabilite']?.toDouble() ?? 95.0,
|
|
nombreElementsAnalyses: cachedData['nombreElementsAnalyses'],
|
|
tempsCalculMs: cachedData['tempsCalculMs'],
|
|
tempsReel: cachedData['tempsReel'] ?? false,
|
|
necessiteMiseAJour: cachedData['necessiteMiseAJour'] ?? false,
|
|
niveauPriorite: cachedData['niveauPriorite'] ?? 3,
|
|
tags: cachedData['tags'] != null
|
|
? List<String>.from(cachedData['tags'])
|
|
: null,
|
|
);
|
|
}
|
|
|
|
/// Détermine la durée de vie du cache selon la période
|
|
Duration _determinerDureeVieCache(PeriodeAnalyse periode) {
|
|
switch (periode) {
|
|
case PeriodeAnalyse.aujourdHui:
|
|
case PeriodeAnalyse.hier:
|
|
return const Duration(minutes: 15); // 15 minutes pour les données récentes
|
|
case PeriodeAnalyse.cetteSemaine:
|
|
case PeriodeAnalyse.semaineDerniere:
|
|
case PeriodeAnalyse.septDerniersJours:
|
|
return const Duration(hours: 1); // 1 heure pour les données hebdomadaires
|
|
case PeriodeAnalyse.ceMois:
|
|
case PeriodeAnalyse.moisDernier:
|
|
case PeriodeAnalyse.trenteDerniersJours:
|
|
return const Duration(hours: 4); // 4 heures pour les données mensuelles
|
|
case PeriodeAnalyse.troisDerniersMois:
|
|
case PeriodeAnalyse.sixDerniersMois:
|
|
return const Duration(hours: 12); // 12 heures pour les données trimestrielles
|
|
case PeriodeAnalyse.cetteAnnee:
|
|
case PeriodeAnalyse.anneeDerniere:
|
|
return const Duration(days: 1); // 1 jour pour les données annuelles
|
|
case PeriodeAnalyse.periodePersonnalisee:
|
|
return const Duration(hours: 2); // 2 heures par défaut
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Paramètres pour le use case CalculerMetrique
|
|
class CalculerMetriqueParams extends Equatable {
|
|
const CalculerMetriqueParams({
|
|
required this.typeMetrique,
|
|
required this.periodeAnalyse,
|
|
this.organisationId,
|
|
this.forceRecalcul = false,
|
|
});
|
|
|
|
final TypeMetrique typeMetrique;
|
|
final PeriodeAnalyse periodeAnalyse;
|
|
final String? organisationId;
|
|
final bool forceRecalcul;
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
typeMetrique,
|
|
periodeAnalyse,
|
|
organisationId,
|
|
forceRecalcul,
|
|
];
|
|
|
|
CalculerMetriqueParams copyWith({
|
|
TypeMetrique? typeMetrique,
|
|
PeriodeAnalyse? periodeAnalyse,
|
|
String? organisationId,
|
|
bool? forceRecalcul,
|
|
}) {
|
|
return CalculerMetriqueParams(
|
|
typeMetrique: typeMetrique ?? this.typeMetrique,
|
|
periodeAnalyse: periodeAnalyse ?? this.periodeAnalyse,
|
|
organisationId: organisationId ?? this.organisationId,
|
|
forceRecalcul: forceRecalcul ?? this.forceRecalcul,
|
|
);
|
|
}
|
|
}
|