Mise en place suppression membre

This commit is contained in:
d6soft
2025-06-12 16:39:44 +02:00
parent ace38d4025
commit 25c9d5874c
19 changed files with 63219 additions and 61871 deletions

View File

@@ -127,18 +127,44 @@ class MembreRepository extends ChangeNotifier {
// Appeler l'API users
final response = await ApiService.instance.post('/users', data: data);
if (response.statusCode == 201 || response.statusCode == 200) {
// Créer le membre avec les données retournées par l'API
final createdMember = MembreModel.fromJson(response.data);
if (response.statusCode == 201) {
// Extraire l'ID de la réponse API
final responseData = response.data;
debugPrint('🎉 Réponse API création utilisateur: $responseData');
// Sauvegarder localement
// L'API retourne {"status":"success","message":"Utilisateur créé avec succès","id":"10027748"}
final userId = responseData['id'] is String ? int.parse(responseData['id']) : responseData['id'] as int;
// Créer le nouveau membre avec l'ID retourné par l'API
final createdMember = MembreModel(
id: userId,
fkEntite: membre.fkEntite,
role: membre.role,
fkTitre: membre.fkTitre,
name: membre.name,
firstName: membre.firstName,
username: membre.username,
sectName: membre.sectName,
email: membre.email,
phone: membre.phone,
mobile: membre.mobile,
dateNaissance: membre.dateNaissance,
dateEmbauche: membre.dateEmbauche,
createdAt: DateTime.now(),
isActive: membre.isActive,
);
// Sauvegarder localement dans Hive
await saveMembreBox(createdMember);
return createdMember; // Retourner le membre créé
debugPrint('✅ Membre créé avec l\'ID: $userId et sauvegardé localement');
return createdMember;
}
debugPrint('❌ Échec création membre - Code: ${response.statusCode}');
return null;
} catch (e) {
debugPrint('Erreur lors de la création du membre: $e');
debugPrint('Erreur lors de la création du membre: $e');
rethrow; // Propager l'exception pour la gestion d'erreurs
} finally {
_isLoading = false;
@@ -174,25 +200,45 @@ class MembreRepository extends ChangeNotifier {
}
}
// Supprimer un membre via l'API
Future<bool> deleteMembre(int id) async {
// Supprimer un membre via l'API avec transfert optionnel
Future<bool> deleteMembre(int membreId, [int? transferToUserId, int? operationId]) async {
_isLoading = true;
notifyListeners();
try {
// Appeler l'API users au lieu de membres (correction ici)
final response = await ApiService.instance.delete('/users/$id');
String endpoint = '/users/$membreId';
// Construire les paramètres query SEULEMENT si on a des passages à transférer
List<String> queryParams = [];
if (transferToUserId != null && transferToUserId > 0) {
queryParams.add('transfer_to=$transferToUserId');
// Ajouter operation_id SEULEMENT s'il y a un transfert
if (operationId != null && operationId > 0) {
queryParams.add('operation_id=$operationId');
}
}
// Ajouter les paramètres à l'endpoint
if (queryParams.isNotEmpty) {
endpoint += '?${queryParams.join('&')}';
}
debugPrint('🔗 DELETE endpoint: $endpoint');
final response = await ApiService.instance.delete(endpoint);
if (response.statusCode == 200 || response.statusCode == 204) {
// Supprimer le membre localement
await deleteMembreBox(id);
await deleteMembreBox(membreId);
return true;
}
return false;
} catch (e) {
debugPrint('Erreur lors de la suppression du membre: $e');
return false;
rethrow;
} finally {
_isLoading = false;
notifyListeners();

View File

@@ -41,6 +41,44 @@ class OperationRepository extends ChangeNotifier {
return _operationBox.get(id);
}
OperationModel? getCurrentOperation() {
try {
// Récupérer toutes les opérations actives
final activeOperations = _operationBox.values.where((operation) => operation.isActive == true).toList();
if (activeOperations.isEmpty) {
debugPrint('⚠️ Aucune opération active trouvée');
return null;
}
// Trier par ID décroissant et prendre la première (ID le plus élevé)
activeOperations.sort((a, b) => b.id.compareTo(a.id));
final currentOperation = activeOperations.first;
debugPrint('🎯 Opération courante: ${currentOperation.id} - ${currentOperation.name}');
return currentOperation;
} catch (e) {
debugPrint('❌ Erreur lors de la récupération de l\'opération courante: $e');
return null;
}
}
// Méthode helper pour récupérer seulement l'ID de l'opération courante
int? getCurrentOperationId() {
final currentOperation = getCurrentOperation();
return currentOperation?.id;
}
// Méthode pour récupérer toutes les opérations actives (utile pour debug/admin)
List<OperationModel> getActiveOperations() {
try {
return _operationBox.values.where((operation) => operation.isActive == true).toList()..sort((a, b) => b.id.compareTo(a.id)); // Tri par ID décroissant
} catch (e) {
debugPrint('❌ Erreur lors de la récupération des opérations actives: $e');
return [];
}
}
// Sauvegarder une opération
Future<void> saveOperation(OperationModel operation) async {
await _operationBox.put(operation.id, operation);

View File

@@ -9,6 +9,9 @@ class PassageRepository extends ChangeNotifier {
// Constructeur sans paramètres - utilise ApiService.instance
PassageRepository();
// Cache pour les statistiques
Map<String, dynamic>? _cachedStats;
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
// et vérifier qu'elle est ouverte avant accès
Box<PassageModel> get _passageBox {
@@ -16,6 +19,19 @@ class PassageRepository extends ChangeNotifier {
return Hive.box<PassageModel>(AppKeys.passagesBoxName);
}
// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
Box<PassageModel> getPassagesBox() {
try {
if (!Hive.isBoxOpen(AppKeys.passagesBoxName)) {
throw Exception('La boîte passages n\'est pas ouverte');
}
return Hive.box<PassageModel>(AppKeys.passagesBoxName);
} catch (e) {
debugPrint('Erreur lors de l\'accès à la boîte passages: $e');
rethrow;
}
}
// Stream pour notifier des changements de passages
StreamController<List<PassageModel>>? _passageStreamController;
@@ -73,6 +89,16 @@ class PassageRepository extends ChangeNotifier {
return _passageBox.values.where((passage) => passage.fkOperation == operationId).toList();
}
// Récupérer les passages par utilisateur
List<PassageModel> getPassagesByUser(int userId) {
try {
return _passageBox.values.where((passage) => passage.fkUser == userId).toList();
} catch (e) {
debugPrint('Erreur lors de la récupération des passages par utilisateur: $e');
return [];
}
}
// Récupérer les passages par date
List<PassageModel> getPassagesByDate(DateTime date) {
return _passageBox.values.where((passage) {
@@ -263,11 +289,14 @@ class PassageRepository extends ChangeNotifier {
}
}
// Statistiques
Map<String, int> getPassageStatistics() {
// Recalculer les statistiques (appelée par le ValueListenableBuilder)
Map<String, dynamic> calculatePassageStatistics() {
final allPassages = getAllPassages();
return {
debugPrint('📊 Calcul des statistiques: ${allPassages.length} passages');
// Statistiques globales
final globalStats = {
'total': allPassages.length,
'effectues': allPassages.where((p) => p.fkType == 1).length,
'a_finaliser': allPassages.where((p) => p.fkType == 2).length,
@@ -276,6 +305,57 @@ class PassageRepository extends ChangeNotifier {
'lots': allPassages.where((p) => p.fkType == 5).length,
'maisons_vides': allPassages.where((p) => p.fkType == 6).length,
};
// Statistiques par utilisateur
final Map<int, Map<String, int>> statsByUser = {};
// Grouper les passages par utilisateur
final passagesByUser = <int, List<PassageModel>>{};
for (final passage in allPassages) {
passagesByUser.putIfAbsent(passage.fkUser, () => []).add(passage);
}
// Calculer les statistiques pour chaque utilisateur
for (final entry in passagesByUser.entries) {
final userId = entry.key;
final userPassages = entry.value;
statsByUser[userId] = {
'total': userPassages.length,
'effectues': userPassages.where((p) => p.fkType == 1).length,
'a_finaliser': userPassages.where((p) => p.fkType == 2).length,
'refuses': userPassages.where((p) => p.fkType == 3).length,
'dons': userPassages.where((p) => p.fkType == 4).length,
'lots': userPassages.where((p) => p.fkType == 5).length,
'maisons_vides': userPassages.where((p) => p.fkType == 6).length,
};
}
// Statistiques par type
final statsByType = {
1: allPassages.where((p) => p.fkType == 1).length,
2: allPassages.where((p) => p.fkType == 2).length,
3: allPassages.where((p) => p.fkType == 3).length,
4: allPassages.where((p) => p.fkType == 4).length,
5: allPassages.where((p) => p.fkType == 5).length,
6: allPassages.where((p) => p.fkType == 6).length,
};
// Mettre en cache et retourner
_cachedStats = {
'global': globalStats,
'by_user': statsByUser,
'by_type': statsByType,
'user_count': statsByUser.length,
'calculated_at': DateTime.now().toIso8601String(),
};
return _cachedStats!;
}
// Getter simple pour les statistiques (optionnel, pour usage sans ValueListenableBuilder)
Map<String, dynamic> getPassageStatistics() {
return _cachedStats ?? calculatePassageStatistics();
}
// Vider tous les passages