Versione OK Pour l'onglet événements.

This commit is contained in:
DahoudG
2025-09-15 20:15:34 +00:00
parent 8a619ee1bf
commit 12d514d866
73 changed files with 11508 additions and 674 deletions

View File

@@ -1,6 +1,9 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/models/cotisation_model.dart';
import '../../../../core/models/payment_model.dart';
import '../../../../core/services/payment_service.dart';
import '../../../../core/services/notification_service.dart';
import '../../domain/repositories/cotisation_repository.dart';
import 'cotisations_event.dart';
import 'cotisations_state.dart';
@@ -10,8 +13,14 @@ import 'cotisations_state.dart';
@injectable
class CotisationsBloc extends Bloc<CotisationsEvent, CotisationsState> {
final CotisationRepository _cotisationRepository;
final PaymentService _paymentService;
final NotificationService _notificationService;
CotisationsBloc(this._cotisationRepository) : super(const CotisationsInitial()) {
CotisationsBloc(
this._cotisationRepository,
this._paymentService,
this._notificationService,
) : super(const CotisationsInitial()) {
// Enregistrement des handlers d'événements
on<LoadCotisations>(_onLoadCotisations);
on<LoadCotisationById>(_onLoadCotisationById);
@@ -28,6 +37,15 @@ class CotisationsBloc extends Bloc<CotisationsEvent, CotisationsState> {
on<ResetCotisationsState>(_onResetCotisationsState);
on<FilterCotisations>(_onFilterCotisations);
on<SortCotisations>(_onSortCotisations);
// Nouveaux handlers pour les paiements et fonctionnalités avancées
on<InitiatePayment>(_onInitiatePayment);
on<CheckPaymentStatus>(_onCheckPaymentStatus);
on<CancelPayment>(_onCancelPayment);
on<ScheduleNotifications>(_onScheduleNotifications);
on<SyncWithServer>(_onSyncWithServer);
on<ApplyAdvancedFilters>(_onApplyAdvancedFilters);
on<ExportCotisations>(_onExportCotisations);
}
/// Handler pour charger la liste des cotisations
@@ -506,4 +524,207 @@ class CotisationsBloc extends Bloc<CotisationsEvent, CotisationsState> {
emit(currentState.copyWith(filteredCotisations: sortedList));
}
}
/// Handler pour initier un paiement
Future<void> _onInitiatePayment(
InitiatePayment event,
Emitter<CotisationsState> emit,
) async {
try {
// Valider les données de paiement
if (!_paymentService.validatePaymentData(
cotisationId: event.cotisationId,
montant: event.montant,
methodePaiement: event.methodePaiement,
numeroTelephone: event.numeroTelephone,
)) {
emit(PaymentFailure(
cotisationId: event.cotisationId,
paymentId: '',
errorMessage: 'Données de paiement invalides',
errorCode: 'INVALID_DATA',
));
return;
}
// Initier le paiement
final payment = await _paymentService.initiatePayment(
cotisationId: event.cotisationId,
montant: event.montant,
methodePaiement: event.methodePaiement,
numeroTelephone: event.numeroTelephone,
nomPayeur: event.nomPayeur,
emailPayeur: event.emailPayeur,
);
emit(PaymentInProgress(
cotisationId: event.cotisationId,
paymentId: payment.id,
methodePaiement: event.methodePaiement,
montant: event.montant,
));
} catch (e) {
emit(PaymentFailure(
cotisationId: event.cotisationId,
paymentId: '',
errorMessage: e.toString(),
));
}
}
/// Handler pour vérifier le statut d'un paiement
Future<void> _onCheckPaymentStatus(
CheckPaymentStatus event,
Emitter<CotisationsState> emit,
) async {
try {
final payment = await _paymentService.checkPaymentStatus(event.paymentId);
if (payment.isSuccessful) {
// Récupérer la cotisation mise à jour
final cotisation = await _cotisationRepository.getCotisationById(payment.cotisationId);
emit(PaymentSuccess(
cotisationId: payment.cotisationId,
payment: payment,
updatedCotisation: cotisation,
));
// Envoyer notification de succès
await _notificationService.showPaymentConfirmation(cotisation, payment.montant);
} else if (payment.isFailed) {
emit(PaymentFailure(
cotisationId: payment.cotisationId,
paymentId: payment.id,
errorMessage: payment.messageErreur ?? 'Paiement échoué',
));
// Envoyer notification d'échec
final cotisation = await _cotisationRepository.getCotisationById(payment.cotisationId);
await _notificationService.showPaymentFailure(cotisation, payment.messageErreur ?? 'Erreur inconnue');
}
} catch (e) {
emit(CotisationsError('Erreur lors de la vérification du paiement: ${e.toString()}'));
}
}
/// Handler pour annuler un paiement
Future<void> _onCancelPayment(
CancelPayment event,
Emitter<CotisationsState> emit,
) async {
try {
final cancelled = await _paymentService.cancelPayment(event.paymentId);
if (cancelled) {
emit(PaymentCancelled(
cotisationId: event.cotisationId,
paymentId: event.paymentId,
));
} else {
emit(const CotisationsError('Impossible d\'annuler le paiement'));
}
} catch (e) {
emit(CotisationsError('Erreur lors de l\'annulation du paiement: ${e.toString()}'));
}
}
/// Handler pour programmer les notifications
Future<void> _onScheduleNotifications(
ScheduleNotifications event,
Emitter<CotisationsState> emit,
) async {
try {
await _notificationService.scheduleAllCotisationsNotifications(event.cotisations);
emit(NotificationsScheduled(
notificationsCount: event.cotisations.length * 2,
cotisationIds: event.cotisations.map((c) => c.id).toList(),
));
} catch (e) {
emit(CotisationsError('Erreur lors de la programmation des notifications: ${e.toString()}'));
}
}
/// Handler pour synchroniser avec le serveur
Future<void> _onSyncWithServer(
SyncWithServer event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const SyncInProgress('Synchronisation en cours...'));
// Recharger les données
final cotisations = await _cotisationRepository.getCotisations();
emit(SyncCompleted(
itemsSynced: cotisations.length,
syncTime: DateTime.now(),
));
// Émettre l'état chargé avec les nouvelles données
emit(CotisationsLoaded(
cotisations: cotisations,
filteredCotisations: cotisations,
));
} catch (e) {
emit(CotisationsError('Erreur lors de la synchronisation: ${e.toString()}'));
}
}
/// Handler pour appliquer des filtres avancés
Future<void> _onApplyAdvancedFilters(
ApplyAdvancedFilters event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const CotisationsLoading());
final cotisations = await _cotisationRepository.rechercherCotisations(
membreId: event.filters['membreId'],
statut: event.filters['statut'],
typeCotisation: event.filters['typeCotisation'],
annee: event.filters['annee'],
mois: event.filters['mois'],
);
emit(CotisationsSearchResults(
cotisations: cotisations,
searchCriteria: event.filters,
));
} catch (e) {
emit(CotisationsError('Erreur lors de l\'application des filtres: ${e.toString()}'));
}
}
/// Handler pour exporter les cotisations
Future<void> _onExportCotisations(
ExportCotisations event,
Emitter<CotisationsState> emit,
) async {
try {
final cotisations = event.cotisations ?? [];
emit(ExportInProgress(
format: event.format,
totalItems: cotisations.length,
));
// TODO: Implémenter l'export réel selon le format
await Future.delayed(const Duration(seconds: 2)); // Simulation
emit(ExportCompleted(
format: event.format,
filePath: '/storage/emulated/0/Download/cotisations.${event.format}',
itemsExported: cotisations.length,
));
} catch (e) {
emit(CotisationsError('Erreur lors de l\'export: ${e.toString()}'));
}
}
}

