Refactoring - Version OK
This commit is contained in:
@@ -0,0 +1,597 @@
|
||||
/// BLoC pour la gestion des contributions
|
||||
library contributions_bloc;
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../core/utils/logger.dart';
|
||||
import '../data/models/contribution_model.dart';
|
||||
import 'contributions_event.dart';
|
||||
import 'contributions_state.dart';
|
||||
|
||||
/// BLoC pour gérer l'état des contributions
|
||||
class ContributionsBloc extends Bloc<ContributionsEvent, ContributionsState> {
|
||||
ContributionsBloc() : super(const ContributionsInitial()) {
|
||||
on<LoadContributions>(_onLoadContributions);
|
||||
on<LoadContributionById>(_onLoadContributionById);
|
||||
on<CreateContribution>(_onCreateContribution);
|
||||
on<UpdateContribution>(_onUpdateContribution);
|
||||
on<DeleteContribution>(_onDeleteContribution);
|
||||
on<SearchContributions>(_onSearchContributions);
|
||||
on<LoadContributionsByMembre>(_onLoadContributionsByMembre);
|
||||
on<LoadContributionsPayees>(_onLoadContributionsPayees);
|
||||
on<LoadContributionsNonPayees>(_onLoadContributionsNonPayees);
|
||||
on<LoadContributionsEnRetard>(_onLoadContributionsEnRetard);
|
||||
on<RecordPayment>(_onRecordPayment);
|
||||
on<LoadContributionsStats>(_onLoadContributionsStats);
|
||||
on<GenerateAnnualContributions>(_onGenerateAnnualContributions);
|
||||
on<SendPaymentReminder>(_onSendPaymentReminder);
|
||||
}
|
||||
|
||||
/// Charger la liste des contributions
|
||||
Future<void> _onLoadContributions(
|
||||
LoadContributions event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'LoadContributions', data: {
|
||||
'page': event.page,
|
||||
'size': event.size,
|
||||
});
|
||||
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions...'));
|
||||
|
||||
// Simuler un délai réseau
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// Données mock
|
||||
final contributions = _getMockContributions();
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
// Pagination
|
||||
final start = event.page * event.size;
|
||||
final end = (start + event.size).clamp(0, total);
|
||||
final paginatedContributions = contributions.sublist(
|
||||
start.clamp(0, total),
|
||||
end,
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: paginatedContributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionsLoaded', data: {
|
||||
'count': paginatedContributions.length,
|
||||
'total': total,
|
||||
});
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors du chargement des contributions',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors du chargement des contributions',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger une contribution par ID
|
||||
Future<void> _onLoadContributionById(
|
||||
LoadContributionById event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'LoadContributionById', data: {
|
||||
'id': event.id,
|
||||
});
|
||||
|
||||
emit(const ContributionsLoading(message: 'Chargement de la contribution...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
final contributions = _getMockContributions();
|
||||
final contribution = contributions.firstWhere(
|
||||
(c) => c.id == event.id,
|
||||
orElse: () => throw Exception('Contribution non trouvée'),
|
||||
);
|
||||
|
||||
emit(ContributionDetailLoaded(contribution: contribution));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionDetailLoaded');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors du chargement de la contribution',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Contribution non trouvée',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Créer une nouvelle contribution
|
||||
Future<void> _onCreateContribution(
|
||||
CreateContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'CreateContribution');
|
||||
|
||||
emit(const ContributionsLoading(message: 'Création de la contribution...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final newContribution = event.contribution.copyWith(
|
||||
id: 'cont_${DateTime.now().millisecondsSinceEpoch}',
|
||||
dateCreation: DateTime.now(),
|
||||
);
|
||||
|
||||
emit(ContributionCreated(contribution: newContribution));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionCreated');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors de la création de la contribution',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors de la création de la contribution',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Mettre à jour une contribution
|
||||
Future<void> _onUpdateContribution(
|
||||
UpdateContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'UpdateContribution', data: {
|
||||
'id': event.id,
|
||||
});
|
||||
|
||||
emit(const ContributionsLoading(message: 'Mise à jour de la contribution...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final updatedContribution = event.contribution.copyWith(
|
||||
id: event.id,
|
||||
dateModification: DateTime.now(),
|
||||
);
|
||||
|
||||
emit(ContributionUpdated(contribution: updatedContribution));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionUpdated');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors de la mise à jour de la contribution',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors de la mise à jour de la contribution',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprimer une contribution
|
||||
Future<void> _onDeleteContribution(
|
||||
DeleteContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'DeleteContribution', data: {
|
||||
'id': event.id,
|
||||
});
|
||||
|
||||
emit(const ContributionsLoading(message: 'Suppression de la contribution...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
emit(ContributionDeleted(id: event.id));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionDeleted');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors de la suppression de la contribution',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors de la suppression de la contribution',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Rechercher des contributions
|
||||
Future<void> _onSearchContributions(
|
||||
SearchContributions event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'SearchContributions');
|
||||
|
||||
emit(const ContributionsLoading(message: 'Recherche en cours...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
var contributions = _getMockContributions();
|
||||
|
||||
// Filtrer par membre
|
||||
if (event.membreId != null) {
|
||||
contributions = contributions
|
||||
.where((c) => c.membreId == event.membreId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Filtrer par statut
|
||||
if (event.statut != null) {
|
||||
contributions = contributions
|
||||
.where((c) => c.statut == event.statut)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Filtrer par type
|
||||
if (event.type != null) {
|
||||
contributions = contributions
|
||||
.where((c) => c.type == event.type)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Filtrer par année
|
||||
if (event.annee != null) {
|
||||
contributions = contributions
|
||||
.where((c) => c.annee == event.annee)
|
||||
.toList();
|
||||
}
|
||||
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
// Pagination
|
||||
final start = event.page * event.size;
|
||||
final end = (start + event.size).clamp(0, total);
|
||||
final paginatedContributions = contributions.sublist(
|
||||
start.clamp(0, total),
|
||||
end,
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: paginatedContributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionsLoaded (search)');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors de la recherche de contributions',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors de la recherche',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger les contributions d'un membre
|
||||
Future<void> _onLoadContributionsByMembre(
|
||||
LoadContributionsByMembre event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'LoadContributionsByMembre', data: {
|
||||
'membreId': event.membreId,
|
||||
});
|
||||
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions du membre...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions()
|
||||
.where((c) => c.membreId == event.membreId)
|
||||
.toList();
|
||||
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: contributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionsLoaded (by membre)');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error(
|
||||
'Erreur lors du chargement des contributions du membre',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
emit(ContributionsError(
|
||||
message: 'Erreur lors du chargement',
|
||||
error: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger les contributions payées
|
||||
Future<void> _onLoadContributionsPayees(
|
||||
LoadContributionsPayees event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions payées...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions()
|
||||
.where((c) => c.statut == ContributionStatus.payee)
|
||||
.toList();
|
||||
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: contributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger les contributions non payées
|
||||
Future<void> _onLoadContributionsNonPayees(
|
||||
LoadContributionsNonPayees event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions non payées...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions()
|
||||
.where((c) => c.statut == ContributionStatus.nonPayee)
|
||||
.toList();
|
||||
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: contributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger les contributions en retard
|
||||
Future<void> _onLoadContributionsEnRetard(
|
||||
LoadContributionsEnRetard event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions en retard...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions()
|
||||
.where((c) => c.statut == ContributionStatus.enRetard)
|
||||
.toList();
|
||||
|
||||
final total = contributions.length;
|
||||
final totalPages = (total / event.size).ceil();
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: contributions,
|
||||
total: total,
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
totalPages: totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Enregistrer un paiement
|
||||
Future<void> _onRecordPayment(
|
||||
RecordPayment event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.blocEvent('ContributionsBloc', 'RecordPayment');
|
||||
|
||||
emit(const ContributionsLoading(message: 'Enregistrement du paiement...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions();
|
||||
final contribution = contributions.firstWhere((c) => c.id == event.contributionId);
|
||||
|
||||
final updatedContribution = contribution.copyWith(
|
||||
montantPaye: event.montant,
|
||||
datePaiement: event.datePaiement,
|
||||
methodePaiement: event.methodePaiement,
|
||||
numeroPaiement: event.numeroPaiement,
|
||||
referencePaiement: event.referencePaiement,
|
||||
statut: event.montant >= contribution.montant
|
||||
? ContributionStatus.payee
|
||||
: ContributionStatus.partielle,
|
||||
dateModification: DateTime.now(),
|
||||
);
|
||||
|
||||
emit(PaymentRecorded(contribution: updatedContribution));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'PaymentRecorded');
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de l\'enregistrement du paiement', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Charger les statistiques
|
||||
Future<void> _onLoadContributionsStats(
|
||||
LoadContributionsStats event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des statistiques...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
final contributions = _getMockContributions();
|
||||
|
||||
final stats = {
|
||||
'total': contributions.length,
|
||||
'payees': contributions.where((c) => c.statut == ContributionStatus.payee).length,
|
||||
'nonPayees': contributions.where((c) => c.statut == ContributionStatus.nonPayee).length,
|
||||
'enRetard': contributions.where((c) => c.statut == ContributionStatus.enRetard).length,
|
||||
'partielles': contributions.where((c) => c.statut == ContributionStatus.partielle).length,
|
||||
'montantTotal': contributions.fold<double>(0, (sum, c) => sum + c.montant),
|
||||
'montantPaye': contributions.fold<double>(0, (sum, c) => sum + (c.montantPaye ?? 0)),
|
||||
'montantRestant': contributions.fold<double>(0, (sum, c) => sum + c.montantRestant),
|
||||
'tauxRecouvrement': 0.0,
|
||||
};
|
||||
|
||||
if (stats['montantTotal']! > 0) {
|
||||
stats['tauxRecouvrement'] = (stats['montantPaye']! / stats['montantTotal']!) * 100;
|
||||
}
|
||||
|
||||
emit(ContributionsStatsLoaded(stats: stats));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Générer les contributions annuelles
|
||||
Future<void> _onGenerateAnnualContributions(
|
||||
GenerateAnnualContributions event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Génération des contributions...'));
|
||||
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
// Simuler la génération de 50 contributions
|
||||
emit(const ContributionsGenerated(nombreGenere: 50));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Envoyer un rappel de paiement
|
||||
Future<void> _onSendPaymentReminder(
|
||||
SendPaymentReminder event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Envoi du rappel...'));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
emit(ReminderSent(contributionId: event.contributionId));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Données mock pour les tests
|
||||
List<ContributionModel> _getMockContributions() {
|
||||
final now = DateTime.now();
|
||||
return [
|
||||
ContributionModel(
|
||||
id: 'cont_001',
|
||||
membreId: 'mbr_001',
|
||||
membreNom: 'Dupont',
|
||||
membrePrenom: 'Jean',
|
||||
montant: 50000,
|
||||
dateEcheance: DateTime(now.year, 12, 31),
|
||||
annee: now.year,
|
||||
statut: ContributionStatus.payee,
|
||||
montantPaye: 50000,
|
||||
datePaiement: DateTime(now.year, 1, 15),
|
||||
methodePaiement: PaymentMethod.virement,
|
||||
),
|
||||
ContributionModel(
|
||||
id: 'cont_002',
|
||||
membreId: 'mbr_002',
|
||||
membreNom: 'Martin',
|
||||
membrePrenom: 'Marie',
|
||||
montant: 50000,
|
||||
dateEcheance: DateTime(now.year, 12, 31),
|
||||
annee: now.year,
|
||||
statut: ContributionStatus.nonPayee,
|
||||
),
|
||||
ContributionModel(
|
||||
id: 'cont_003',
|
||||
membreId: 'mbr_003',
|
||||
membreNom: 'Bernard',
|
||||
membrePrenom: 'Pierre',
|
||||
montant: 50000,
|
||||
dateEcheance: DateTime(now.year - 1, 12, 31),
|
||||
annee: now.year - 1,
|
||||
statut: ContributionStatus.enRetard,
|
||||
),
|
||||
ContributionModel(
|
||||
id: 'cont_004',
|
||||
membreId: 'mbr_004',
|
||||
membreNom: 'Dubois',
|
||||
membrePrenom: 'Sophie',
|
||||
montant: 50000,
|
||||
dateEcheance: DateTime(now.year, 12, 31),
|
||||
annee: now.year,
|
||||
statut: ContributionStatus.partielle,
|
||||
montantPaye: 25000,
|
||||
datePaiement: DateTime(now.year, 2, 10),
|
||||
methodePaiement: PaymentMethod.especes,
|
||||
),
|
||||
ContributionModel(
|
||||
id: 'cont_005',
|
||||
membreId: 'mbr_005',
|
||||
membreNom: 'Petit',
|
||||
membrePrenom: 'Luc',
|
||||
montant: 50000,
|
||||
dateEcheance: DateTime(now.year, 12, 31),
|
||||
annee: now.year,
|
||||
statut: ContributionStatus.payee,
|
||||
montantPaye: 50000,
|
||||
datePaiement: DateTime(now.year, 3, 5),
|
||||
methodePaiement: PaymentMethod.mobileMoney,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user