From 22fec56fcf5cd6d6ae38bb77d19f07cfabc17e40 Mon Sep 17 00:00:00 2001 From: dahoud <41957584+DahoudG@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:39:27 +0000 Subject: [PATCH] =?UTF-8?q?fix(wave-mock):=20appeler=20mock-complete=20bac?= =?UTF-8?q?kend=20pour=20cr=C3=A9diter=20r=C3=A9ellement=20les=20comptes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le mock simulait seulement l'UI mais n'appelait pas le backend pour confirmer le paiement → le solde restait à 0 après dépôt simulé. Fix : en mode mock, après la simulation UI, appeler GET /api/wave-redirect/mock-complete?ref={id} qui : - Marque l'intention de paiement comme complétée - Crédite le compte épargne (pour les dépôts) - Enregistre le paiement de cotisation (pour les cotisations) Changements : - depot_epargne_dialog : appelle confirmerMockPaiement(versementId) - payment_dialog : appelle confirmerMockPaiement(clientReference) - transaction_epargne_repository : nouvelle méthode confirmerMockPaiement() + versementId ajouté à DepotWaveResult - contribution_repository : nouvelle méthode confirmerMockPaiement() + intentionPaiementId ajouté à WavePaiementInitResult --- .../data/repositories/contribution_repository.dart | 10 ++++++++++ .../presentation/widgets/payment_dialog.dart | 14 +++++++++++--- .../transaction_epargne_repository.dart | 11 +++++++++++ .../presentation/widgets/depot_epargne_dialog.dart | 11 +++++++---- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/features/contributions/data/repositories/contribution_repository.dart b/lib/features/contributions/data/repositories/contribution_repository.dart index 3a9543f..1752309 100644 --- a/lib/features/contributions/data/repositories/contribution_repository.dart +++ b/lib/features/contributions/data/repositories/contribution_repository.dart @@ -292,6 +292,7 @@ class ContributionRepositoryImpl implements IContributionRepository { waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '', waveCheckoutSessionId: data['waveCheckoutSessionId'] as String?, clientReference: data['clientReference'] as String?, + intentionPaiementId: data['intentionPaiementId'] as String? ?? data['clientReference'] as String?, message: data['message'] as String? ?? 'Ouvrez Wave pour confirmer le paiement.', ); } @@ -369,12 +370,20 @@ class ContributionRepositoryImpl implements IContributionRepository { } } + /// Confirme un paiement mock (mode dev) côté backend. + /// Appelle GET /api/wave-redirect/mock-complete?ref={id} + Future confirmerMockPaiement(String ref) async { + await _apiClient.get('/api/wave-redirect/mock-complete', queryParameters: {'ref': ref}); + } +} + /// Résultat de l'initiation d'un paiement Wave (redirection vers l'app Wave). class WavePaiementInitResult { final String redirectUrl; final String waveLaunchUrl; final String? waveCheckoutSessionId; final String? clientReference; + final String? intentionPaiementId; final String message; const WavePaiementInitResult({ @@ -382,6 +391,7 @@ class WavePaiementInitResult { required this.waveLaunchUrl, this.waveCheckoutSessionId, this.clientReference, + this.intentionPaiementId, required this.message, }); } diff --git a/lib/features/contributions/presentation/widgets/payment_dialog.dart b/lib/features/contributions/presentation/widgets/payment_dialog.dart index f409188..af0dca3 100644 --- a/lib/features/contributions/presentation/widgets/payment_dialog.dart +++ b/lib/features/contributions/presentation/widgets/payment_dialog.dart @@ -448,10 +448,18 @@ class _PaymentDialogState extends State { final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl; if (url.isEmpty) throw Exception('URL Wave non reçue'); - // Mode dev/mock : simuler le paiement sans ouvrir le navigateur + // Mode dev/mock : simuler ET confirmer côté backend final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd; if (isMock) { - await Future.delayed(const Duration(milliseconds: 800)); + // Confirmer côté backend pour que la cotisation soit réellement payée + final ref = result.clientReference.isNotEmpty ? result.clientReference : result.intentionPaiementId; + if (ref.isNotEmpty) { + try { + final mockRepo = getIt(); + await mockRepo.confirmerMockPaiement(ref); + } catch (_) {} + } + await Future.delayed(const Duration(milliseconds: 400)); if (!mounted) return; Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( @@ -459,7 +467,7 @@ class _PaymentDialogState extends State { content: Row(children: [ Icon(Icons.science_rounded, color: AppColors.onPrimary, size: 16), const SizedBox(width: 8), - const Expanded(child: Text('Paiement simulé avec succès (mode dev)')), + const Expanded(child: Text('Paiement simulé et enregistré (mode dev)')), ]), backgroundColor: AppColors.success, ), diff --git a/lib/features/epargne/data/repositories/transaction_epargne_repository.dart b/lib/features/epargne/data/repositories/transaction_epargne_repository.dart index ebb2fbb..737117b 100644 --- a/lib/features/epargne/data/repositories/transaction_epargne_repository.dart +++ b/lib/features/epargne/data/repositories/transaction_epargne_repository.dart @@ -161,19 +161,30 @@ class TransactionEpargneRepository { waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '', redirectUrl: data['redirectUrl'] as String? ?? data['waveLaunchUrl'] as String? ?? '', message: data['message'] as String? ?? 'Ouvrez Wave pour confirmer le dépôt.', + versementId: data['versementId'] as String? ?? data['clientReference'] as String? ?? '', ); } } + /// Confirme un paiement mock (mode dev) côté backend. + /// Appelle GET /api/wave-redirect/mock-complete?ref={id} + /// pour que le backend crédite réellement le compte. + Future confirmerMockPaiement(String versementId) async { + await _apiClient.get('/api/wave-redirect/mock-complete', queryParameters: {'ref': versementId}); + } +} + /// Résultat de l'initiation d'un dépôt Wave (épargne). class DepotWaveResult { final String waveLaunchUrl; final String redirectUrl; final String message; + final String versementId; const DepotWaveResult({ required this.waveLaunchUrl, required this.redirectUrl, required this.message, + this.versementId = '', }); } diff --git a/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart b/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart index c9c1a07..9002864 100644 --- a/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart +++ b/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart @@ -161,11 +161,14 @@ class _DepotEpargneDialogState extends State { final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl; if (url.isEmpty) throw Exception('URL Wave non reçue'); - // Mode dev/mock : simuler le paiement au lieu d'ouvrir le navigateur + // Mode dev/mock : simuler le paiement ET confirmer côté backend final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd; if (isMock) { - // Simulation : attendre 1s puis confirmer le succès - await Future.delayed(const Duration(milliseconds: 800)); + // 1. Appeler le mock-complete backend pour réellement créditer le compte + try { + await _repository.confirmerMockPaiement(result.versementId); + } catch (_) {} + await Future.delayed(const Duration(milliseconds: 400)); if (!mounted) return; Navigator.of(context).pop(true); widget.onSuccess?.call(); @@ -174,7 +177,7 @@ class _DepotEpargneDialogState extends State { content: const Row(children: [ Icon(Icons.science_rounded, color: Colors.white, size: 16), SizedBox(width: 8), - Expanded(child: Text('Dépôt simulé avec succès (mode dev)')), + Expanded(child: Text('Dépôt simulé et crédité (mode dev)')), ]), backgroundColor: AppColors.success, ),