feat(unionflow): ajout Spec-Kit, constitution, mission mutuelles
- Config Spec-Kit pour Spec-Driven Development - CONSTITUTION.md + .specify/memory/constitution.md - Commandes Cursor /speckit.*, règles projet - Mission: associations + mutuelles d'épargne et de financement - .gitignore: versionner config spec-kit unionflow Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
/// 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 '../data/repositories/contribution_repository.dart';
|
||||
import 'contributions_event.dart';
|
||||
import 'contributions_state.dart';
|
||||
|
||||
/// BLoC pour gérer l'état des contributions via l'API backend
|
||||
class ContributionsBloc extends Bloc<ContributionsEvent, ContributionsState> {
|
||||
final ContributionRepository _repository;
|
||||
|
||||
ContributionsBloc(this._repository) : 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);
|
||||
}
|
||||
|
||||
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...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
|
||||
AppLogger.blocState('ContributionsBloc', 'ContributionsLoaded', data: {
|
||||
'count': result.contributions.length,
|
||||
'total': result.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));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionById(
|
||||
LoadContributionById event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement de la contribution...'));
|
||||
final contribution = await _repository.getCotisationById(event.id);
|
||||
emit(ContributionDetailLoaded(contribution: contribution));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Contribution non trouvée', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCreateContribution(
|
||||
CreateContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Création de la contribution...'));
|
||||
final created = await _repository.createCotisation(event.contribution);
|
||||
emit(ContributionCreated(contribution: created));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de la création de la contribution', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onUpdateContribution(
|
||||
UpdateContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Mise à jour de la contribution...'));
|
||||
final updated = await _repository.updateCotisation(event.id, event.contribution);
|
||||
emit(ContributionUpdated(contribution: updated));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de la mise à jour', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onDeleteContribution(
|
||||
DeleteContribution event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Suppression de la contribution...'));
|
||||
await _repository.deleteCotisation(event.id);
|
||||
emit(ContributionDeleted(id: event.id));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de la suppression', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSearchContributions(
|
||||
SearchContributions event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Recherche en cours...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
membreId: event.membreId,
|
||||
statut: event.statut?.name,
|
||||
type: event.type?.name,
|
||||
annee: event.annee,
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de la recherche', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionsByMembre(
|
||||
LoadContributionsByMembre event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions du membre...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
membreId: event.membreId,
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors du chargement', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionsPayees(
|
||||
LoadContributionsPayees event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions payées...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
statut: 'PAYEE',
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionsNonPayees(
|
||||
LoadContributionsNonPayees event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions non payées...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
statut: 'NON_PAYEE',
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionsEnRetard(
|
||||
LoadContributionsEnRetard event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des contributions en retard...'));
|
||||
|
||||
final result = await _repository.getCotisations(
|
||||
page: event.page,
|
||||
size: event.size,
|
||||
statut: 'EN_RETARD',
|
||||
);
|
||||
|
||||
emit(ContributionsLoaded(
|
||||
contributions: result.contributions,
|
||||
total: result.total,
|
||||
page: result.page,
|
||||
size: result.size,
|
||||
totalPages: result.totalPages,
|
||||
));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onRecordPayment(
|
||||
RecordPayment event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Enregistrement du paiement...'));
|
||||
|
||||
final updated = await _repository.enregistrerPaiement(
|
||||
event.contributionId,
|
||||
montant: event.montant,
|
||||
datePaiement: event.datePaiement,
|
||||
methodePaiement: event.methodePaiement.name,
|
||||
numeroPaiement: event.numeroPaiement,
|
||||
referencePaiement: event.referencePaiement,
|
||||
);
|
||||
|
||||
emit(PaymentRecorded(contribution: updated));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur lors de l\'enregistrement du paiement', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadContributionsStats(
|
||||
LoadContributionsStats event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Chargement des statistiques...'));
|
||||
final stats = await _repository.getStatistiques();
|
||||
emit(ContributionsStatsLoaded(stats: stats.map((k, v) => MapEntry(k, (v is num) ? v.toDouble() : 0.0))));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onGenerateAnnualContributions(
|
||||
GenerateAnnualContributions event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Génération des contributions...'));
|
||||
final count = await _repository.genererCotisationsAnnuelles(event.annee);
|
||||
emit(ContributionsGenerated(nombreGenere: count));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSendPaymentReminder(
|
||||
SendPaymentReminder event,
|
||||
Emitter<ContributionsState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(const ContributionsLoading(message: 'Envoi du rappel...'));
|
||||
await _repository.envoyerRappel(event.contributionId);
|
||||
emit(ReminderSent(contributionId: event.contributionId));
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('Erreur', error: e, stackTrace: stackTrace);
|
||||
emit(ContributionsError(message: 'Erreur', error: e));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user