View File

@@ -204,3 +204,97 @@ class SortCotisations extends CotisationsEvent {
@override
List<Object?> get props => [sortBy, ascending];
}
/// Événement pour initier un paiement
class InitiatePayment extends CotisationsEvent {
final String cotisationId;
final double montant;
final String methodePaiement;
final String numeroTelephone;
final String? nomPayeur;
final String? emailPayeur;
const InitiatePayment({
required this.cotisationId,
required this.montant,
required this.methodePaiement,
required this.numeroTelephone,
this.nomPayeur,
this.emailPayeur,
});
@override
List<Object?> get props => [
cotisationId,
montant,
methodePaiement,
numeroTelephone,
nomPayeur,
emailPayeur,
];
}
/// Événement pour vérifier le statut d'un paiement
class CheckPaymentStatus extends CotisationsEvent {
final String paymentId;
const CheckPaymentStatus(this.paymentId);
@override
List<Object?> get props => [paymentId];
}
/// Événement pour annuler un paiement
class CancelPayment extends CotisationsEvent {
final String paymentId;
final String cotisationId;
const CancelPayment({
required this.paymentId,
required this.cotisationId,
});
@override
List<Object?> get props => [paymentId, cotisationId];
}
/// Événement pour programmer des notifications
class ScheduleNotifications extends CotisationsEvent {
final List<CotisationModel> cotisations;
const ScheduleNotifications(this.cotisations);
@override
List<Object?> get props => [cotisations];
}
/// Événement pour synchroniser avec le serveur
class SyncWithServer extends CotisationsEvent {
final bool forceSync;
const SyncWithServer({this.forceSync = false});
@override
List<Object?> get props => [forceSync];
}
/// Événement pour appliquer des filtres avancés
class ApplyAdvancedFilters extends CotisationsEvent {
final Map<String, dynamic> filters;
const ApplyAdvancedFilters(this.filters);
@override
List<Object?> get props => [filters];
}
/// Événement pour exporter des données
class ExportCotisations extends CotisationsEvent {
final String format; // 'pdf', 'excel', 'csv'
final List<CotisationModel>? cotisations;
const ExportCotisations(this.format, {this.cotisations});
@override
List<Object?> get props => [format, cotisations];
}

