fix(wave-mock): appeler mock-complete backend pour créditer réellement les comptes
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
This commit is contained in:
@@ -292,6 +292,7 @@ class ContributionRepositoryImpl implements IContributionRepository {
|
|||||||
waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '',
|
waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '',
|
||||||
waveCheckoutSessionId: data['waveCheckoutSessionId'] as String?,
|
waveCheckoutSessionId: data['waveCheckoutSessionId'] as String?,
|
||||||
clientReference: data['clientReference'] 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.',
|
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<void> 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).
|
/// Résultat de l'initiation d'un paiement Wave (redirection vers l'app Wave).
|
||||||
class WavePaiementInitResult {
|
class WavePaiementInitResult {
|
||||||
final String redirectUrl;
|
final String redirectUrl;
|
||||||
final String waveLaunchUrl;
|
final String waveLaunchUrl;
|
||||||
final String? waveCheckoutSessionId;
|
final String? waveCheckoutSessionId;
|
||||||
final String? clientReference;
|
final String? clientReference;
|
||||||
|
final String? intentionPaiementId;
|
||||||
final String message;
|
final String message;
|
||||||
|
|
||||||
const WavePaiementInitResult({
|
const WavePaiementInitResult({
|
||||||
@@ -382,6 +391,7 @@ class WavePaiementInitResult {
|
|||||||
required this.waveLaunchUrl,
|
required this.waveLaunchUrl,
|
||||||
this.waveCheckoutSessionId,
|
this.waveCheckoutSessionId,
|
||||||
this.clientReference,
|
this.clientReference,
|
||||||
|
this.intentionPaiementId,
|
||||||
required this.message,
|
required this.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -448,10 +448,18 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
|||||||
final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl;
|
final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl;
|
||||||
if (url.isEmpty) throw Exception('URL Wave non reçue');
|
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;
|
final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd;
|
||||||
if (isMock) {
|
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<IContributionRepository>();
|
||||||
|
await mockRepo.confirmerMockPaiement(ref);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
await Future.delayed(const Duration(milliseconds: 400));
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -459,7 +467,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
|||||||
content: Row(children: [
|
content: Row(children: [
|
||||||
Icon(Icons.science_rounded, color: AppColors.onPrimary, size: 16),
|
Icon(Icons.science_rounded, color: AppColors.onPrimary, size: 16),
|
||||||
const SizedBox(width: 8),
|
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,
|
backgroundColor: AppColors.success,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -161,19 +161,30 @@ class TransactionEpargneRepository {
|
|||||||
waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '',
|
waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '',
|
||||||
redirectUrl: data['redirectUrl'] as String? ?? data['waveLaunchUrl'] as String? ?? '',
|
redirectUrl: data['redirectUrl'] as String? ?? data['waveLaunchUrl'] as String? ?? '',
|
||||||
message: data['message'] as String? ?? 'Ouvrez Wave pour confirmer le dépôt.',
|
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<void> 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).
|
/// Résultat de l'initiation d'un dépôt Wave (épargne).
|
||||||
class DepotWaveResult {
|
class DepotWaveResult {
|
||||||
final String waveLaunchUrl;
|
final String waveLaunchUrl;
|
||||||
final String redirectUrl;
|
final String redirectUrl;
|
||||||
final String message;
|
final String message;
|
||||||
|
final String versementId;
|
||||||
|
|
||||||
const DepotWaveResult({
|
const DepotWaveResult({
|
||||||
required this.waveLaunchUrl,
|
required this.waveLaunchUrl,
|
||||||
required this.redirectUrl,
|
required this.redirectUrl,
|
||||||
required this.message,
|
required this.message,
|
||||||
|
this.versementId = '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,11 +161,14 @@ class _DepotEpargneDialogState extends State<DepotEpargneDialog> {
|
|||||||
final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl;
|
final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl;
|
||||||
if (url.isEmpty) throw Exception('URL Wave non reçue');
|
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;
|
final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd;
|
||||||
if (isMock) {
|
if (isMock) {
|
||||||
// Simulation : attendre 1s puis confirmer le succès
|
// 1. Appeler le mock-complete backend pour réellement créditer le compte
|
||||||
await Future.delayed(const Duration(milliseconds: 800));
|
try {
|
||||||
|
await _repository.confirmerMockPaiement(result.versementId);
|
||||||
|
} catch (_) {}
|
||||||
|
await Future.delayed(const Duration(milliseconds: 400));
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
Navigator.of(context).pop(true);
|
Navigator.of(context).pop(true);
|
||||||
widget.onSuccess?.call();
|
widget.onSuccess?.call();
|
||||||
@@ -174,7 +177,7 @@ class _DepotEpargneDialogState extends State<DepotEpargneDialog> {
|
|||||||
content: const Row(children: [
|
content: const Row(children: [
|
||||||
Icon(Icons.science_rounded, color: Colors.white, size: 16),
|
Icon(Icons.science_rounded, color: Colors.white, size: 16),
|
||||||
SizedBox(width: 8),
|
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,
|
backgroundColor: AppColors.success,
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user