|
|
|
@ -44,13 +44,34 @@ class OrderPrinter { |
|
|
|
PrinterSettings? _settings; |
|
|
|
PrinterConnectionStatus _connectionStatus = PrinterConnectionStatus.notConfigured; |
|
|
|
|
|
|
|
DateTime? _lastConfigUpdate; |
|
|
|
static const Duration _configCacheTimeout = Duration(minutes: 5); |
|
|
|
|
|
|
|
// Getters publics |
|
|
|
PrinterSettings? get settings => _settings; |
|
|
|
PrinterConnectionStatus get connectionStatus => _connectionStatus; |
|
|
|
bool get isConfigured => _settings != null && |
|
|
|
_settings!.ipAddress != null && |
|
|
|
_settings!.ipAddress!.isNotEmpty && |
|
|
|
_settings!.port != null; |
|
|
|
|
|
|
|
// Getter isConfigured modifié pour inclure validation temporelle |
|
|
|
bool get isConfigured { |
|
|
|
// Vérifier si la configuration existe |
|
|
|
if (_settings == null || |
|
|
|
_settings!.ipAddress == null || |
|
|
|
_settings!.ipAddress!.isEmpty || |
|
|
|
_settings!.port == null) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Vérifier si la configuration n'est pas trop ancienne |
|
|
|
if (_lastConfigUpdate != null && |
|
|
|
DateTime.now().difference(_lastConfigUpdate!) > _configCacheTimeout) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("⚠️ Configuration expirée, rechargement nécessaire"); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// Constantes ESC/POS |
|
|
|
static const List<int> ESC_CONDENSED_ON = [0x1B, 0x0F]; |
|
|
|
@ -73,6 +94,96 @@ class OrderPrinter { |
|
|
|
static const String rightWord = 'cocher'; |
|
|
|
static const int padding = 1; |
|
|
|
|
|
|
|
/// Force la réinitialisation complète de l'instance |
|
|
|
static void resetInstance() { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Réinitialisation complète de l'instance OrderPrinter"); |
|
|
|
} |
|
|
|
_instance = null; |
|
|
|
} |
|
|
|
|
|
|
|
/// Méthode pour vider complètement le cache et recharger |
|
|
|
Future<bool> forceClearAndReload() async { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🧹 Nettoyage complet de la configuration..."); |
|
|
|
} |
|
|
|
|
|
|
|
// Effacer complètement tout |
|
|
|
_settings = null; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
_connectionStatus = PrinterConnectionStatus.notConfigured; |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Rechargement forcé depuis l'API..."); |
|
|
|
} |
|
|
|
|
|
|
|
// Attendre un peu pour s'assurer que tout est nettoyé |
|
|
|
await Future.delayed(const Duration(milliseconds: 100)); |
|
|
|
|
|
|
|
// Recharger depuis l'API avec un timeout plus court pour déboguer |
|
|
|
try { |
|
|
|
var printerSettings = await RestaurantApiService.getPrinterSettings() |
|
|
|
.timeout( |
|
|
|
const Duration(seconds: 8), |
|
|
|
onTimeout: () => throw TimeoutException('Timeout lors de la récupération'), |
|
|
|
); |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("📡 Nouvelle config reçue de l'API:"); |
|
|
|
print(" IP: ${printerSettings.ipAddress}"); |
|
|
|
print(" Port: ${printerSettings.port}"); |
|
|
|
} |
|
|
|
|
|
|
|
// Validation |
|
|
|
if (printerSettings.ipAddress == null || printerSettings.ipAddress!.isEmpty) { |
|
|
|
throw ArgumentError('Adresse IP non définie'); |
|
|
|
} |
|
|
|
|
|
|
|
if (printerSettings.port == null || printerSettings.port! <= 0) { |
|
|
|
throw ArgumentError('Port invalide'); |
|
|
|
} |
|
|
|
|
|
|
|
if (!_isValidIpAddress(printerSettings.ipAddress!)) { |
|
|
|
throw ArgumentError('Format IP invalide: ${printerSettings.ipAddress}'); |
|
|
|
} |
|
|
|
|
|
|
|
// Appliquer la nouvelle configuration |
|
|
|
_settings = printerSettings; |
|
|
|
_lastConfigUpdate = DateTime.now(); |
|
|
|
_connectionStatus = PrinterConnectionStatus.disconnected; |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("✅ Configuration mise à jour avec succès:"); |
|
|
|
print(" Nouvelle IP: ${_settings!.ipAddress}"); |
|
|
|
print(" Nouveau Port: ${_settings!.port}"); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("❌ Erreur lors du rechargement forcé: $e"); |
|
|
|
} |
|
|
|
_connectionStatus = PrinterConnectionStatus.error; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Méthode de débogage pour vérifier l'état actuel |
|
|
|
void debugCurrentState() { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔍 État actuel de OrderPrinter:"); |
|
|
|
print(" isConfigured: $isConfigured"); |
|
|
|
print(" connectionStatus: $_connectionStatus"); |
|
|
|
print(" settings: ${_settings != null ? '${_settings!.ipAddress}:${_settings!.port}' : 'null'}"); |
|
|
|
print(" lastConfigUpdate: $_lastConfigUpdate"); |
|
|
|
if (_lastConfigUpdate != null) { |
|
|
|
final age = DateTime.now().difference(_lastConfigUpdate!); |
|
|
|
print(" config age: ${age.inMinutes} minutes"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Initialise la configuration de l'imprimante avec gestion d'erreurs robuste |
|
|
|
Future<bool> initialize() async { |
|
|
|
try { |
|
|
|
@ -80,15 +191,23 @@ class OrderPrinter { |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🔧 Initialisation de la configuration imprimante..."); |
|
|
|
print(" État avant: ${_settings != null ? '${_settings!.ipAddress}:${_settings!.port}' : 'null'}"); |
|
|
|
} |
|
|
|
|
|
|
|
// Récupération des paramètres avec timeout via votre API |
|
|
|
// Forcer la récupération depuis l'API |
|
|
|
var printerSettings = await RestaurantApiService.getPrinterSettings() |
|
|
|
.timeout( |
|
|
|
const Duration(seconds: 10), |
|
|
|
onTimeout: () => throw TimeoutException('Timeout lors de la récupération des paramètres'), |
|
|
|
); |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("📡 Réponse de l'API:"); |
|
|
|
print(" IP reçue: ${printerSettings.ipAddress}"); |
|
|
|
print(" Port reçu: ${printerSettings.port}"); |
|
|
|
print(" Nom: ${printerSettings.name}"); |
|
|
|
} |
|
|
|
|
|
|
|
// Validation des paramètres |
|
|
|
if (printerSettings.ipAddress == null || printerSettings.ipAddress!.isEmpty) { |
|
|
|
throw ArgumentError('Adresse IP de l\'imprimante non définie'); |
|
|
|
@ -103,39 +222,62 @@ class OrderPrinter { |
|
|
|
throw ArgumentError('Format d\'adresse IP invalide: ${printerSettings.ipAddress}'); |
|
|
|
} |
|
|
|
|
|
|
|
_settings=null; |
|
|
|
// Vérifier si la configuration a changé |
|
|
|
bool configChanged = _settings == null || |
|
|
|
_settings!.ipAddress != printerSettings.ipAddress || |
|
|
|
_settings!.port != printerSettings.port; |
|
|
|
|
|
|
|
if (configChanged) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Changement de configuration détecté:"); |
|
|
|
if (_settings != null) { |
|
|
|
print(" Ancienne: ${_settings!.ipAddress}:${_settings!.port}"); |
|
|
|
} else { |
|
|
|
print(" Ancienne: null"); |
|
|
|
} |
|
|
|
print(" Nouvelle: ${printerSettings.ipAddress}:${printerSettings.port}"); |
|
|
|
} |
|
|
|
// Réinitialiser le statut de connexion |
|
|
|
_connectionStatus = PrinterConnectionStatus.disconnected; |
|
|
|
} else { |
|
|
|
if (kDebugMode) { |
|
|
|
print("ℹ️ Aucun changement de configuration"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Configuration réussie |
|
|
|
_settings = printerSettings; |
|
|
|
_connectionStatus = PrinterConnectionStatus.disconnected; |
|
|
|
_settings = PrinterSettings(); |
|
|
|
_settings = printerSettings; |
|
|
|
_lastConfigUpdate = DateTime.now(); |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("✅ Imprimante configurée : ${_settings!.ipAddress}:${_settings!.port}"); |
|
|
|
if (_settings!.name != null) { |
|
|
|
print("📋 Nom: ${_settings!.name}"); |
|
|
|
} |
|
|
|
if (_settings!.type != null) { |
|
|
|
print("🏷️ Type: ${_settings!.type}"); |
|
|
|
} |
|
|
|
print("✅ Configuration appliquée:"); |
|
|
|
print(" IP finale: ${_settings!.ipAddress}"); |
|
|
|
print(" Port final: ${_settings!.port}"); |
|
|
|
print(" Statut: $_connectionStatus"); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} on TimeoutException catch (e) { |
|
|
|
_connectionStatus = PrinterConnectionStatus.error; |
|
|
|
_settings = null; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
if (kDebugMode) { |
|
|
|
print("⏰ Timeout lors de l'initialisation: $e"); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} on ArgumentError catch (e) { |
|
|
|
_connectionStatus = PrinterConnectionStatus.error; |
|
|
|
_settings = null; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
if (kDebugMode) { |
|
|
|
print("❌ Paramètres invalides: $e"); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} catch (e) { |
|
|
|
_connectionStatus = PrinterConnectionStatus.error; |
|
|
|
_settings = null; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
if (kDebugMode) { |
|
|
|
print("💥 Erreur lors de la récupération des paramètres d'imprimante : $e"); |
|
|
|
} |
|
|
|
@ -143,24 +285,79 @@ class OrderPrinter { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Nouvelle méthode pour forcer la revalidation |
|
|
|
Future<bool> forceReload() async { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Rechargement forcé de la configuration imprimante"); |
|
|
|
} |
|
|
|
|
|
|
|
// Effacer la configuration actuelle |
|
|
|
_settings = null; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
_connectionStatus = PrinterConnectionStatus.notConfigured; |
|
|
|
|
|
|
|
// Recharger depuis l'API |
|
|
|
return await initialize(); |
|
|
|
} |
|
|
|
|
|
|
|
/// Valide le format d'une adresse IP |
|
|
|
bool _isValidIpAddress(String ip) { |
|
|
|
final ipRegex = RegExp(r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'); |
|
|
|
return ipRegex.hasMatch(ip); |
|
|
|
} |
|
|
|
|
|
|
|
/// Version améliorée du test de connexion avec plus de logs |
|
|
|
Future<ConnectionTestResult> testConnectionWithDebug({ |
|
|
|
Duration timeout = const Duration(seconds: 5), |
|
|
|
int maxRetries = 3, |
|
|
|
}) async { |
|
|
|
// Debug de l'état avant test |
|
|
|
debugCurrentState(); |
|
|
|
|
|
|
|
// Vérifier et recharger si nécessaire |
|
|
|
if (!isConfigured) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Configuration non valide, rechargement forcé..."); |
|
|
|
} |
|
|
|
|
|
|
|
final reloadSuccess = await forceClearAndReload(); |
|
|
|
if (!reloadSuccess) { |
|
|
|
return const ConnectionTestResult( |
|
|
|
isSuccessful: false, |
|
|
|
message: 'Impossible de recharger la configuration', |
|
|
|
status: PrinterConnectionStatus.notConfigured, |
|
|
|
responseTime: Duration.zero, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🎯 Test de connexion vers: ${_settings!.ipAddress}:${_settings!.port}"); |
|
|
|
} |
|
|
|
|
|
|
|
return await testConnection(timeout: timeout, maxRetries: maxRetries); |
|
|
|
} |
|
|
|
|
|
|
|
/// Test de connexion avancé avec métriques |
|
|
|
Future<ConnectionTestResult> testConnection({ |
|
|
|
Duration timeout = const Duration(seconds: 5), |
|
|
|
int maxRetries = 3, |
|
|
|
}) async { |
|
|
|
// Vérifier et recharger la configuration si nécessaire |
|
|
|
if (!isConfigured) { |
|
|
|
return const ConnectionTestResult( |
|
|
|
isSuccessful: false, |
|
|
|
message: 'Imprimante non configurée', |
|
|
|
status: PrinterConnectionStatus.notConfigured, |
|
|
|
responseTime: Duration.zero, |
|
|
|
); |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Configuration non valide, tentative de rechargement..."); |
|
|
|
} |
|
|
|
|
|
|
|
final reloadSuccess = await initialize(); |
|
|
|
if (!reloadSuccess) { |
|
|
|
return const ConnectionTestResult( |
|
|
|
isSuccessful: false, |
|
|
|
message: 'Impossible de recharger la configuration imprimante', |
|
|
|
status: PrinterConnectionStatus.notConfigured, |
|
|
|
responseTime: Duration.zero, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
final stopwatch = Stopwatch()..start(); |
|
|
|
@ -279,6 +476,10 @@ class OrderPrinter { |
|
|
|
'timestamp': DateTime.now().toIso8601String(), |
|
|
|
'configured': isConfigured, |
|
|
|
'connectionStatus': _connectionStatus.toString(), |
|
|
|
'lastConfigUpdate': _lastConfigUpdate?.toIso8601String(), |
|
|
|
'configAge': _lastConfigUpdate != null |
|
|
|
? DateTime.now().difference(_lastConfigUpdate!).inMinutes |
|
|
|
: null, |
|
|
|
}; |
|
|
|
|
|
|
|
if (_settings != null) { |
|
|
|
@ -364,6 +565,11 @@ class OrderPrinter { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Vérifier si c'est un changement |
|
|
|
bool configChanged = _settings == null || |
|
|
|
_settings!.ipAddress != ipAddress || |
|
|
|
_settings!.port != port; |
|
|
|
|
|
|
|
_settings = PrinterSettings( |
|
|
|
ipAddress: ipAddress, |
|
|
|
port: port, |
|
|
|
@ -373,7 +579,12 @@ class OrderPrinter { |
|
|
|
updatedAt: DateTime.now(), |
|
|
|
); |
|
|
|
|
|
|
|
_connectionStatus = PrinterConnectionStatus.disconnected; |
|
|
|
_lastConfigUpdate = DateTime.now(); |
|
|
|
|
|
|
|
// Réinitialiser le statut si changement |
|
|
|
if (configChanged) { |
|
|
|
_connectionStatus = PrinterConnectionStatus.disconnected; |
|
|
|
} |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🔧 Configuration mise à jour: $ipAddress:$port"); |
|
|
|
@ -396,12 +607,41 @@ class OrderPrinter { |
|
|
|
void resetConfiguration() { |
|
|
|
_settings = null; |
|
|
|
_connectionStatus = PrinterConnectionStatus.notConfigured; |
|
|
|
_lastConfigUpdate = null; |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Configuration de l'imprimante réinitialisée"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Vérifie si la configuration a changé |
|
|
|
bool hasConfigurationChanged(PrinterSettings newSettings) { |
|
|
|
if (_settings == null) return true; |
|
|
|
|
|
|
|
return _settings!.ipAddress != newSettings.ipAddress || |
|
|
|
_settings!.port != newSettings.port || |
|
|
|
_settings!.name != newSettings.name || |
|
|
|
_settings!.type != newSettings.type; |
|
|
|
} |
|
|
|
|
|
|
|
/// Informations de debug |
|
|
|
Map<String, dynamic> getDebugInfo() { |
|
|
|
return { |
|
|
|
'isConfigured': isConfigured, |
|
|
|
'connectionStatus': _connectionStatus.toString(), |
|
|
|
'lastConfigUpdate': _lastConfigUpdate?.toIso8601String(), |
|
|
|
'configAge': _lastConfigUpdate != null |
|
|
|
? DateTime.now().difference(_lastConfigUpdate!).inMinutes |
|
|
|
: null, |
|
|
|
'settings': _settings != null ? { |
|
|
|
'ipAddress': _settings!.ipAddress, |
|
|
|
'port': _settings!.port, |
|
|
|
'name': _settings!.name, |
|
|
|
'type': _settings!.type, |
|
|
|
} : null, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
/// Méthode pour normaliser les caractères accentués |
|
|
|
String safePadRight(String text, int width) { |
|
|
|
// Remplace temporairement les accents par des lettres simples |
|
|
|
@ -420,8 +660,28 @@ class OrderPrinter { |
|
|
|
return normalized.padRight(width); |
|
|
|
} |
|
|
|
|
|
|
|
Future<bool> _ensureValidConfiguration() async { |
|
|
|
if (!isConfigured) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("🔄 Configuration non valide, rechargement..."); |
|
|
|
} |
|
|
|
final reloaded = await initialize(); |
|
|
|
if (!reloaded) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("❌ Impossible de recharger la configuration imprimante"); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// Méthodes d'impression optimisées |
|
|
|
Future<bool> printOrderESCPOS(Order order) async { |
|
|
|
if (!await _ensureValidConfiguration()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
final connectionTest = await testConnection(); |
|
|
|
if (!connectionTest.isSuccessful) { |
|
|
|
if (kDebugMode) { |
|
|
|
@ -508,6 +768,11 @@ class OrderPrinter { |
|
|
|
} |
|
|
|
|
|
|
|
Future<bool> printOrderESC80MM(Order order) async { |
|
|
|
// Auto-revalidation avant impression |
|
|
|
if (!await _ensureValidConfiguration()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
final connectionTest = await testConnection(); |
|
|
|
if (!connectionTest.isSuccessful) { |
|
|
|
if (kDebugMode) { |
|
|
|
@ -575,6 +840,10 @@ class OrderPrinter { |
|
|
|
} |
|
|
|
|
|
|
|
Future<bool> printOrderESCPOSOptimized(Order order) async { |
|
|
|
if (!await _ensureValidConfiguration()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
final connectionTest = await testConnection(); |
|
|
|
if (!connectionTest.isSuccessful) { |
|
|
|
if (kDebugMode) { |
|
|
|
@ -686,6 +955,67 @@ class OrderPrinter { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Fonction utilitaire pour forcer la mise à jour |
|
|
|
Future<bool> forceUpdatePrinterConfig() async { |
|
|
|
final printer = OrderPrinter.instance; |
|
|
|
|
|
|
|
if (kDebugMode) { |
|
|
|
print("🔧 Forçage de la mise à jour de configuration..."); |
|
|
|
} |
|
|
|
|
|
|
|
// Méthode 1: Utiliser forceClearAndReload |
|
|
|
bool success = await printer.forceClearAndReload(); |
|
|
|
|
|
|
|
if (success) { |
|
|
|
if (kDebugMode) { |
|
|
|
print("✅ Configuration mise à jour avec succès"); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
if (kDebugMode) { |
|
|
|
print("❌ Échec de la mise à jour, tentative de réinitialisation complète..."); |
|
|
|
} |
|
|
|
|
|
|
|
// Méthode 2: Réinitialisation complète de l'instance |
|
|
|
OrderPrinter.resetInstance(); |
|
|
|
|
|
|
|
// Obtenir la nouvelle instance et initialiser |
|
|
|
final newPrinter = OrderPrinter.instance; |
|
|
|
return await newPrinter.initialize(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Fonction pour tester avec débogage complet |
|
|
|
Future<void> testPrinterWithFullDebug() async { |
|
|
|
final printer = OrderPrinter.instance; |
|
|
|
|
|
|
|
print("🔍 === DÉBOGAGE COMPLET IMPRIMANTE ==="); |
|
|
|
|
|
|
|
// État initial |
|
|
|
printer.debugCurrentState(); |
|
|
|
|
|
|
|
// Force la mise à jour |
|
|
|
print("🔄 Forçage de la mise à jour..."); |
|
|
|
await printer.forceClearAndReload(); |
|
|
|
|
|
|
|
// État après mise à jour |
|
|
|
print("📊 État après mise à jour:"); |
|
|
|
printer.debugCurrentState(); |
|
|
|
|
|
|
|
// Test de connexion |
|
|
|
print("🔗 Test de connexion..."); |
|
|
|
final result = await printer.testConnectionWithDebug(); |
|
|
|
|
|
|
|
print("📋 Résultat: ${result.isSuccessful ? '✅' : '❌'} ${result.message}"); |
|
|
|
|
|
|
|
// Diagnostic complet |
|
|
|
print("🏥 Diagnostic complet:"); |
|
|
|
final diagnostics = await printer.runDiagnostics(); |
|
|
|
diagnostics.forEach((key, value) { |
|
|
|
print(" $key: $value"); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// Fonctions utilitaires pour rétrocompatibilité |
|
|
|
Future<bool> printOrderPDF(Order order) async { |
|
|
|
final printer = OrderPrinter.instance; |
|
|
|
|