Files
wortis_tpe/lib/services/wortis_api_service.dart

562 lines
17 KiB
Dart

// Enhanced lib/services/wortis_api_service.dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/service_model.dart';
class WortisApiService {
static const String baseUrl = 'https://api.live.wortis.cg/tpe';
// Singleton pattern
static final WortisApiService _instance = WortisApiService._internal();
factory WortisApiService() => _instance;
WortisApiService._internal();
// Retry configuration
static const int maxRetries = 3;
static const Duration retryDelay = Duration(seconds: 2);
Future<List<WortisService>> getServices() async {
return _retryRequest<List<WortisService>>(() async {
final response = await http
.get(
Uri.parse('$baseUrl/get_services_back'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Connection': 'keep-alive',
},
)
.timeout(Duration(seconds: 30));
if (response.statusCode == 200) {
final Map<String, dynamic> jsonData = json.decode(response.body);
final List<dynamic> servicesJson = jsonData['all_services'] ?? [];
return servicesJson
.map((serviceJson) => WortisService.fromJson(serviceJson))
.toList();
} else {
throw Exception('Erreur API: ${response.statusCode}');
}
});
}
// Méthode pour grouper les services par secteur
Map<String, List<WortisService>> groupServicesBySector(
List<WortisService> services,
) {
Map<String, List<WortisService>> grouped = {};
for (var service in services) {
String sector = service.secteurActivite;
if (grouped[sector] == null) {
grouped[sector] = [];
}
grouped[sector]!.add(service);
}
return grouped;
}
// Generic retry logic
Future<T> _retryRequest<T>(Future<T> Function() request) async {
Exception? lastException;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await request();
} on SocketException catch (e) {
lastException = e;
print('Tentative $attempt échouée (SocketException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on HttpException catch (e) {
lastException = e;
print('Tentative $attempt échouée (HttpException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on http.ClientException catch (e) {
lastException = e;
print('Tentative $attempt échouée (ClientException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} catch (e) {
// For other exceptions, don't retry
rethrow;
}
}
throw Exception(
'Impossible de se connecter après $maxRetries tentatives: $lastException',
);
}
}
class AuthApiService {
static const String baseUrl = 'https://api.live.wortis.cg/tpe';
static const int maxRetries = 3;
static const Duration retryDelay = Duration(seconds: 2);
/// Test de connexion à l'API avec retry
static Future<bool> testConnection() async {
try {
return await _retryRequest<bool>(() async {
final response = await http
.get(
Uri.parse('http://google.com/'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
)
.timeout(Duration(seconds: 10));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['success'] == true;
}
return false;
});
} catch (e) {
print('Erreur test connexion après plusieurs tentatives: $e');
return false;
}
}
/// Connexion utilisateur avec retry
static Future<Map<String, dynamic>> login(String agentId, String pin) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.post(
Uri.parse('$baseUrl/auth/login'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode({'agent_id': agentId, 'pin': pin}),
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur login API après retry: $e');
return {'success': false, 'message': 'Erreur de connexion au serveur'};
}
}
/// Créer un utilisateur avec retry
static Future<Map<String, dynamic>> createUser(
String nom,
String pin, {
String role = 'agent',
}) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.post(
Uri.parse('$baseUrl/users/register'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode({'nom': nom, 'pin': pin, 'role': role}),
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur création utilisateur après retry: $e');
return {'success': false, 'message': 'Erreur de création'};
}
}
/// Récupérer le solde d'un agent avec retry
static Future<Map<String, dynamic>> getAgentBalance(String agentId) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.get(
Uri.parse('$baseUrl/agent/$agentId/balance'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur récupération solde après retry: $e');
return {
'success': false,
'message': 'Erreur lors de la récupération du solde',
};
}
}
/// Recharger le solde d'un agent avec retry
static Future<Map<String, dynamic>> rechargeAgent(
String agentId,
double montant,
) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.post(
Uri.parse('$baseUrl/agent/$agentId/recharge'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode({'montant': montant}),
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur recharge après retry: $e');
return {'success': false, 'message': 'Erreur lors de la recharge'};
}
}
/// Mettre à jour le solde d'un agent avec retry
static Future<Map<String, dynamic>> updateAgentBalance(
String agentId,
double nouveauSolde,
) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.put(
Uri.parse('$baseUrl/agent/$agentId/balance'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode({'solde': nouveauSolde}),
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur mise à jour solde après retry: $e');
return {
'success': false,
'message': 'Erreur lors de la mise à jour du solde',
};
}
}
/// Enregistrer une transaction avec retry
static Future<Map<String, dynamic>> recordTransaction({
required String agentId,
required String serviceId,
required String serviceName,
required double montant,
required double commission,
required String typeTransaction,
required Map<String, dynamic> detailsTransaction,
}) async {
try {
return await _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.post(
Uri.parse('$baseUrl/transactions'),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode({
'agent_id': agentId,
'service_id': serviceId,
'service_name': serviceName,
'montant': montant,
'commission': commission,
'type_transaction': typeTransaction,
'details': detailsTransaction,
'date_transaction': DateTime.now().toIso8601String(),
}),
)
.timeout(Duration(seconds: 15));
return jsonDecode(response.body);
});
} catch (e) {
print('Erreur enregistrement transaction après retry: $e');
return {
'success': false,
'message': 'Erreur lors de l\'enregistrement de la transaction',
};
}
}
// Generic retry logic for AuthApiService
static Future<T> _retryRequest<T>(Future<T> Function() request) async {
Exception? lastException;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await request();
} on SocketException catch (e) {
lastException = e;
print('AuthAPI - Tentative $attempt échouée (SocketException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on HttpException catch (e) {
lastException = e;
print('AuthAPI - Tentative $attempt échouée (HttpException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on http.ClientException catch (e) {
lastException = e;
print('AuthAPI - Tentative $attempt échouée (ClientException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} catch (e) {
// For other exceptions, don't retry
rethrow;
}
}
throw Exception(
'Impossible de se connecter après $maxRetries tentatives: $lastException',
);
}
}
class ApiService {
static const String baseUrl = 'https://api.live.wortis.cg/tpe';
static const int maxRetries = 3;
static const Duration retryDelay = Duration(seconds: 2);
/// Récupérer les champs d'un service avec retry amélioré
Future<Map<String, dynamic>> fetchServiceFields(String serviceName) async {
return _retryRequest<Map<String, dynamic>>(() async {
// Fix: Remove double slash in URL
final url = '$baseUrl/service/${Uri.encodeComponent(serviceName)}';
print('Fetching service fields from: $url');
final response = await http
.get(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Connection': 'keep-alive',
'User-Agent': 'WortisApp/1.0',
},
)
.timeout(Duration(seconds: 30));
print('Response status: ${response.statusCode}');
print('Response headers: ${response.headers}');
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception(
'Erreur API: ${response.statusCode} - ${response.body}',
);
}
});
}
/// Vérifier les données avec GET et retry
Future<Map<String, dynamic>> verifyDataGet(
String url,
Map<String, dynamic> params,
) async {
return _retryRequest<Map<String, dynamic>>(() async {
final uri = Uri.parse(url).replace(
queryParameters: params.map(
(key, value) => MapEntry(key, value.toString()),
),
);
final response = await http
.get(
uri,
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
)
.timeout(Duration(seconds: 30));
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception(
'Données non trouvées - Status: ${response.statusCode}',
);
}
});
}
/// Vérifier les données avec POST et retry
Future<Map<String, dynamic>> verifyDataPost(
String url,
Map<String, dynamic> data,
String operationId,
) async {
return _retryRequest<Map<String, dynamic>>(() async {
final response = await http
.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode(data),
)
.timeout(Duration(seconds: 30));
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception(
'Données non trouvées - Status: ${response.statusCode}',
);
}
});
}
/// Soumettre les données du formulaire avec retry
Future<void> submitFormData(
BuildContext context,
String url,
Map<String, dynamic> data,
Map<String, dynamic>? serviceData,
dynamic additionalData,
bool isCardPayment,
) async {
try {
await _retryRequest<void>(() async {
print(url);
final response = await http
.post(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Connection': 'keep-alive',
},
body: jsonEncode(data),
)
.timeout(Duration(seconds: 30));
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
// Afficher un message de succès
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
Icon(Icons.check_circle, color: Colors.white),
SizedBox(width: 8),
Text('Transaction effectuée avec succès'),
],
),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
);
// Retourner à la page précédente
Navigator.of(context).pop();
}
} else {
throw Exception(
'Erreur lors de la soumission - Status: ${response.statusCode}',
);
}
});
} catch (e) {
print('Erreur submitFormData après retry: $e');
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
Icon(Icons.error, color: Colors.white),
SizedBox(width: 8),
Expanded(
child: Text(
'Erreur lors de la transaction: ${e.toString()}',
maxLines: 2,
),
),
],
),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
duration: Duration(seconds: 5),
),
);
}
}
}
/// Annuler l'opération en cours
void cancelOperation() {
print('Opération annulée');
}
// Generic retry logic for ApiService
Future<T> _retryRequest<T>(Future<T> Function() request) async {
Exception? lastException;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await request();
} on SocketException catch (e) {
lastException = e;
print('API - Tentative $attempt échouée (SocketException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on HttpException catch (e) {
lastException = e;
print('API - Tentative $attempt échouée (HttpException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} on http.ClientException catch (e) {
lastException = e;
print('API - Tentative $attempt échouée (ClientException): $e');
if (attempt < maxRetries) {
await Future.delayed(retryDelay * attempt);
}
} catch (e) {
// For other exceptions, don't retry
rethrow;
}
}
throw Exception(
'Impossible de se connecter après $maxRetries tentatives: $lastException',
);
}
}