View File

@@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import '../../../../core/models/cotisation_model.dart';
import '../../../../core/models/payment_model.dart';
/// États du BLoC des cotisations
abstract class CotisationsState extends Equatable {
@@ -245,3 +246,137 @@ class CotisationsSearchResults extends CotisationsState {
@override
List<Object?> get props => [cotisations, searchCriteria, hasReachedMax, currentPage];
}
/// État pour un paiement en cours
class PaymentInProgress extends CotisationsState {
final String cotisationId;
final String paymentId;
final String methodePaiement;
final double montant;
const PaymentInProgress({
required this.cotisationId,
required this.paymentId,
required this.methodePaiement,
required this.montant,
});
@override
List<Object?> get props => [cotisationId, paymentId, methodePaiement, montant];
}
/// État pour un paiement réussi
class PaymentSuccess extends CotisationsState {
final String cotisationId;
final PaymentModel payment;
final CotisationModel updatedCotisation;
const PaymentSuccess({
required this.cotisationId,
required this.payment,
required this.updatedCotisation,
});
@override
List<Object?> get props => [cotisationId, payment, updatedCotisation];
}
/// État pour un paiement échoué
class PaymentFailure extends CotisationsState {
final String cotisationId;
final String paymentId;
final String errorMessage;
final String? errorCode;
const PaymentFailure({
required this.cotisationId,
required this.paymentId,
required this.errorMessage,
this.errorCode,
});
@override
List<Object?> get props => [cotisationId, paymentId, errorMessage, errorCode];
}
/// État pour un paiement annulé
class PaymentCancelled extends CotisationsState {
final String cotisationId;
final String paymentId;
const PaymentCancelled({
required this.cotisationId,
required this.paymentId,
});
@override
List<Object?> get props => [cotisationId, paymentId];
}
/// État pour la synchronisation en cours
class SyncInProgress extends CotisationsState {
final String message;
const SyncInProgress(this.message);
@override
List<Object?> get props => [message];
}
/// État pour la synchronisation terminée
class SyncCompleted extends CotisationsState {
final int itemsSynced;
final DateTime syncTime;
const SyncCompleted({
required this.itemsSynced,
required this.syncTime,
});
@override
List<Object?> get props => [itemsSynced, syncTime];
}
/// État pour l'export en cours
class ExportInProgress extends CotisationsState {
final String format;
final int totalItems;
const ExportInProgress({
required this.format,
required this.totalItems,
});
@override
List<Object?> get props => [format, totalItems];
}
/// État pour l'export terminé
class ExportCompleted extends CotisationsState {
final String format;
final String filePath;
final int itemsExported;
const ExportCompleted({
required this.format,
required this.filePath,
required this.itemsExported,
});
@override
List<Object?> get props => [format, filePath, itemsExported];
}
/// État pour les notifications programmées
class NotificationsScheduled extends CotisationsState {
final int notificationsCount;
final List<String> cotisationIds;
const NotificationsScheduled({
required this.notificationsCount,
required this.cotisationIds,
});
@override
List<Object?> get props => [notificationsCount, cotisationIds];
}